示例#1
0
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
{
	if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
		dev_err(pd->dev, "Unsupported zero length i2c read\n");
		return -EIO;
	}

	/* Initialize channel registers */
	iic_set_clr(pd, ICCR, 0, ICCR_ICE);

	/* Enable channel and configure rx ack */
	iic_set_clr(pd, ICCR, ICCR_ICE, 0);

	/* Set the clock */
	iic_wr(pd, ICCL, pd->iccl);
	iic_wr(pd, ICCH, pd->icch);

	pd->msg = usr_msg;
	pd->pos = -1;
	pd->sr = 0;

	/* Enable all interrupts to begin with */
	iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
	return 0;
}
示例#2
0
//8 bits register address only
static int write_eeprom(U8 slvAddr, U8 addr, U8 data)
{
	int i;
	U8 ch[3];
	
	ch[1] = addr;
	ch[2] = data;
	
	rIICDS   = slvAddr;
	rIICSTAT = 0xf0;		//MasTx,Start
	for(i=0; i<3; i++)
		if(iic_wr(ch[i], i))
			break;
	rIICSTAT = 0xd0;		//Stop MasTx condition
	if(i<3)
		return -1;
	
	i = 200;	//200ms
	while(i--) {
		Delay(1);
		rIICDS     = slvAddr;
		rIICSTAT   = 0xf0;
		if(!iic_wr(0, 0))
			break;
	}
	rIICSTAT = 0xd0;
		
	return i?0:-1;
}
示例#3
0
static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
{
	struct platform_device *dev = dev_id;
	struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
	unsigned char sr;
	int wakeup;

	sr = iic_rd(pd, ICSR);
	pd->sr |= sr; /* remember state */

	dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
	       (pd->msg->flags & I2C_M_RD) ? "read" : "write",
	       pd->pos, pd->msg->len);

	if (sr & (ICSR_AL | ICSR_TACK)) {
		/* don't interrupt transaction - continue to issue stop */
		iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
		wakeup = 0;
	} else if (pd->msg->flags & I2C_M_RD)
		wakeup = sh_mobile_i2c_isr_rx(pd);
	else
		wakeup = sh_mobile_i2c_isr_tx(pd);

	if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
		iic_wr(pd, ICSR, sr & ~ICSR_WAIT);

	if (wakeup) {
		pd->sr |= SW_DONE;
		wake_up(&pd->wait);
	}

	return IRQ_HANDLED;
}
示例#4
0
static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
		     bool do_init)
{
	if (do_init) {
		/* Initialize channel registers */
		iic_wr(pd, ICCR, ICCR_SCP);

		/* Enable channel and configure rx ack */
		iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);

		/* Set the clock */
		iic_wr(pd, ICCL, pd->iccl & 0xff);
		iic_wr(pd, ICCH, pd->icch & 0xff);
	}

	pd->msg = usr_msg;
	pd->pos = -1;
	pd->sr = 0;

	pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
	if (pd->dma_buf)
		sh_mobile_i2c_xfer_dma(pd);

	/* Enable all interrupts to begin with */
	iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
}
示例#5
0
//8 bits register address only
static int read_eeprom(U8 slvAddr, U8 addr, U8 *pBuf)
{
	int i;
	U8 ch[2];
	
	ch[1] = addr;
	
	rIICDS   = slvAddr;
	rIICSTAT = 0xf0;		//MasTx,Start
	for(i=0; i<2; i++)
		if(iic_wr(ch[i], i))
			break;
	if(i<2) {
		rIICSTAT = 0xd0;	//Stop MasTx condition
		return -1;
	}

	rIICDS   = slvAddr;
	rIICSTAT = 0xb0;		//Master Rx,Start
	if(!iic_wr(0, 0))		//wait ack
		i = iic_rd(pBuf);	
	rIICSTAT = 0x90;		//Stop MaxRx condition
	
	return i;
}
示例#6
0
static void deactivate_ch(struct sh_mobile_i2c_data *pd)
{
	/* Clear/disable interrupts */
	iic_wr(pd, ICSR, 0);
	iic_wr(pd, ICIC, 0);

	/* Disable channel */
	iic_set_clr(pd, ICCR, 0, ICCR_ICE);

	/* Disable clock and mark device as idle */
	clk_disable(pd->clk);
	pm_runtime_put_sync(pd->dev);
}
示例#7
0
static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
			    enum sh_mobile_i2c_op op, unsigned char data)
{
	unsigned char ret = 0;
	unsigned long flags;

	dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);

	spin_lock_irqsave(&pd->lock, flags);

	switch (op) {
	case OP_START: /* issue start and trigger DTE interrupt */
		iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY);
		break;
	case OP_TX_FIRST: /* disable DTE interrupt and write data */
		iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
		iic_wr(pd, ICDR, data);
		break;
	case OP_TX: /* write data */
		iic_wr(pd, ICDR, data);
		break;
	case OP_TX_STOP: /* issue a stop (or rep_start) */
		iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
					       : ICCR_ICE | ICCR_TRS | ICCR_BBSY);
		break;
	case OP_TX_TO_RX: /* select read mode */
		iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
		break;
	case OP_RX: /* just read data */
		ret = iic_rd(pd, ICDR);
		break;
	case OP_RX_STOP: /* enable DTE interrupt, issue stop */
		iic_wr(pd, ICIC,
		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
		break;
	case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
		iic_wr(pd, ICIC,
		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
		ret = iic_rd(pd, ICDR);
		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
		break;
	}

	spin_unlock_irqrestore(&pd->lock, flags);

	dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
	return ret;
}
示例#8
0
static void activate_ch(struct sh_mobile_i2c_data *pd)
{
	/* Wake up device and enable clock */
	pm_runtime_get_sync(pd->dev);
	clk_prepare_enable(pd->clk);

	/* Enable channel and configure rx ack */
	iic_set_clr(pd, ICCR, ICCR_ICE, 0);

	/* Mask all interrupts */
	iic_wr(pd, ICIC, 0);

	/* Set the clock */
	iic_wr(pd, ICCL, pd->iccl & 0xff);
	iic_wr(pd, ICCH, pd->icch & 0xff);
}
示例#9
0
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
			      struct i2c_msg *msgs,
			      int num)
{
	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
	struct i2c_msg	*msg;
	int err = 0;
	int i;
	long timeout;

	/* Wake up device and enable clock */
	pm_runtime_get_sync(pd->dev);

	/* Process all messages */
	for (i = 0; i < num; i++) {
		bool do_start = pd->send_stop || !i;
		msg = &msgs[i];
		pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
		pd->stop_after_dma = false;

		start_ch(pd, msg, do_start);

		if (do_start)
			i2c_op(pd, OP_START, 0);

		/* The interrupt handler takes care of the rest... */
		timeout = wait_event_timeout(pd->wait,
				       pd->sr & (ICSR_TACK | SW_DONE),
				       adapter->timeout);

		/* 'stop_after_dma' tells if DMA transfer was complete */
		i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);

		if (!timeout) {
			dev_err(pd->dev, "Transfer request timed out\n");
			if (pd->dma_direction != DMA_NONE)
				sh_mobile_i2c_cleanup_dma(pd);

			err = -ETIMEDOUT;
			break;
		}

		if (pd->send_stop)
			err = poll_busy(pd);
		else
			err = poll_dte(pd);
		if (err < 0)
			break;
	}

	/* Disable channel */
	iic_wr(pd, ICCR, ICCR_SCP);

	/* Disable clock and mark device as idle */
	pm_runtime_put_sync(pd->dev);

	return err ?: num;
}
示例#10
0
static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
{
	struct sh_mobile_i2c_data *pd = dev_id;
	unsigned char sr;
	int wakeup = 0;

	sr = iic_rd(pd, ICSR);
	pd->sr |= sr; /* remember state */

	dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
	       (pd->msg->flags & I2C_M_RD) ? "read" : "write",
	       pd->pos, pd->msg->len);

	/* Kick off TxDMA after preface was done */
	if (pd->dma_direction == DMA_TO_DEVICE && pd->pos == 0)
		iic_set_clr(pd, ICIC, ICIC_TDMAE, 0);
	else if (sr & (ICSR_AL | ICSR_TACK))
		/* don't interrupt transaction - continue to issue stop */
		iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
	else if (pd->msg->flags & I2C_M_RD)
		wakeup = sh_mobile_i2c_isr_rx(pd);
	else
		wakeup = sh_mobile_i2c_isr_tx(pd);

	/* Kick off RxDMA after preface was done */
	if (pd->dma_direction == DMA_FROM_DEVICE && pd->pos == 1)
		iic_set_clr(pd, ICIC, ICIC_RDMAE, 0);

	if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
		iic_wr(pd, ICSR, sr & ~ICSR_WAIT);

	if (wakeup) {
		pd->sr |= SW_DONE;
		wake_up(&pd->wait);
	}

	/* defeat write posting to avoid spurious WAIT interrupts */
	iic_rd(pd, ICSR);

	return IRQ_HANDLED;
}
示例#11
0
/*
 * r8a7740 chip has lasting errata on I2C I/O pad reset.
 * this is work-around for it.
 */
