コード例 #1
0
ファイル: i2c-sh_mobile.c プロジェクト: ANFS/ANFS-kernel
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
ファイル: i2c-sh_mobile.c プロジェクト: AlexShiLucky/linux
static void sh_mobile_i2c_dma_callback(void *data)
{
	struct sh_mobile_i2c_data *pd = data;

	sh_mobile_i2c_dma_unmap(pd);
	pd->pos = pd->msg->len;
	pd->stop_after_dma = true;

	iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
}
コード例 #3
0
ファイル: i2c-sh_mobile.c プロジェクト: AlexShiLucky/linux
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;
}
コード例 #4
0
ファイル: i2c-sh_mobile.c プロジェクト: ANFS/ANFS-kernel
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);
}
コード例 #5
0
ファイル: i2c-sh_mobile.c プロジェクト: AlexShiLucky/linux
/*
 * 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);
}
コード例 #6
0
ファイル: i2c-sh_mobile.c プロジェクト: Amitabha2001/linux
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);
}
コード例 #7
0
ファイル: i2c-sh_mobile.c プロジェクト: ANFS/ANFS-kernel
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);
}