static int smc_hw_set_param(smc_dev_t *smc) { unsigned long v=0; SMCCARD_HW_Reg0_t *reg0; SMC_ANSWER_TO_RST_t *reg1; SMCCARD_HW_Reg2_t *reg2; SMC_INTERRUPT_Reg_t *reg_int; SMCCARD_HW_Reg5_t *reg5; SMCCARD_HW_Reg6_t *reg6; unsigned long freq_cpu = get_mpeg_clk()/1000; v = SMC_READ_REG(REG0); reg0 = (SMCCARD_HW_Reg0_t*)&v; reg0->etu_divider = ETU_DIVIDER_CLOCK_HZ*smc->param.f/(smc->param.d*smc->param.freq)-1; SMC_WRITE_REG(REG0, v); v = SMC_READ_REG(REG6); reg6 = (SMCCARD_HW_Reg6_t*)&v; reg6->N_parameter = smc->param.n; reg6->cwi_value = smc->param.cwi; reg6->bgt = smc->param.bgt; reg6->bwi = smc->param.bwi; SMC_WRITE_REG(REG6, v); return 0; }
static int smc_hw_start_send(smc_dev_t *smc) { unsigned long flags; unsigned int sc_status; SMC_STATUS_Reg_t *sc_status_reg = (SMC_STATUS_Reg_t*)&sc_status; u8 byte; int cnt = 0; spin_lock_irqsave(&smc->slock, flags); while(1) { sc_status = SMC_READ_REG(STATUS); if (!smc->send_count || sc_status_reg->send_fifo_full_status) { break; } byte = smc->send_buf[smc->send_start++]; SMC_WRITE_REG(FIFO, byte); smc->send_start %= SEND_BUF_SIZE; smc->send_count--; cnt++; } spin_unlock_irqrestore(&smc->slock, flags); pr_dbg("send %d bytes to hw\n", cnt); return 0; }
static int smc_hw_deactive(smc_dev_t *smc) { if(smc->active) { unsigned long sc_reg0 = SMC_READ_REG(REG0); SMCCARD_HW_Reg0_t *sc_reg0_reg = (void *)&sc_reg0; sc_reg0_reg->rst_level = 0; sc_reg0_reg->enable= 0; sc_reg0_reg->start_atr = 0; sc_reg0_reg->start_atr_en = 0; sc_reg0_reg->clk_en=0; SMC_WRITE_REG(REG0,sc_reg0); udelay(200); if(smc->reset) { smc->reset(NULL, 1); } else { if(smc->reset_pin != -1) { gpio_request(smc->reset_pin, "smc:RESET"); gpio_out(smc->reset_pin, 1); } } smc->active = 0; } return 0; }
static int smc_hw_deactive(smc_dev_t *smc) { if(smc->active) { unsigned long sc_reg0 = SMC_READ_REG(REG0); SMCCARD_HW_Reg0_t *sc_reg0_reg = (void *)&sc_reg0; sc_reg0_reg->rst_level = 0; sc_reg0_reg->enable= 0; sc_reg0_reg->start_atr = 0; sc_reg0_reg->start_atr_en = 0; sc_reg0_reg->clk_en=0; SMC_WRITE_REG(REG0,sc_reg0); udelay(200); gpio_request(smc->power_pin, "smc:POWER"); gpio_direction_output(smc->power_pin, 1); smc->active = 0; } return 0; }
static int smc_write(struct file *filp, const char __user *buff, size_t size, loff_t *offp) { smc_dev_t *smc = (smc_dev_t*)filp->private_data; unsigned long flags; int pos = 0, ret; unsigned long sc_int; SMC_INTERRUPT_Reg_t *sc_int_reg = (void *)&sc_int; ret = mutex_lock_interruptible(&smc->lock); if(ret) return ret; pr_dbg("wait write buffer\n"); if(!(filp->f_flags&O_NONBLOCK)) { ret = wait_event_interruptible(smc->wr_wq, smc_can_write(smc)); } if(ret==0) { spin_lock_irqsave(&smc->slock, flags); if(!smc->cardin) { ret = -ENODEV; } else if (smc->send_count==SEND_BUF_SIZE) { ret = -EAGAIN; } else { ret = SEND_BUF_SIZE-smc->send_count; if(ret>size) ret = size; pos = smc->send_start+smc->send_count; pos %= SEND_BUF_SIZE; smc->send_count += ret; } spin_unlock_irqrestore(&smc->slock, flags); } if(ret>0) { int cnt = SEND_BUF_SIZE-pos; if(cnt>=ret) { copy_from_user(smc->send_buf+pos, buff, ret); } else { int cnt1 = ret-cnt; copy_from_user(smc->send_buf+pos, buff, cnt); copy_from_user(smc->send_buf, buff+cnt, cnt1); } sc_int = SMC_READ_REG(INTR); #ifdef DISABLE_RECV_INT sc_int_reg->recv_fifo_bytes_threshold_int_mask = 0; #endif sc_int_reg->send_fifo_last_byte_int_mask = 1; SMC_WRITE_REG(INTR, sc_int|0x3FF); pr_dbg("write %d bytes\n", ret); smc_hw_start_send(smc); } mutex_unlock(&smc->lock); return ret; }
static irqreturn_t smc_irq_handler(int irq, void *data) { smc_dev_t *smc = (smc_dev_t*)data; unsigned int sc_status; unsigned int sc_reg0; unsigned int sc_int; SMC_STATUS_Reg_t *sc_status_reg = (SMC_STATUS_Reg_t*)&sc_status; SMC_INTERRUPT_Reg_t *sc_int_reg = (SMC_INTERRUPT_Reg_t*)&sc_int; SMCCARD_HW_Reg0_t *sc_reg0_reg = (void *)&sc_reg0; sc_int = SMC_READ_REG(INTR); printk("smc intr:0x%x\n", sc_int); if(sc_int_reg->recv_fifo_bytes_threshold_int) { if(smc->recv_count==RECV_BUF_SIZE) { pr_error("receive buffer overflow\n"); } else { int pos = smc->recv_start+smc->recv_count; pos %= RECV_BUF_SIZE; smc->recv_buf[pos] = SMC_READ_REG(FIFO); smc->recv_count++; pr_dbg("irq: recv 1 byte\n"); } sc_int_reg->recv_fifo_bytes_threshold_int = 0; wake_up_interruptible(&smc->rd_wq); } if(sc_int_reg->send_fifo_last_byte_int) { int cnt = 0; while(1) { u8 byte; sc_status = SMC_READ_REG(STATUS); if (!smc->send_count || sc_status_reg->send_fifo_full_status) { break; } byte = smc->send_buf[smc->send_start++]; SMC_WRITE_REG(FIFO, byte); smc->send_start %= SEND_BUF_SIZE; smc->send_count--; cnt++; } pr_dbg("irq: send %d bytes to hw\n", cnt); if(!smc->send_count) { sc_int_reg->send_fifo_last_byte_int_mask = 0; sc_int_reg->recv_fifo_bytes_threshold_int_mask = 1; } sc_int_reg->send_fifo_last_byte_int = 0; wake_up_interruptible(&smc->wr_wq); } sc_reg0 = SMC_READ_REG(REG0); smc->cardin = sc_reg0_reg->card_detect; SMC_WRITE_REG(INTR, sc_int|0x3FF); return IRQ_HANDLED; }
static int smc_hw_reset(smc_dev_t *smc) { unsigned long flags; int ret; unsigned long sc_reg0 = SMC_READ_REG(REG0); SMCCARD_HW_Reg0_t *sc_reg0_reg = (void *)&sc_reg0; unsigned long sc_int; SMC_INTERRUPT_Reg_t *sc_int_reg = (void *)&sc_int; spin_lock_irqsave(&smc->slock, flags); if(smc->cardin) { ret = 0; } else { ret = -ENODEV; } spin_unlock_irqrestore(&smc->slock, flags); if(ret>=0) { /*Reset*/ #ifdef NO_HOT_RESET smc->active = 0; #endif if(smc->active) { sc_reg0_reg->rst_level = 0; sc_reg0_reg->clk_en = 1; sc_reg0_reg->etu_divider = ETU_DIVIDER_CLOCK_HZ*smc->param.f/(smc->param.d*smc->param.freq)-1; pr_dbg("hot reset\n"); SMC_WRITE_REG(REG0, sc_reg0); udelay(800/smc->param.freq); // >= 400/f ; /* disable receive interrupt*/ sc_int = SMC_READ_REG(INTR); sc_int_reg->recv_fifo_bytes_threshold_int_mask = 0; SMC_WRITE_REG(INTR, sc_int|0x3FF); sc_reg0_reg->rst_level = 1; sc_reg0_reg->start_atr = 1; SMC_WRITE_REG(REG0, sc_reg0); } else { pr_dbg("cold reset\n"); smc_hw_deactive(smc); udelay(200); smc_hw_active(smc); sc_reg0_reg->clk_en =1 ; sc_reg0_reg->enable = 0; sc_reg0_reg->rst_level = 0; SMC_WRITE_REG(REG0, sc_reg0); udelay(2000); // >= 400/f ; /* disable receive interrupt*/ sc_int = SMC_READ_REG(INTR); sc_int_reg->recv_fifo_bytes_threshold_int_mask = 0; SMC_WRITE_REG(INTR, sc_int|0x3FF); sc_reg0_reg->rst_level = 1; sc_reg0_reg->start_atr_en = 1; sc_reg0_reg->enable = 1; SMC_WRITE_REG(REG0, sc_reg0); } /*Read ATR*/ smc->atr.atr_len = 0; smc->recv_count = 0; smc->send_count = 0; ret = smc_hw_read_atr(smc); /*Disable ATR*/ sc_reg0 = SMC_READ_REG(REG0); sc_reg0_reg->start_atr_en = 0; sc_reg0_reg->start_atr = 0; SMC_WRITE_REG(REG0,sc_reg0); #ifndef DISABLE_RECV_INT sc_int_reg->recv_fifo_bytes_threshold_int_mask = 1; #endif SMC_WRITE_REG(INTR, sc_int|0x3FF); } return ret; }
static int smc_hw_setup(smc_dev_t *smc) { unsigned long v=0; SMCCARD_HW_Reg0_t *reg0; SMC_ANSWER_TO_RST_t *reg1; SMCCARD_HW_Reg2_t *reg2; SMC_INTERRUPT_Reg_t *reg_int; SMCCARD_HW_Reg5_t *reg5; SMCCARD_HW_Reg6_t *reg6; unsigned long freq_cpu = get_mpeg_clk()/1000; printk("SMC CLK SOURCE - %luKHz\n", freq_cpu); v = SMC_READ_REG(REG0); reg0 = (SMCCARD_HW_Reg0_t*)&v; reg0->enable = 0; reg0->clk_en = 0; reg0->clk_oen = 0; reg0->card_detect = 0; reg0->start_atr = 0; reg0->start_atr_en = 0; reg0->rst_level = 0; reg0->io_level = 0; reg0->recv_fifo_threshold = FIFO_THRESHOLD_DEFAULT; reg0->etu_divider = ETU_DIVIDER_CLOCK_HZ*smc->param.f/(smc->param.d*smc->param.freq)-1; SMC_WRITE_REG(REG0, v); v = SMC_READ_REG(REG1); reg1 = (SMC_ANSWER_TO_RST_t*)&v; reg1->atr_final_tcnt = ATR_FINAL_TCNT_DEFAULT; reg1->atr_holdoff_tcnt = ATR_HOLDOFF_TCNT_DEFAULT; reg1->atr_clk_mux = ATR_CLK_MUX_DEFAULT; reg1->atr_holdoff_en = ATR_HOLDOFF_EN; SMC_WRITE_REG(REG1, v); v = SMC_READ_REG(REG2); reg2 = (SMCCARD_HW_Reg2_t*)&v; reg2->recv_invert = smc->param.recv_invert; reg2->recv_lsb_msb = smc->param.recv_lsb_msb; reg2->xmit_invert = smc->param.xmit_invert; reg2->xmit_lsb_msb = smc->param.xmit_lsb_msb; reg2->xmit_retries = smc->param.xmit_retries; reg2->xmit_repeat_dis = smc->param.xmit_repeat_dis; reg2->recv_no_parity = smc->param.recv_no_parity; reg2->clk_tcnt = freq_cpu/smc->param.freq - 1; reg2->det_filter_sel = DET_FILTER_SEL_DEFAULT; reg2->io_filter_sel = IO_FILTER_SEL_DEFAULT; SMC_WRITE_REG(REG2, v); v = SMC_READ_REG(INTR); reg_int = (SMC_INTERRUPT_Reg_t*)&v; reg_int->recv_fifo_bytes_threshold_int_mask = 0; reg_int->send_fifo_last_byte_int_mask = 1; reg_int->cwt_expeired_int_mask = 1; reg_int->bwt_expeired_int_mask = 1; reg_int->write_full_fifo_int_mask = 1; reg_int->send_and_recv_confilt_int_mask = 1; reg_int->recv_error_int_mask = 1; reg_int->send_error_int_mask = 1; reg_int->rst_expired_int_mask = 1; reg_int->card_detect_int_mask = 0; SMC_WRITE_REG(INTR,v|0x03FF); v = SMC_READ_REG(REG5); reg5 = (SMCCARD_HW_Reg5_t*)&v; reg5->cwt_detect_en = 1; reg5->bwt_base_time_gnt = BWT_BASE_DEFAULT; SMC_WRITE_REG(REG5, v); v = SMC_READ_REG(REG6); reg6 = (SMCCARD_HW_Reg6_t*)&v; reg6->N_parameter = smc->param.n; reg6->cwi_value = smc->param.cwi; reg6->bgt = smc->param.bgt; reg6->bwi = smc->param.bwi; SMC_WRITE_REG(REG6, v); return 0; }