static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
{
	iic_set_clr(pd, ICCR, ICCR_ICE, 0);
	iic_rd(pd, ICCR); /* dummy read */

	iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0);
	iic_rd(pd, ICSTART); /* dummy read */

	udelay(10);

	iic_wr(pd, ICCR, ICCR_SCP);
	iic_wr(pd, ICSTART, 0);

	udelay(10);

	iic_wr(pd, ICCR, ICCR_TRS);
	udelay(10);
	iic_wr(pd, ICCR, 0);
	udelay(10);
	iic_wr(pd, ICCR, ICCR_TRS);
	udelay(10);

	return sh_mobile_i2c_init(pd);
}
示例#12
0
static int seek_iic_device(U8 slvAddr)
{
	int i;
	
	i = 40;	//400ms
	while(i--) {
		rIICDS   = slvAddr;
		rIICSTAT = 0xf0;	//MasTx,Start
		if(!iic_wr(0, 0))	
			break;
		Delay(10);
	}
	rIICSTAT = 0xd0;		//Stop MasTx condition
	return i<40;
}
示例#13
0
static void activate_ch(struct sh_mobile_i2c_data *pd)
{
	unsigned long i2c_clk;
	u_int32_t num;
	u_int32_t denom;
	u_int32_t tmp;

	/* Wake up device and enable clock */
	pm_runtime_get_sync(pd->dev);
	clk_enable(pd->clk);

	/* Get clock rate after clock is enabled */
	i2c_clk = clk_get_rate(pd->clk);

	/* Calculate the value for iccl. From the data sheet:
	 * iccl = (p clock / transfer rate) * (L / (L + H))
	 * where L and H are the SCL low/high ratio (5/4 in this case).
	 * We also round off the result.
	 */
	num = i2c_clk * 5;
	denom = NORMAL_SPEED * 9;
	tmp = num * 10 / denom;
	if (tmp % 10 >= 5)
		pd->iccl = (u_int8_t)((num/denom) + 1);
	else
		pd->iccl = (u_int8_t)(num/denom);

	/* one more bit of ICCL in ICIC */
	if (pd->flags & IIC_FLAG_HAS_ICIC67) {
		if ((num/denom) > 0xff)
			pd->icic |= ICIC_ICCLB8;
		else
			pd->icic &= ~ICIC_ICCLB8;
	}

	/* Calculate the value for icch. From the data sheet:
	   icch = (p clock / transfer rate) * (H / (L + H)) */
	num = i2c_clk * 4;
	tmp = num * 10 / denom;
	if (tmp % 10 >= 5)
		pd->icch = (u_int8_t)((num/denom) + 1);
	else
		pd->icch = (u_int8_t)(num/denom);

	/* one more bit of ICCH in ICIC */
	if (pd->flags & IIC_FLAG_HAS_ICIC67) {
		if ((num/denom) > 0xff)
			pd->icic |= ICIC_ICCHB8;
		else
			pd->icic &= ~ICIC_ICCHB8;
	}

	/* Enable channel and configure rx ack */
	iic_set_clr(pd, ICCR, ICCR_ICE, 0);

	/* Mask all interrupts */
	iic_wr(pd, ICIC, 0);

	/* Set the clock */
	iic_wr(pd, ICCL, pd->iccl);
	iic_wr(pd, ICCH, pd->icch);
}
示例#14
0
static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
			unsigned char set, unsigned char clr)
{
	iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
}