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;
}
Example #4
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;
}