From 47bb27e78867997040a228328f2a631c3c7f2c82 Mon Sep 17 00:00:00 2001 From: "Du, Wenkai" Date: Thu, 10 Apr 2014 23:03:19 +0000 Subject: i2c: designware: Mask all interrupts during i2c controller enable There have been "i2c_designware 80860F41:00: controller timed out" errors on a number of Baytrail platforms. The issue is caused by incorrect value in Interrupt Mask Register (DW_IC_INTR_MASK) when i2c core is being enabled. This causes call to __i2c_dw_enable() to immediately start the transfer which leads to timeout. There are 3 failure modes observed: 1. Failure in S0 to S3 resume path The default value after reset for DW_IC_INTR_MASK is 0x8ff. When we start the first transaction after resuming from system sleep, TX_EMPTY interrupt is already unmasked because of the hardware default. 2. Failure in normal operational path This failure happens rarely and is hard to reproduce. Debug trace showed that DW_IC_INTR_MASK had value of 0x254 when failure occurred, which meant TX_EMPTY was unmasked. 3. Failure in S3 to S0 suspend path This failure also happens rarely and is hard to reproduce. Adding debug trace that read DW_IC_INTR_MASK made this failure not reproducible. But from ISR call trace we could conclude TX_EMPTY was unmasked when problem occurred. The patch masks all interrupts before the controller is enabled to resolve the faulty DW_IC_INTR_MASK conditions. Signed-off-by: Wenkai Du Acked-by: Mika Westerberg [wsa: improved the comment and removed typo in commit msg] Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-designware-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 22e92c3d3d0..3c20e4bd6dd 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -422,6 +422,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) */ dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR); + /* enforce disabled interrupts (due to HW issues) */ + i2c_dw_disable_int(dev); + /* Enable the adapter */ __i2c_dw_enable(dev, true); -- cgit v1.2.3-70-g09d2 From 37e5eb0bae7bb4d98c2153c3c3400b5c00c3cad1 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 10 Apr 2014 16:19:29 +0200 Subject: i2c: nomadik: Don't use IS_ERR for devm_ioremap devm_ioremap() returns NULL on error, not an error. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-nomadik.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 28cbe1b2a2e..32c85e9ecda 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -999,7 +999,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) dev->virtbase = devm_ioremap(&adev->dev, adev->res.start, resource_size(&adev->res)); - if (IS_ERR(dev->virtbase)) { + if (!dev->virtbase) { ret = -ENOMEM; goto err_no_mem; } -- cgit v1.2.3-70-g09d2 From ce78cc071f5f541480e381cc0241d37590041a9d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 11 Apr 2014 15:19:41 -0700 Subject: i2c: s3c2410: resume race fix Don't unmark the device as suspended until after it's been re-setup. The main race would be w.r.t. an i2c driver that gets resumed at the same time (asyncronously), that is allowed to do a transfer since suspended is set to 0 before reinit, but really should have seen the -EIO return instead. Signed-off-by: Olof Johansson Signed-off-by: Doug Anderson Acked-by: Kukjin Kim Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-s3c2410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index ae4491062e4..bb3a9964f7e 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1276,10 +1276,10 @@ static int s3c24xx_i2c_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); - i2c->suspended = 0; clk_prepare_enable(i2c->clk); s3c24xx_i2c_init(i2c); clk_disable_unprepare(i2c->clk); + i2c->suspended = 0; return 0; } -- cgit v1.2.3-70-g09d2 From fa01d096bfcfd89398b1f3a3f91805dab76f7fe5 Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Fri, 2 May 2014 20:54:29 -0500 Subject: i2c: qup: Fix pm_runtime_get_sync usage This patch corrects the error check on the call to pm_runtime_get_sync. Signed-off-by: Andy Gross Reviewed-by: Ivan T. Ivanov Acked-by: Bjorn Andersson Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 1b4cf14f110..2a5efb5b487 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -479,7 +479,7 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, int ret, idx; ret = pm_runtime_get_sync(qup->dev); - if (ret) + if (ret < 0) goto out; writel(1, qup->base + QUP_SW_RESET); -- cgit v1.2.3-70-g09d2 From d7653964c590ba846aa11a8f6edf409773cbc492 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 May 2014 18:36:21 +0200 Subject: i2c: rcar: bail out on zero length transfers This hardware does not support zero length transfers. Instead, the driver does one (random) byte transfers currently with undefined results for the slaves. We now bail out. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-rcar.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index d4fa8eba6e9..06d47aafbb7 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -561,6 +561,12 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ret = -EINVAL; for (i = 0; i < num; i++) { + /* This HW can't send STOP after address phase */ + if (msgs[i].len == 0) { + ret = -EOPNOTSUPP; + break; + } + /*-------------- spin lock -----------------*/ spin_lock_irqsave(&priv->lock, flags); @@ -625,7 +631,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, static u32 rcar_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + /* This HW can't do SMBUS_QUICK and NOSTART */ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); } static const struct i2c_algorithm rcar_i2c_algo = { -- cgit v1.2.3-70-g09d2 From 5ed9d92f1b0fbed3fe4370a91b4baed58c3d2a23 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 31 Mar 2014 14:54:57 +0200 Subject: i2c: mv64xxx: Change i2c compatibles for sunxi The Allwinner A10 compatibles were following a slightly different compatible patterns than the rest of the SoCs for historical reasons. Move to the other pattern for consistency across all Allwinner Socs. Signed-off-by: Maxime Ripard [wsa: dropped binding OK as per http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229438.html] Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt | 2 +- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt index befd4fb4764..5c30026921a 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -5,7 +5,7 @@ Required properties : - reg : Offset and length of the register set for the device - compatible : Should be either: - - "allwinner,sun4i-i2c" + - "allwinner,sun4i-a10-i2c" - "allwinner,sun6i-a31-i2c" - "marvell,mv64xxx-i2c" - "marvell,mv78230-i2c" diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 540ea692bf7..9f4b775e2e3 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -681,7 +681,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = { ***************************************************************************** */ static const struct of_device_id mv64xxx_i2c_of_match_table[] = { - { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, + { .compatible = "allwinner,sun4i-a10-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "allwinner,sun6i-a31-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, -- cgit v1.2.3-70-g09d2 From 8e8782c71595a5ad29e234ce6b3d2fce787fb07a Mon Sep 17 00:00:00 2001 From: Kaushal Butala Date: Fri, 4 Apr 2014 14:56:10 +0200 Subject: i2c: imx: add SMBus block read support The smbus block read is not currently supported for imx i2c devices. This patchset adds the support to imx i2c bus so that blocks of data can be read using SMbus block reads.(using i2c_smbus_read_block_data() function from the i2c_core.c.). Tested with 3.10.9 kernel. Reviewed-by: Shawn Guo Signed-off-by: Kaushal Butala Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index db895fb22e6..886217f1ba6 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -462,6 +462,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) { int i, result; unsigned int temp; + int block_data = msgs->flags & I2C_M_RECV_LEN; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", @@ -481,7 +482,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) /* setup bus to read data */ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp &= ~I2CR_MTX; - if (msgs->len - 1) + + /* + * Reset the I2CR_TXAK flag initially for SMBus block read since the + * length is unknown + */ + if ((msgs->len - 1) || block_data) temp &= ~I2CR_TXAK; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ @@ -490,9 +496,24 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) /* read data */ for (i = 0; i < msgs->len; i++) { + u8 len = 0; result = i2c_imx_trx_complete(i2c_imx); if (result) return result; + /* + * First byte is the length of remaining packet + * in the SMBus block data read. Add it to + * msgs->len. + */ + if ((!i) && block_data) { + len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) + return -EPROTO; + dev_dbg(&i2c_imx->adapter.dev, + "<%s> read length: 0x%X\n", + __func__, len); + msgs->len += len; + } if (i == (msgs->len - 1)) { /* It must generate STOP before read I2DR to prevent controller from generating another clock cycle */ @@ -510,7 +531,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) temp |= I2CR_TXAK; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); } - msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + if ((!i) && block_data) + msgs->buf[0] = len; + else + msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); dev_dbg(&i2c_imx->adapter.dev, "<%s> read byte: B%d=0x%X\n", __func__, i, msgs->buf[i]); @@ -583,7 +607,8 @@ fail0: static u32 i2c_imx_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL + | I2C_FUNC_SMBUS_READ_BLOCK_DATA; } static struct i2c_algorithm i2c_imx_algo = { -- cgit v1.2.3-70-g09d2 From 9219982bc64a41ec7745668b06f86e97b498e10a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 10 Apr 2014 15:59:36 +0200 Subject: i2c: nomadik: Fixup system suspend For !CONFIG_PM_RUNTIME, the device were never put back into active state while resuming. For CONFIG_PM_RUNTIME, we blindly trusted the device to be inactive while we were about to handle it at suspend late, which is just too optimistic. Even if the driver uses pm_runtime_put_sync() after each tranfer to return it's runtime PM resources, there are no guarantees this will actually mean the device will inactivated. The reason is that the PM core will prevent runtime suspend during system suspend, and thus when a transfer occurs during the early phases of system suspend the device will be kept active after the transfer. To handle both issues above, use pm_runtime_force_suspend|resume() from the system suspend|resume callbacks. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 32c85e9ecda..0e55d85fd4e 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -879,19 +879,19 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) #ifdef CONFIG_PM_SLEEP static int nmk_i2c_suspend_late(struct device *dev) { - pinctrl_pm_select_sleep_state(dev); + int ret; + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + pinctrl_pm_select_sleep_state(dev); return 0; } static int nmk_i2c_resume_early(struct device *dev) { - /* First go to the default state */ - pinctrl_pm_select_default_state(dev); - /* Then let's idle the pins until the next transfer happens */ - pinctrl_pm_select_idle_state(dev); - - return 0; + return pm_runtime_force_resume(dev); } #endif -- cgit v1.2.3-70-g09d2 From 482116badacba9308abd6c5cae2f5f19e2f81449 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Fri, 11 Apr 2014 13:44:44 +0200 Subject: i2c: ali1563: fix checkpatch.pl issues Fixed most checkpatch.pl issues Signed-off-by: Richard Leitner Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ali1563.c | 82 ++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 37 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 98a1c97739b..15517d78d5f 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -63,7 +63,7 @@ static struct pci_driver ali1563_pci_driver; static unsigned short ali1563_smba; -static int ali1563_transaction(struct i2c_adapter * a, int size) +static int ali1563_transaction(struct i2c_adapter *a, int size) { u32 data; int timeout; @@ -78,7 +78,7 @@ static int ali1563_transaction(struct i2c_adapter * a, int size) data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) { dev_err(&a->dev, "ali1563: Trying to reset busy device\n"); - outb_p(data | HST_STS_BAD,SMB_HST_STS); + outb_p(data | HST_STS_BAD, SMB_HST_STS); data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) return -EBUSY; @@ -102,10 +102,10 @@ static int ali1563_transaction(struct i2c_adapter * a, int size) if (!timeout) { dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n"); /* Issue 'kill' to host controller */ - outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); + outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2); data = inb_p(SMB_HST_STS); status = -ETIMEDOUT; - } + } /* device error - no response, ignore the autodetection case */ if (data & HST_STS_DEVERR) { @@ -117,18 +117,18 @@ static int ali1563_transaction(struct i2c_adapter * a, int size) if (data & HST_STS_BUSERR) { dev_err(&a->dev, "Bus collision!\n"); /* Issue timeout, hoping it helps */ - outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); + outb_p(HST_CNTL1_TIMEOUT, SMB_HST_CNTL1); } if (data & HST_STS_FAIL) { dev_err(&a->dev, "Cleaning fail after KILL!\n"); - outb_p(0x0,SMB_HST_CNTL2); + outb_p(0x0, SMB_HST_CNTL2); } return status; } -static int ali1563_block_start(struct i2c_adapter * a) +static int ali1563_block_start(struct i2c_adapter *a) { u32 data; int timeout; @@ -142,8 +142,8 @@ static int ali1563_block_start(struct i2c_adapter * a) data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) { - dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); - outb_p(data | HST_STS_BAD,SMB_HST_STS); + dev_warn(&a->dev, "ali1563: Trying to reset busy device\n"); + outb_p(data | HST_STS_BAD, SMB_HST_STS); data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) return -EBUSY; @@ -184,13 +184,14 @@ static int ali1563_block_start(struct i2c_adapter * a) return status; } -static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw) +static int ali1563_block(struct i2c_adapter *a, + union i2c_smbus_data *data, u8 rw) { int i, len; int error = 0; /* Do we need this? */ - outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1); if (rw == I2C_SMBUS_WRITE) { len = data->block[0]; @@ -198,8 +199,8 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 len = 1; else if (len > 32) len = 32; - outb_p(len,SMB_HST_DAT0); - outb_p(data->block[1],SMB_BLK_DAT); + outb_p(len, SMB_HST_DAT0); + outb_p(data->block[1], SMB_BLK_DAT); } else len = 32; @@ -208,10 +209,12 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 for (i = 0; i < len; i++) { if (rw == I2C_SMBUS_WRITE) { outb_p(data->block[i + 1], SMB_BLK_DAT); - if ((error = ali1563_block_start(a))) + error = ali1563_block_start(a); + if (error) break; } else { - if ((error = ali1563_block_start(a))) + error = ali1563_block_start(a); + if (error) break; if (i == 0) { len = inb_p(SMB_HST_DAT0); @@ -224,25 +227,26 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 } } /* Do we need this? */ - outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1); return error; } -static s32 ali1563_access(struct i2c_adapter * a, u16 addr, +static s32 ali1563_access(struct i2c_adapter *a, u16 addr, unsigned short flags, char rw, u8 cmd, - int size, union i2c_smbus_data * data) + int size, union i2c_smbus_data *data) { int error = 0; int timeout; u32 reg; for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) { - if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY)) + reg = inb_p(SMB_HST_STS); + if (!(reg & HST_STS_BUSY)) break; } if (!timeout) - dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg); - outb_p(0xff,SMB_HST_STS); + dev_warn(&a->dev, "SMBus not idle. HST_STS = %02x\n", reg); + outb_p(0xff, SMB_HST_STS); /* Map the size to what the chip understands */ switch (size) { @@ -268,13 +272,14 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, } outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); - outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2); + outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | + (size << 3), SMB_HST_CNTL2); /* Write the command register */ - switch(size) { + switch (size) { case HST_CNTL2_BYTE: - if (rw== I2C_SMBUS_WRITE) + if (rw == I2C_SMBUS_WRITE) /* Beware it uses DAT0 register and not CMD! */ outb_p(cmd, SMB_HST_DAT0); break; @@ -292,11 +297,12 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, break; case HST_CNTL2_BLOCK: outb_p(cmd, SMB_HST_CMD); - error = ali1563_block(a,data,rw); + error = ali1563_block(a, data, rw); goto Done; } - if ((error = ali1563_transaction(a, size))) + error = ali1563_transaction(a, size); + if (error) goto Done; if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) @@ -317,7 +323,7 @@ Done: return error; } -static u32 ali1563_func(struct i2c_adapter * a) +static u32 ali1563_func(struct i2c_adapter *a) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | @@ -329,13 +335,13 @@ static int ali1563_setup(struct pci_dev *dev) { u16 ctrl; - pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); + pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); /* SMB I/O Base in high 12 bits and must be aligned with the * size of the I/O space. */ ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); if (!ali1563_smba) { - dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); + dev_warn(&dev->dev, "ali1563_smba Uninitialized\n"); goto Err; } @@ -350,8 +356,8 @@ static int ali1563_setup(struct pci_dev *dev) ctrl | ALI1563_SMB_IOEN); pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); if (!(ctrl & ALI1563_SMB_IOEN)) { - dev_err(&dev->dev, "I/O space still not enabled, " - "giving up\n"); + dev_err(&dev->dev, + "I/O space still not enabled, giving up\n"); goto Err; } } @@ -375,7 +381,7 @@ Err: static void ali1563_shutdown(struct pci_dev *dev) { - release_region(ali1563_smba,ALI1563_SMB_IOSIZE); + release_region(ali1563_smba, ALI1563_SMB_IOSIZE); } static const struct i2c_algorithm ali1563_algorithm = { @@ -394,12 +400,14 @@ static int ali1563_probe(struct pci_dev *dev, { int error; - if ((error = ali1563_setup(dev))) + error = ali1563_setup(dev); + if (error) goto exit; ali1563_adapter.dev.parent = &dev->dev; snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name), "SMBus ALi 1563 Adapter @ %04x", ali1563_smba); - if ((error = i2c_add_adapter(&ali1563_adapter))) + error = i2c_add_adapter(&ali1563_adapter); + if (error) goto exit_shutdown; return 0; @@ -421,12 +429,12 @@ static const struct pci_device_id ali1563_id_table[] = { {}, }; -MODULE_DEVICE_TABLE (pci, ali1563_id_table); +MODULE_DEVICE_TABLE(pci, ali1563_id_table); static struct pci_driver ali1563_pci_driver = { - .name = "ali1563_smbus", + .name = "ali1563_smbus", .id_table = ali1563_id_table, - .probe = ali1563_probe, + .probe = ali1563_probe, .remove = ali1563_remove, }; -- cgit v1.2.3-70-g09d2 From 218e1496135e94e901bf1c136d81ede7e2b418b8 Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Mon, 28 Apr 2014 14:29:58 +0530 Subject: i2c: exynos5: add support for HSI2C on Exynos5260 SoC HSI2C module on Exynos5260 differs from current modules in following ways: 1. HSI2C on Exynos5260 has fifo_depth of 16bytes 2. Module needs to be reset as a part of init sequence. Hence, Following changes are involved. 1. Add a new compatible string and Updates the Documentation dt bindings. 2. Introduce a variant struct to support the changes in H/W 3. Reset the module during init. Thus, bringing the module back to default state irrespective of what firmware did with it. Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Pankaj Dubey Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-exynos5.txt | 11 +++- drivers/i2c/busses/i2c-exynos5.c | 67 ++++++++++++++++++---- 2 files changed, 64 insertions(+), 14 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt index 056732cfdce..d4745e31f5c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt @@ -5,7 +5,14 @@ at various speeds ranging from 100khz to 3.4Mhz. Required properties: - compatible: value should be. - -> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c. + -> "samsung,exynos5-hsi2c", (DEPRECATED) + for i2c compatible with HSI2C available + on Exynos5250 and Exynos5420 SoCs. + -> "samsung,exynos5250-hsi2c", for i2c compatible with HSI2C available + on Exynos5250 and Exynos5420 SoCs. + -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available + on Exynos5260 SoCs. + - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt number to the cpu. @@ -26,7 +33,7 @@ Optional properties: Example: hsi2c@12ca0000 { - compatible = "samsung,exynos5-hsi2c"; + compatible = "samsung,exynos5250-hsi2c"; reg = <0x12ca0000 0x100>; interrupts = <56>; clock-frequency = <100000>; diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 00af0a0a336..ba1faf0ef96 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -76,12 +76,6 @@ #define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4) #define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16) -/* As per user manual FIFO max depth is 64bytes */ -#define HSI2C_FIFO_MAX 0x40 -/* default trigger levels for Tx and Rx FIFOs */ -#define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30) -#define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10) - /* I2C_TRAILING_CTL Register bits */ #define HSI2C_TRAILING_COUNT (0xf) @@ -183,14 +177,54 @@ struct exynos5_i2c { * 2. Fast speed upto 1Mbps */ int speed_mode; + + /* Version of HS-I2C Hardware */ + struct exynos_hsi2c_variant *variant; +}; + +/** + * struct exynos_hsi2c_variant - platform specific HSI2C driver data + * @fifo_depth: the fifo depth supported by the HSI2C module + * + * Specifies platform specific configuration of HSI2C module. + * Note: A structure for driver specific platform data is used for future + * expansion of its usage. + */ +struct exynos_hsi2c_variant { + unsigned int fifo_depth; +}; + +static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { + .fifo_depth = 64, +}; + +static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { + .fifo_depth = 16, }; static const struct of_device_id exynos5_i2c_match[] = { - { .compatible = "samsung,exynos5-hsi2c" }, - {}, + { + .compatible = "samsung,exynos5-hsi2c", + .data = &exynos5250_hsi2c_data + }, { + .compatible = "samsung,exynos5250-hsi2c", + .data = &exynos5250_hsi2c_data + }, { + .compatible = "samsung,exynos5260-hsi2c", + .data = &exynos5260_hsi2c_data + }, {}, }; MODULE_DEVICE_TABLE(of, exynos5_i2c_match); +static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant + (struct platform_device *pdev) +{ + const struct of_device_id *match; + + match = of_match_node(exynos5_i2c_match, pdev->dev.of_node); + return (struct exynos_hsi2c_variant *)match->data; +} + static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) { writel(readl(i2c->regs + HSI2C_INT_STATUS), @@ -415,7 +449,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); - len = HSI2C_FIFO_MAX - fifo_level; + len = i2c->variant->fifo_depth - fifo_level; if (len > (i2c->msg->len - i2c->msg_ptr)) len = i2c->msg->len - i2c->msg_ptr; @@ -483,6 +517,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) u32 i2c_auto_conf = 0; u32 fifo_ctl; unsigned long flags; + unsigned short trig_lvl; i2c_ctl = readl(i2c->regs + HSI2C_CTL); i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); @@ -493,13 +528,19 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) i2c_auto_conf = HSI2C_READ_WRITE; - fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL); + trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? + (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len; + fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl); + int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN | HSI2C_INT_TRAILING_EN); } else { i2c_ctl |= HSI2C_TXCHON; - fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL); + trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? + (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len; + fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_lvl); + int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN; } @@ -691,7 +732,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev) if (ret) goto err_clk; - exynos5_i2c_init(i2c); + i2c->variant = exynos5_i2c_get_variant(pdev); + + exynos5_i2c_reset(i2c); ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { -- cgit v1.2.3-70-g09d2 From a78f6a4140f95cbedc0b28c4c883e8aa9ba044f1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:07 +0200 Subject: i2c: sh_mobile: replace magic hex values with constants No functional change, binaries are identical. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 1d79585ba4b..d91625eea6b 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -316,7 +316,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, switch (op) { case OP_START: /* issue start and trigger DTE interrupt */ - iic_wr(pd, ICCR, 0x94); + 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); @@ -327,10 +327,11 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, break; case OP_TX_STOP: /* write data and issue a stop afterwards */ iic_wr(pd, ICDR, data); - iic_wr(pd, ICCR, pd->send_stop ? 0x90 : 0x94); + 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, 0x81); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP); break; case OP_RX: /* just read data */ ret = iic_rd(pd, ICDR); @@ -338,13 +339,13 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, 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, 0xc0); + 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, 0xc0); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); break; } -- cgit v1.2.3-70-g09d2 From 5a72b25e7896e6358b62b590ce5b3a457516ae40 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:08 +0200 Subject: i2c: sh_mobile: improve error handling Use standard i2c error codes for i2c failures. Also, don't print something on timeout since it happens regularly with i2c. Simplify some, logic, too. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index d91625eea6b..d2fa222df3d 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -480,7 +480,7 @@ 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; + return -EOPNOTSUPP; } if (do_init) { @@ -515,17 +515,12 @@ static int poll_dte(struct sh_mobile_i2c_data *pd) break; if (val & ICSR_TACK) - return -EIO; + return -ENXIO; udelay(10); } - if (!i) { - dev_warn(pd->dev, "Timeout polling for DTE!\n"); - return -ETIMEDOUT; - } - - return 0; + return i ? 0 : -ETIMEDOUT; } static int poll_busy(struct sh_mobile_i2c_data *pd) @@ -543,20 +538,18 @@ static int poll_busy(struct sh_mobile_i2c_data *pd) */ if (!(val & ICSR_BUSY)) { /* handle missing acknowledge and arbitration lost */ - if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) - return -EIO; + val |= pd->sr; + if (val & ICSR_TACK) + return -ENXIO; + if (val & ICSR_AL) + return -EAGAIN; break; } udelay(10); } - if (!i) { - dev_err(pd->dev, "Polling timed out\n"); - return -ETIMEDOUT; - } - - return 0; + return i ? 0 : -ETIMEDOUT; } static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, -- cgit v1.2.3-70-g09d2 From 88c289ec28dfb0f383dcdbadd2c759f910585815 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:09 +0200 Subject: i2c: sh_mobile: honor DT bus speed settings Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index d2fa222df3d..2e481abd50c 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -657,6 +657,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct resource *res; int size; int ret; + u32 bus_speed; pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL); if (pd == NULL) { @@ -697,7 +698,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) } /* Use platform data bus speed or STANDARD_MODE */ - pd->bus_speed = STANDARD_MODE; + ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); + pd->bus_speed = ret ? STANDARD_MODE : bus_speed; + if (pdata && pdata->bus_speed) pd->bus_speed = pdata->bus_speed; pd->clks_per_count = 1; -- cgit v1.2.3-70-g09d2 From 4fd31c2eb7bf19927524bca1c5c17e6bb0f4f6eb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:11 +0200 Subject: i2c: sh_mobile: devm conversion, low hanging fruits Convert the easy parts to devm. irqs will be converted in a seperate patch to keep diffs readable. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 41 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2e481abd50c..c47d11493b9 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -655,45 +655,33 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - int size; int ret; u32 bus_speed; - pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL); - if (pd == NULL) { - dev_err(&dev->dev, "cannot allocate private data\n"); + pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL); + if (!pd) return -ENOMEM; - } - pd->clk = clk_get(&dev->dev, NULL); + pd->clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(pd->clk)) { dev_err(&dev->dev, "cannot get clock\n"); - ret = PTR_ERR(pd->clk); - goto err; + return PTR_ERR(pd->clk); } ret = sh_mobile_i2c_hook_irqs(dev, 1); if (ret) { dev_err(&dev->dev, "cannot request IRQ\n"); - goto err_clk; + return ret; } pd->dev = &dev->dev; platform_set_drvdata(dev, pd); res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&dev->dev, "cannot find IO resource\n"); - ret = -ENOENT; - goto err_irq; - } - size = resource_size(res); - - pd->reg = ioremap(res->start, size); - if (pd->reg == NULL) { - dev_err(&dev->dev, "cannot map IO\n"); - ret = -ENXIO; + pd->reg = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(pd->reg)) { + ret = PTR_ERR(pd->reg); goto err_irq; } @@ -710,7 +698,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. */ - if (size > 0x17) + if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; sh_mobile_i2c_init(pd); @@ -747,7 +735,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(adap); if (ret < 0) { dev_err(&dev->dev, "cannot add numbered adapter\n"); - goto err_all; + goto err_irq; } dev_info(&dev->dev, @@ -756,14 +744,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return 0; - err_all: - iounmap(pd->reg); err_irq: sh_mobile_i2c_hook_irqs(dev, 0); - err_clk: - clk_put(pd->clk); - err: - kfree(pd); return ret; } @@ -772,11 +754,8 @@ static int sh_mobile_i2c_remove(struct platform_device *dev) struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); i2c_del_adapter(&pd->adap); - iounmap(pd->reg); sh_mobile_i2c_hook_irqs(dev, 0); - clk_put(pd->clk); pm_runtime_disable(&dev->dev); - kfree(pd); return 0; } -- cgit v1.2.3-70-g09d2 From 7fe8a9993337e4d1957737b4468fc574af8fb957 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:12 +0200 Subject: i2c: sh_mobile: devm conversion, irq setup This is what devm was made for. No rollback mechanism needed, remove the hook parameter from the irq setup function and simplify it. While we are here change some variables to proper types. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 56 ++++++++++---------------------------- 1 file changed, 15 insertions(+), 41 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c47d11493b9..ddc9970fd72 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -611,42 +611,25 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; -static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) +static int sh_mobile_i2c_hook_irqs(struct platform_device *dev) { struct resource *res; - int ret = -ENXIO; - int n, k = 0; + resource_size_t n; + int k = 0, ret; while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { - for (n = res->start; hook && n <= res->end; n++) { - if (request_irq(n, sh_mobile_i2c_isr, 0, - dev_name(&dev->dev), dev)) { - for (n--; n >= res->start; n--) - free_irq(n, dev); - - goto rollback; + for (n = res->start; n <= res->end; n++) { + ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), dev); + if (ret) { + dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + return ret; } } k++; } - if (hook) - return k > 0 ? 0 : -ENOENT; - - ret = 0; - - rollback: - k--; - - while (k >= 0) { - res = platform_get_resource(dev, IORESOURCE_IRQ, k); - for (n = res->start; n <= res->end; n++) - free_irq(n, dev); - - k--; - } - - return ret; + return k > 0 ? 0 : -ENOENT; } static int sh_mobile_i2c_probe(struct platform_device *dev) @@ -668,11 +651,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return PTR_ERR(pd->clk); } - ret = sh_mobile_i2c_hook_irqs(dev, 1); - if (ret) { - dev_err(&dev->dev, "cannot request IRQ\n"); + ret = sh_mobile_i2c_hook_irqs(dev); + if (ret) return ret; - } pd->dev = &dev->dev; platform_set_drvdata(dev, pd); @@ -680,10 +661,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) res = platform_get_resource(dev, IORESOURCE_MEM, 0); pd->reg = devm_ioremap_resource(&dev->dev, res); - if (IS_ERR(pd->reg)) { - ret = PTR_ERR(pd->reg); - goto err_irq; - } + if (IS_ERR(pd->reg)) + return PTR_ERR(pd->reg); /* Use platform data bus speed or STANDARD_MODE */ ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); @@ -735,7 +714,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(adap); if (ret < 0) { dev_err(&dev->dev, "cannot add numbered adapter\n"); - goto err_irq; + return ret; } dev_info(&dev->dev, @@ -743,10 +722,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) adap->nr, pd->bus_speed, pd->iccl, pd->icch); return 0; - - err_irq: - sh_mobile_i2c_hook_irqs(dev, 0); - return ret; } static int sh_mobile_i2c_remove(struct platform_device *dev) @@ -754,7 +729,6 @@ static int sh_mobile_i2c_remove(struct platform_device *dev) struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); i2c_del_adapter(&pd->adap); - sh_mobile_i2c_hook_irqs(dev, 0); pm_runtime_disable(&dev->dev); return 0; } -- cgit v1.2.3-70-g09d2 From ed4121e129ae46615ab570318b5b8f31494ced98 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:13 +0200 Subject: i2c: sh_mobile: remove superfluous offset parameter Following the KISS principle, remove unneeded stuff. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index ddc9970fd72..9a5b693454e 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -194,7 +194,7 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); } -static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int offset) +static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf) { /* * Conditional expression: @@ -206,10 +206,10 @@ static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int off * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return (((count_khz * (tLOW + tf)) + 5000) / 10000) + offset; + return (((count_khz * (tLOW + tf)) + 5000) / 10000); } -static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int offset) +static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf) { /* * Conditional expression: @@ -225,14 +225,13 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int of * to take into account the fall time of SDA signal (tf) at START * condition, in order to meet both tHIGH and tHD;STA specs. */ - return (((count_khz * (tHIGH + tf)) + 5000) / 10000) + offset; + return (((count_khz * (tHIGH + tf)) + 5000) / 10000); } static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk_khz; u32 tHIGH, tLOW, tf; - int offset; /* Get clock rate after clock is enabled */ clk_prepare_enable(pd->clk); @@ -243,26 +242,24 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) tLOW = 47; /* tLOW = 4.7 us */ tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */ tf = 3; /* tf = 0.3 us */ - offset = 0; /* No offset */ } else if (pd->bus_speed == FAST_MODE) { tLOW = 13; /* tLOW = 1.3 us */ tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */ tf = 3; /* tf = 0.3 us */ - offset = 0; /* No offset */ } else { dev_err(pd->dev, "unrecognized bus speed %lu Hz\n", pd->bus_speed); goto out; } - pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf, offset); + pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); /* one more bit of ICCL in ICIC */ if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) pd->icic |= ICIC_ICCLB8; else pd->icic &= ~ICIC_ICCLB8; - pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf, offset); + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); /* one more bit of ICCH in ICIC */ if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) pd->icic |= ICIC_ICCHB8; -- cgit v1.2.3-70-g09d2 From 6ed7053c2255c34886297b995c6a18607b36d668 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:14 +0200 Subject: i2c: sh_mobile: bail out on errors when initializing sh_mobile_i2c_init() could detect wrong settings, but didn't bail out, so it would continue unconfigured. Fix this. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 9a5b693454e..9f02013eaee 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -228,7 +228,7 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf) return (((count_khz * (tHIGH + tf)) + 5000) / 10000); } -static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk_khz; u32 tHIGH, tLOW, tf; @@ -236,6 +236,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) /* Get clock rate after clock is enabled */ clk_prepare_enable(pd->clk); i2c_clk_khz = clk_get_rate(pd->clk) / 1000; + clk_disable_unprepare(pd->clk); i2c_clk_khz /= pd->clks_per_count; if (pd->bus_speed == STANDARD_MODE) { @@ -249,7 +250,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) } else { dev_err(pd->dev, "unrecognized bus speed %lu Hz\n", pd->bus_speed); - goto out; + return -EINVAL; } pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); @@ -266,8 +267,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) else pd->icic &= ~ICIC_ICCHB8; -out: - clk_disable_unprepare(pd->clk); + return 0; } static void activate_ch(struct sh_mobile_i2c_data *pd) @@ -677,7 +677,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; - sh_mobile_i2c_init(pd); + ret = sh_mobile_i2c_init(pd); + if (ret) + return ret; /* Enable Runtime PM for this device. * -- cgit v1.2.3-70-g09d2 From 7663ebefca8079ef0fd2fff1047d3d10af654c78 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:15 +0200 Subject: i2c: sh_mobile: check timing parameters for valid range Due to misconfiguration, it can happen that the calculated timing parameters are out of range. Bail out if that happens. We can also simplify some logic later because of the verified value. Also, make the printouts of the values more precise by adding the hex-prefixes. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 9f02013eaee..b1d399e3e5f 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -232,6 +232,7 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk_khz; u32 tHIGH, tLOW, tf; + uint16_t max_val; /* Get clock rate after clock is enabled */ clk_prepare_enable(pd->clk); @@ -254,15 +255,23 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) } pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); + + max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; + if (pd->iccl > max_val || pd->icch > max_val) { + dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n", + pd->iccl, pd->icch); + return -EINVAL; + } + /* one more bit of ICCL in ICIC */ - if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + if (pd->iccl & 0x100) pd->icic |= ICIC_ICCLB8; else pd->icic &= ~ICIC_ICCLB8; - pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); /* one more bit of ICCH in ICIC */ - if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + if (pd->icch & 0x100) pd->icic |= ICIC_ICCHB8; else pd->icic &= ~ICIC_ICCHB8; @@ -717,7 +726,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) } dev_info(&dev->dev, - "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n", + "I2C adapter %d with bus speed %lu Hz (L/H=0x%x/0x%x)\n", adap->nr, pd->bus_speed, pd->iccl, pd->icch); return 0; -- cgit v1.2.3-70-g09d2 From 67240dfcb8dcf756cc00fb37f5cb7e3ee2fa6190 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 2 May 2014 21:15:16 +0200 Subject: i2c: sh_mobile: fix clock calculation for newer SoCs Newer SoCs have so fast input clocks that the ICCL/H registers only count every second clock to have a meaningful 9-bit range. The driver was already prepared for that happening, but didn't use it so far. Add the proper DT configuration for SoCs that need it. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 48 ++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index b1d399e3e5f..c29be2bba6e 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -32,6 +32,7 @@ #include #include #include +#include #include /* Transmit operation: */ @@ -139,6 +140,10 @@ struct sh_mobile_i2c_data { bool send_stop; }; +struct sh_mobile_dt_config { + int clks_per_count; +}; + #define IIC_FLAG_HAS_ICIC67 (1 << 0) #define STANDARD_MODE 100000 @@ -617,6 +622,22 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; +static const struct sh_mobile_dt_config default_dt_config = { + .clks_per_count = 1, +}; + +static const struct sh_mobile_dt_config rcar_gen2_dt_config = { + .clks_per_count = 2, +}; + +static const struct of_device_id sh_mobile_i2c_dt_ids[] = { + { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, + { .compatible = "renesas,iic-r8a7790", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7791", .data = &rcar_gen2_dt_config }, + {}, +}; +MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); + static int sh_mobile_i2c_hook_irqs(struct platform_device *dev) { struct resource *res; @@ -674,11 +695,24 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); pd->bus_speed = ret ? STANDARD_MODE : bus_speed; - if (pdata && pdata->bus_speed) - pd->bus_speed = pdata->bus_speed; pd->clks_per_count = 1; - if (pdata && pdata->clks_per_count) - pd->clks_per_count = pdata->clks_per_count; + + if (dev->dev.of_node) { + const struct of_device_id *match; + + match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev); + if (match) { + const struct sh_mobile_dt_config *config; + + config = match->data; + pd->clks_per_count = config->clks_per_count; + } + } else { + if (pdata && pdata->bus_speed) + pd->bus_speed = pdata->bus_speed; + if (pdata && pdata->clks_per_count) + pd->clks_per_count = pdata->clks_per_count; + } /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. @@ -758,12 +792,6 @@ static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = { .runtime_resume = sh_mobile_i2c_runtime_nop, }; -static const struct of_device_id sh_mobile_i2c_dt_ids[] = { - { .compatible = "renesas,rmobile-iic", }, - {}, -}; -MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); - static struct platform_driver sh_mobile_i2c_driver = { .driver = { .name = "i2c-sh_mobile", -- cgit v1.2.3-70-g09d2 From fa96faaa119b3f5f8c3936e290913258d2712ef3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 6 May 2014 10:05:21 +0200 Subject: i2c: eg20t: Fix Kconfig dependencies The i2c-eg20t driver is for a companion chip to the Intel Atom E600 series processors. These are 32-bit x86 processors so the driver is only needed on X86_32. Add COMPILE_TEST as an alternative, so that the driver can still be build-tested elsewhere. Signed-off-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c94db1c5e35..9c750efa69a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -449,7 +449,7 @@ config I2C_EFM32 config I2C_EG20T tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" - depends on PCI + depends on PCI && (X86_32 || COMPILE_TEST) help This driver is for PCH(Platform controller Hub) I2C of EG20T which is an IOH(Input/Output Hub) for x86 embedded processor. -- cgit v1.2.3-70-g09d2 From a0682a31588990cb6f870f1a48cf019525605625 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 17 Dec 2013 15:48:19 +0900 Subject: i2c: gpio: Use devm_gpio_request() Use devm_gpio_request() to make cleanup paths simpler. Signed-off-by: Jingoo Han Reviewed-by: Violeta Menendez Reviewed-by: Ian Molton Tested-by: Violeta Menendez Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-gpio.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 02d2d4abb9d..71a45b210a2 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -147,24 +147,22 @@ static int i2c_gpio_probe(struct platform_device *pdev) scl_pin = pdata->scl_pin; } - ret = gpio_request(sda_pin, "sda"); + ret = devm_gpio_request(&pdev->dev, sda_pin, "sda"); if (ret) { if (ret == -EINVAL) ret = -EPROBE_DEFER; /* Try again later */ - goto err_request_sda; + return ret; } - ret = gpio_request(scl_pin, "scl"); + ret = devm_gpio_request(&pdev->dev, scl_pin, "scl"); if (ret) { if (ret == -EINVAL) ret = -EPROBE_DEFER; /* Try again later */ - goto err_request_scl; + return ret; } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_add_bus; - } + if (!priv) + return -ENOMEM; adap = &priv->adap; bit_data = &priv->bit_data; pdata = &priv->pdata; @@ -225,7 +223,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); if (ret) - goto err_add_bus; + return ret; platform_set_drvdata(pdev, priv); @@ -235,13 +233,6 @@ static int i2c_gpio_probe(struct platform_device *pdev) ? ", no clock stretching" : ""); return 0; - -err_add_bus: - gpio_free(scl_pin); -err_request_scl: - gpio_free(sda_pin); -err_request_sda: - return ret; } static int i2c_gpio_remove(struct platform_device *pdev) @@ -255,8 +246,6 @@ static int i2c_gpio_remove(struct platform_device *pdev) pdata = &priv->pdata; i2c_del_adapter(adap); - gpio_free(pdata->scl_pin); - gpio_free(pdata->sda_pin); return 0; } -- cgit v1.2.3-70-g09d2 From 819a39510ed8e7f473309d071ede0fb02f0d0e79 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 27 May 2014 14:06:28 +0200 Subject: i2c: rcar: add compatibles for additional SoC Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-rcar.txt | 3 +++ drivers/i2c/busses/i2c-rcar.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index dd8b2dd1ede..16b3e07aa98 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -7,6 +7,9 @@ Required properties: "renesas,i2c-r8a7779" "renesas,i2c-r8a7790" "renesas,i2c-r8a7791" + "renesas,i2c-r8a7792" + "renesas,i2c-r8a7793" + "renesas,i2c-r8a7794" - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier. diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 06d47aafbb7..467eafa050a 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -646,6 +646,9 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7791", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); -- cgit v1.2.3-70-g09d2 From 90104d06372e41b2a844950f6648322b09f9b8b9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 27 May 2014 14:06:28 +0200 Subject: i2c: sh_mobile: add compatibles for additional SoC Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c29be2bba6e..8b5e79cb446 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -634,6 +634,9 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, { .compatible = "renesas,iic-r8a7790", .data = &rcar_gen2_dt_config }, { .compatible = "renesas,iic-r8a7791", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7792", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7793", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7794", .data = &rcar_gen2_dt_config }, {}, }; MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); -- cgit v1.2.3-70-g09d2 From 1c176d534f81c350f67dd4dc6d0330a45c11c9a6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:36 +0200 Subject: i2c: rcar: not everything needs to be a function Very basic operations, just called once, can also go to the caller. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 467eafa050a..de4e6b81fa9 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -312,18 +312,9 @@ scgd_find: return 0; } -static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv) -{ - rcar_i2c_write(priv, ICCCR, priv->icccr); -} - /* * status functions */ -static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv) -{ - return rcar_i2c_read(priv, ICMSR); -} #define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff) static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit) @@ -480,7 +471,7 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) /*-------------- spin lock -----------------*/ spin_lock(&priv->lock); - msr = rcar_i2c_status_get(priv); + msr = rcar_i2c_read(priv, ICMSR); /* * Arbitration lost @@ -554,7 +545,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, spin_lock_irqsave(&priv->lock, flags); rcar_i2c_init(priv); - rcar_i2c_clock_start(priv); + /* start clock */ + rcar_i2c_write(priv, ICCCR, priv->icccr); spin_unlock_irqrestore(&priv->lock, flags); /*-------------- spin unlock -----------------*/ -- cgit v1.2.3-70-g09d2 From 93e953d3785fa6fc7fda4b64bd38d003f1dcb1d2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:37 +0200 Subject: i2c: rcar: no need to store irq number We use devm, so irq number is only needed during probe. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index de4e6b81fa9..5a3e8a12e8d 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -116,7 +116,6 @@ struct rcar_i2c_priv { wait_queue_head_t wait; int pos; - int irq; u32 icccr; u32 flags; enum rcar_i2c_type devtype; @@ -653,7 +652,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) struct resource *res; struct device *dev = &pdev->dev; u32 bus_speed; - int ret; + int irq, ret; priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); if (!priv) { @@ -687,7 +686,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (IS_ERR(priv->io)) return PTR_ERR(priv->io); - priv->irq = platform_get_irq(pdev, 0); + irq = platform_get_irq(pdev, 0); init_waitqueue_head(&priv->wait); spin_lock_init(&priv->lock); @@ -701,10 +700,10 @@ static int rcar_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); - ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, + ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv); if (ret < 0) { - dev_err(dev, "cannot get irq %d\n", priv->irq); + dev_err(dev, "cannot get irq %d\n", irq); return ret; } -- cgit v1.2.3-70-g09d2 From 4f443a8a611d0cb3c40e95e0d90e9d7e4740eda6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:38 +0200 Subject: i2c: rcar: refactor bus state machine Remove the seperate functions and use designated constants. As readable but less overhead. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 5a3e8a12e8d..eadaca0ef4b 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -79,11 +79,9 @@ #define MATE (1 << 0) /* address sent irq en */ -enum { - RCAR_BUS_PHASE_ADDR, - RCAR_BUS_PHASE_DATA, - RCAR_BUS_PHASE_STOP, -}; +#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) +#define RCAR_BUS_PHASE_DATA (MDBS | MIE) +#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) enum { RCAR_IRQ_CLOSE, @@ -204,21 +202,6 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) return -EBUSY; } -static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase) -{ - switch (phase) { - case RCAR_BUS_PHASE_ADDR: - rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG); - break; - case RCAR_BUS_PHASE_DATA: - rcar_i2c_write(priv, ICMCR, MDBS | MIE); - break; - case RCAR_BUS_PHASE_STOP: - rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB); - break; - } -} - /* * clock function */ @@ -328,7 +311,7 @@ static int rcar_i2c_recv(struct rcar_i2c_priv *priv) { rcar_i2c_set_addr(priv, 1); rcar_i2c_status_clear(priv); - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV); return 0; @@ -347,7 +330,7 @@ static int rcar_i2c_send(struct rcar_i2c_priv *priv) rcar_i2c_set_addr(priv, 0); rcar_i2c_status_clear(priv); - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND); return 0; @@ -376,7 +359,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) * goto data phase. */ if (msr & MAT) - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); if (priv->pos < msg->len) { /* @@ -404,7 +387,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) * prepare stop condition here. * ID_DONE will be set on STOP irq. */ - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); else /* * If current msg is _NOT_ last msg, @@ -452,9 +435,9 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) * otherwise, go to DATA phase. */ if (priv->pos + 1 >= msg->len) - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); else - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); rcar_i2c_recv_restart(priv); @@ -502,7 +485,7 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) dev_dbg(dev, "Nack\n"); /* go to stop phase */ - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP); rcar_i2c_flags_set(priv, ID_NACK); goto out; -- cgit v1.2.3-70-g09d2 From f2382249b27d1589a1ae495a1df84d890982a3e1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:39 +0200 Subject: i2c: rcar: refactor irq state machine Remove the seperate functions and use designated constants. As readable but less overhead. Actually, this is even more readable since the old function used a mix of "=" and "|=". Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index eadaca0ef4b..f2cbb8a7d0b 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -83,12 +83,9 @@ #define RCAR_BUS_PHASE_DATA (MDBS | MIE) #define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) -enum { - RCAR_IRQ_CLOSE, - RCAR_IRQ_OPEN_FOR_SEND, - RCAR_IRQ_OPEN_FOR_RECV, - RCAR_IRQ_OPEN_FOR_STOP, -}; +#define RCAR_IRQ_SEND (MNRE | MALE | MSTE | MATE | MDEE) +#define RCAR_IRQ_RECV (MNRE | MALE | MSTE | MATE | MDRE) +#define RCAR_IRQ_STOP (MSTE) /* * flags @@ -158,28 +155,6 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, 0); } -static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open) -{ - u32 val = MNRE | MALE | MSTE | MATE; /* default */ - - switch (open) { - case RCAR_IRQ_OPEN_FOR_SEND: - val |= MDEE; /* default + send */ - break; - case RCAR_IRQ_OPEN_FOR_RECV: - val |= MDRE; /* default + read */ - break; - case RCAR_IRQ_OPEN_FOR_STOP: - val = MSTE; /* stop irq only */ - break; - case RCAR_IRQ_CLOSE: - default: - val = 0; /* all close */ - break; - } - rcar_i2c_write(priv, ICMIER, val); -} - static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv) { rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv); @@ -312,7 +287,7 @@ static int rcar_i2c_recv(struct rcar_i2c_priv *priv) rcar_i2c_set_addr(priv, 1); rcar_i2c_status_clear(priv); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV); + rcar_i2c_write(priv, ICMIER, RCAR_IRQ_RECV); return 0; } @@ -331,7 +306,7 @@ static int rcar_i2c_send(struct rcar_i2c_priv *priv) rcar_i2c_set_addr(priv, 0); rcar_i2c_status_clear(priv); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND); + rcar_i2c_write(priv, ICMIER, RCAR_IRQ_SEND); return 0; } @@ -486,7 +461,7 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) /* go to stop phase */ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); - rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP); + rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP); rcar_i2c_flags_set(priv, ID_NACK); goto out; } @@ -501,7 +476,7 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) out: if (rcar_i2c_flags_has(priv, ID_DONE)) { - rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE); + rcar_i2c_write(priv, ICMIER, 0); rcar_i2c_status_clear(priv); wake_up(&priv->wait); } -- cgit v1.2.3-70-g09d2 From 3f7de22eb28244fc79bc744d9f51d018da343962 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:40 +0200 Subject: i2c: rcar: check bus free before first message We should always check if the bus is free, independently if it is a read or write. It should be done before the first message, though. After that, we ourselves keep the bus busy. Remove a 'ret' assignment which only silenced a build warning. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index f2cbb8a7d0b..828b519146f 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -294,15 +294,6 @@ static int rcar_i2c_recv(struct rcar_i2c_priv *priv) static int rcar_i2c_send(struct rcar_i2c_priv *priv) { - int ret; - - /* - * It should check bus status when send case - */ - ret = rcar_i2c_bus_barrier(priv); - if (ret < 0) - return ret; - rcar_i2c_set_addr(priv, 0); rcar_i2c_status_clear(priv); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); @@ -508,7 +499,10 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, spin_unlock_irqrestore(&priv->lock, flags); /*-------------- spin unlock -----------------*/ - ret = -EINVAL; + ret = rcar_i2c_bus_barrier(priv); + if (ret < 0) + goto out; + for (i = 0; i < num; i++) { /* This HW can't send STOP after address phase */ if (msgs[i].len == 0) { @@ -569,7 +563,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ret = i + 1; /* The number of transfer */ } - +out: pm_runtime_put(dev); if (ret < 0 && ret != -ENXIO) -- cgit v1.2.3-70-g09d2 From 386babf8e2f7dd483f88e5c0c4c761346b750185 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:41 +0200 Subject: i2c: rcar: refactor setting up msg Setting up a read or write message is similar enough to be done in one function. Also, move a helper function into the new function since it is only used here. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 828b519146f..42005ccd325 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -155,11 +155,6 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, 0); } -static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv) -{ - rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv); -} - /* * bus control functions */ @@ -279,25 +274,14 @@ static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit) rcar_i2c_write(priv, ICMSR, ~bit); } -/* - * recv/send functions - */ -static int rcar_i2c_recv(struct rcar_i2c_priv *priv) +static int rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) { - rcar_i2c_set_addr(priv, 1); - rcar_i2c_status_clear(priv); - rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - rcar_i2c_write(priv, ICMIER, RCAR_IRQ_RECV); - - return 0; -} + int read = !!rcar_i2c_is_recv(priv); -static int rcar_i2c_send(struct rcar_i2c_priv *priv) -{ - rcar_i2c_set_addr(priv, 0); + rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); rcar_i2c_status_clear(priv); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - rcar_i2c_write(priv, ICMIER, RCAR_IRQ_SEND); + rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); return 0; } @@ -520,11 +504,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, if (priv->msg == &msgs[num - 1]) rcar_i2c_flags_set(priv, ID_LAST_MSG); - /* start send/recv */ - if (rcar_i2c_is_recv(priv)) - ret = rcar_i2c_recv(priv); - else - ret = rcar_i2c_send(priv); + ret = rcar_i2c_prepare_msg(priv); spin_unlock_irqrestore(&priv->lock, flags); /*-------------- spin unlock -----------------*/ -- cgit v1.2.3-70-g09d2 From 3c95de674496e08d3b373f85af4aa59c23ddb8d6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:42 +0200 Subject: i2c: rcar: refactor status bit handling The old macros made it harder to see what was actually happening. Replace them with something more readable. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 42005ccd325..07256a6b56f 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -87,6 +87,9 @@ #define RCAR_IRQ_RECV (MNRE | MALE | MSTE | MATE | MDRE) #define RCAR_IRQ_STOP (MSTE) +#define RCAR_IRQ_ACK_SEND (~(MAT | MDE)) +#define RCAR_IRQ_ACK_RECV (~(MAT | MDR)) + /* * flags */ @@ -268,27 +271,18 @@ scgd_find: * status functions */ -#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff) -static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit) -{ - rcar_i2c_write(priv, ICMSR, ~bit); -} - static int rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) { int read = !!rcar_i2c_is_recv(priv); rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); - rcar_i2c_status_clear(priv); + rcar_i2c_write(priv, ICMSR, 0); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); return 0; } -#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE)) -#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR)) - /* * interrupt functions */ @@ -348,7 +342,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) return ID_DONE; } - rcar_i2c_send_restart(priv); + rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND); return 0; } @@ -389,7 +383,7 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) else rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); - rcar_i2c_recv_restart(priv); + rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV); return 0; } @@ -452,7 +446,7 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) out: if (rcar_i2c_flags_has(priv, ID_DONE)) { rcar_i2c_write(priv, ICMIER, 0); - rcar_i2c_status_clear(priv); + rcar_i2c_write(priv, ICMSR, 0); wake_up(&priv->wait); } -- cgit v1.2.3-70-g09d2 From 150b8be3cda54412ad7b54f5392b513b25c0aaa7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:43 +0200 Subject: i2c: rcar: remove spinlock The i2c core has per-adapter locks, so no need to protect again. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 07256a6b56f..e16784124a4 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -36,7 +36,6 @@ #include #include #include -#include /* register offsets */ #define ICSCR 0x00 /* slave ctrl */ @@ -110,7 +109,6 @@ struct rcar_i2c_priv { struct i2c_msg *msg; struct clk *clk; - spinlock_t lock; wait_queue_head_t wait; int pos; @@ -394,9 +392,6 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) struct device *dev = rcar_i2c_priv_to_dev(priv); u32 msr; - /*-------------- spin lock -----------------*/ - spin_lock(&priv->lock); - msr = rcar_i2c_read(priv, ICMSR); /* @@ -450,9 +445,6 @@ out: wake_up(&priv->wait); } - spin_unlock(&priv->lock); - /*-------------- spin unlock -----------------*/ - return IRQ_HANDLED; } @@ -462,21 +454,14 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, { struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); struct device *dev = rcar_i2c_priv_to_dev(priv); - unsigned long flags; int i, ret, timeout; pm_runtime_get_sync(dev); - /*-------------- spin lock -----------------*/ - spin_lock_irqsave(&priv->lock, flags); - rcar_i2c_init(priv); /* start clock */ rcar_i2c_write(priv, ICCCR, priv->icccr); - spin_unlock_irqrestore(&priv->lock, flags); - /*-------------- spin unlock -----------------*/ - ret = rcar_i2c_bus_barrier(priv); if (ret < 0) goto out; @@ -488,9 +473,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, break; } - /*-------------- spin lock -----------------*/ - spin_lock_irqsave(&priv->lock, flags); - /* init each data */ priv->msg = &msgs[i]; priv->pos = 0; @@ -500,9 +482,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ret = rcar_i2c_prepare_msg(priv); - spin_unlock_irqrestore(&priv->lock, flags); - /*-------------- spin unlock -----------------*/ - if (ret < 0) break; @@ -614,7 +593,6 @@ static int rcar_i2c_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); init_waitqueue_head(&priv->wait); - spin_lock_init(&priv->lock); adap = &priv->adap; adap->nr = pdev->id; -- cgit v1.2.3-70-g09d2 From 3e3aabac443e25712a3788cf88cc188e13ca8b0e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:44 +0200 Subject: i2c: rcar: reuse status bits as enable bits Status register and enable register are identical regarding their layout. Use the bit definitions for both. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index e16784124a4..4c46d1b1b61 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -59,7 +59,7 @@ #define FSB (1 << 1) /* force stop bit */ #define ESG (1 << 0) /* en startbit gen */ -/* ICMSR */ +/* ICMSR (also for ICMIE) */ #define MNR (1 << 6) /* nack received */ #define MAL (1 << 5) /* arbitration lost */ #define MST (1 << 4) /* sent a stop */ @@ -68,23 +68,14 @@ #define MDR (1 << 1) #define MAT (1 << 0) /* slave addr xfer done */ -/* ICMIE */ -#define MNRE (1 << 6) /* nack irq en */ -#define MALE (1 << 5) /* arblos irq en */ -#define MSTE (1 << 4) /* stop irq en */ -#define MDEE (1 << 3) -#define MDTE (1 << 2) -#define MDRE (1 << 1) -#define MATE (1 << 0) /* address sent irq en */ - #define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) #define RCAR_BUS_PHASE_DATA (MDBS | MIE) #define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) -#define RCAR_IRQ_SEND (MNRE | MALE | MSTE | MATE | MDEE) -#define RCAR_IRQ_RECV (MNRE | MALE | MSTE | MATE | MDRE) -#define RCAR_IRQ_STOP (MSTE) +#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE) +#define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR) +#define RCAR_IRQ_STOP (MST) #define RCAR_IRQ_ACK_SEND (~(MAT | MDE)) #define RCAR_IRQ_ACK_RECV (~(MAT | MDR)) -- cgit v1.2.3-70-g09d2 From 51371cdc86403d9f643efe3d4a4febd11f084c74 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:45 +0200 Subject: i2c: rcar: janitorial cleanup after refactoring Remove some obvious comments, remove some superfluous debug output (the error code carries the same information), some white space fixing... Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 50 +++++-------------------------------------- 1 file changed, 5 insertions(+), 45 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 4c46d1b1b61..27b84d734a6 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -80,9 +80,6 @@ #define RCAR_IRQ_ACK_SEND (~(MAT | MDE)) #define RCAR_IRQ_ACK_RECV (~(MAT | MDR)) -/* - * flags - */ #define ID_LAST_MSG (1 << 0) #define ID_IOERROR (1 << 1) #define ID_DONE (1 << 2) @@ -105,7 +102,7 @@ struct rcar_i2c_priv { int pos; u32 icccr; u32 flags; - enum rcar_i2c_type devtype; + enum rcar_i2c_type devtype; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) @@ -116,9 +113,7 @@ struct rcar_i2c_priv { #define LOOP_TIMEOUT 1024 -/* - * basic functions - */ + static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val) { writel(val, priv->io + reg); @@ -147,9 +142,6 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, 0); } -/* - * bus control functions - */ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { int i; @@ -164,9 +156,6 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) return -EBUSY; } -/* - * clock function - */ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, u32 bus_speed, struct device *dev) @@ -256,10 +245,6 @@ scgd_find: return 0; } -/* - * status functions - */ - static int rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) { int read = !!rcar_i2c_is_recv(priv); @@ -380,40 +365,24 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) static irqreturn_t rcar_i2c_irq(int irq, void *ptr) { struct rcar_i2c_priv *priv = ptr; - struct device *dev = rcar_i2c_priv_to_dev(priv); u32 msr; msr = rcar_i2c_read(priv, ICMSR); - /* - * Arbitration lost - */ + /* Arbitration lost */ if (msr & MAL) { - /* - * CAUTION - * - * When arbitration lost, device become _slave_ mode. - */ - dev_dbg(dev, "Arbitration Lost\n"); rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); goto out; } - /* - * Stop - */ + /* Stop */ if (msr & MST) { - dev_dbg(dev, "Stop\n"); rcar_i2c_flags_set(priv, ID_DONE); goto out; } - /* - * Nack - */ + /* Nack */ if (msr & MNR) { - dev_dbg(dev, "Nack\n"); - /* go to stop phase */ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP); @@ -421,9 +390,6 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) goto out; } - /* - * recv/send - */ if (rcar_i2c_is_recv(priv)) rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); else @@ -476,9 +442,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, if (ret < 0) break; - /* - * wait result - */ timeout = wait_event_timeout(priv->wait, rcar_i2c_flags_has(priv, ID_DONE), 5 * HZ); @@ -487,9 +450,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, break; } - /* - * error handling - */ if (rcar_i2c_flags_has(priv, ID_NACK)) { ret = -ENXIO; break; -- cgit v1.2.3-70-g09d2 From 3d99beabf17506b9d48461d1677a61a430000ad7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 28 May 2014 09:44:46 +0200 Subject: i2c: rcar: update copyright and license information Make clear that the driver is GPL v2 only. Remove FSF address. Remove filename in comment. Update copyright information. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 27b84d734a6..71e88d05550 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1,7 +1,9 @@ /* - * drivers/i2c/busses/i2c-rcar.c + * Driver for the Renesas RCar I2C unit * - * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2014 Wolfram Sang + * + * Copyright (C) 2012-14 Renesas Solutions Corp. * Kuninori Morimoto * * This file is based on the drivers/i2c/busses/i2c-sh7760.c @@ -12,16 +14,12 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License + * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include @@ -608,6 +606,6 @@ static struct platform_driver rcar_i2c_driver = { module_platform_driver(rcar_i2c_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Renesas R-Car I2C bus driver"); MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v1.2.3-70-g09d2 From 054b62d9f25c903958749e4cea25261324a7a2a4 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 30 Apr 2014 14:24:58 +0800 Subject: i2c: imx: fix the i2c bus hang issue when do repeat restart Test i2c device Maxim max44009, datasheet is located at: http://www.maximintegrated.com/datasheet/index.mvp/id/7175 The max44009 support repeat operation like: read -> repeat restart -> read/write The current i2c imx host controller driver don't support this operation that causes i2c bus hang due to "MTX" is cleared in .i2c_imx_read(). If "read" is the last message there have no problem, so the current driver supports all SMbus operation like: write -> repeat restart -> read/write IMX i2c controller for master receiver has some limitation: - If it is the last byte for one operation, it must generate STOP signal before read I2DR to prevent controller from generating another clock cycle. - If it is the last byte in the read, and then do repeat restart, it must set "MTX" before read I2DR to prevent controller from generating another extra clock cycle. The patch is to fix the issue. Signed-off-by: Fugang Duan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 886217f1ba6..5f4bc700825 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -458,7 +458,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) return 0; } -static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) +static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { int i, result; unsigned int temp; @@ -515,15 +515,30 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) msgs->len += len; } if (i == (msgs->len - 1)) { - /* It must generate STOP before read I2DR to prevent - controller from generating another clock cycle */ - dev_dbg(&i2c_imx->adapter.dev, - "<%s> clear MSTA\n", __func__); - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp &= ~(I2CR_MSTA | I2CR_MTX); - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - i2c_imx_bus_busy(i2c_imx, 0); - i2c_imx->stopped = 1; + if (is_lastmsg) { + /* + * It must generate STOP before read I2DR to prevent + * controller from generating another clock cycle + */ + dev_dbg(&i2c_imx->adapter.dev, + "<%s> clear MSTA\n", __func__); + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~(I2CR_MSTA | I2CR_MTX); + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + i2c_imx_bus_busy(i2c_imx, 0); + i2c_imx->stopped = 1; + } else { + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = readb(i2c_imx->base + IMX_I2C_I2CR); + temp |= I2CR_MTX; + writeb(temp, i2c_imx->base + IMX_I2C_I2CR); + } } else if (i == (msgs->len - 2)) { dev_dbg(&i2c_imx->adapter.dev, "<%s> set TXAK\n", __func__); @@ -547,6 +562,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, { unsigned int i, temp; int result; + bool is_lastmsg = false; struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); @@ -558,6 +574,9 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, /* read/write data */ for (i = 0; i < num; i++) { + if (i == num - 1) + is_lastmsg = true; + if (i) { dev_dbg(&i2c_imx->adapter.dev, "<%s> repeated start\n", __func__); @@ -588,7 +607,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, (temp & I2SR_RXAK ? 1 : 0)); #endif if (msgs[i].flags & I2C_M_RD) - result = i2c_imx_read(i2c_imx, &msgs[i]); + result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); else result = i2c_imx_write(i2c_imx, &msgs[i]); if (result) -- cgit v1.2.3-70-g09d2 From 9b2a6da33ccb1bc0d68f4319cef7c7299727ac4d Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 20 May 2014 10:21:45 +0800 Subject: i2c: imx: update i2c clock divider for each transaction Since IMX serial SOCs support low bus freq mode, some clocks freq may change to save power. I2C needs to check the clock source and update the divider. For example: i.MX6SL I2C clk is from IPG_PERCLK which is sourced from IPG_CLK. Under normal operation, IPG_CLK is 66MHz, ipg_perclk is at 22MHz. In low bus freq mode, IPG_CLK is at 12MHz and IPG_PERCLK is down to 4MHz. So the I2C driver must update the divider register for each transaction when the current IPG_PERCLK is not equal to the clock of previous transaction. Signed-off-by: Fugang Duan [wsa: removed an outdated comment and simplified debug output] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 93 +++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 44 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 5f4bc700825..fe53207a6eb 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -183,6 +183,8 @@ struct imx_i2c_struct { unsigned int disable_delay; int stopped; unsigned int ifdr; /* IMX_I2C_IFDR */ + unsigned int cur_clk; + unsigned int bitrate; const struct imx_i2c_hwdata *hwdata; }; @@ -305,6 +307,48 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) return 0; } +static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) +{ + struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; + unsigned int i2c_clk_rate; + unsigned int div; + int i; + + /* Divider value calculation */ + i2c_clk_rate = clk_get_rate(i2c_imx->clk); + if (i2c_imx->cur_clk == i2c_clk_rate) + return; + else + i2c_imx->cur_clk = i2c_clk_rate; + + div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate; + if (div < i2c_clk_div[0].div) + i = 0; + else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) + i = i2c_imx->hwdata->ndivs - 1; + else + for (i = 0; i2c_clk_div[i].div < div; i++); + + /* Store divider value */ + i2c_imx->ifdr = i2c_clk_div[i].val; + + /* + * There dummy delay is calculated. + * It should be about one I2C clock period long. + * This delay is used in I2C bus disable function + * to fix chip hardware bug. + */ + i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div + + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); + +#ifdef CONFIG_I2C_DEBUG_BUS + dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n", + i2c_clk_rate, div); + dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n", + i2c_clk_div[i].val, i2c_clk_div[i].div); +#endif +} + static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) { unsigned int temp = 0; @@ -312,6 +356,8 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + i2c_imx_set_clk(i2c_imx); + result = clk_prepare_enable(i2c_imx->clk); if (result) return result; @@ -367,45 +413,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) clk_disable_unprepare(i2c_imx->clk); } -static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, - unsigned int rate) -{ - struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; - unsigned int i2c_clk_rate; - unsigned int div; - int i; - - /* Divider value calculation */ - i2c_clk_rate = clk_get_rate(i2c_imx->clk); - div = (i2c_clk_rate + rate - 1) / rate; - if (div < i2c_clk_div[0].div) - i = 0; - else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) - i = i2c_imx->hwdata->ndivs - 1; - else - for (i = 0; i2c_clk_div[i].div < div; i++); - - /* Store divider value */ - i2c_imx->ifdr = i2c_clk_div[i].val; - - /* - * There dummy delay is calculated. - * It should be about one I2C clock period long. - * This delay is used in I2C bus disable function - * to fix chip hardware bug. - */ - i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div - + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); - - /* dev_dbg() can't be used, because adapter is not yet registered */ -#ifdef CONFIG_I2C_DEBUG_BUS - dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n", - __func__, i2c_clk_rate, div); - dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n", - __func__, i2c_clk_div[i].val, i2c_clk_div[i].div); -#endif -} - static irqreturn_t i2c_imx_isr(int irq, void *dev_id) { struct imx_i2c_struct *i2c_imx = dev_id; @@ -644,7 +651,6 @@ static int i2c_imx_probe(struct platform_device *pdev) struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; int irq, ret; - u32 bitrate; dev_dbg(&pdev->dev, "<%s>\n", __func__); @@ -708,12 +714,11 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); /* Set up clock divider */ - bitrate = IMX_I2C_BIT_RATE; + i2c_imx->bitrate = IMX_I2C_BIT_RATE; ret = of_property_read_u32(pdev->dev.of_node, - "clock-frequency", &bitrate); + "clock-frequency", &i2c_imx->bitrate); if (ret < 0 && pdata && pdata->bitrate) - bitrate = pdata->bitrate; - i2c_imx_set_clk(i2c_imx, bitrate); + i2c_imx->bitrate = pdata->bitrate; /* Set up chip registers to defaults */ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, -- cgit v1.2.3-70-g09d2 From 7da62cb1853025a579a8942fc4d7c9dee6afb73e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 1 Jun 2014 22:35:25 +0200 Subject: i2c: nuc900: remove driver Arnd said in another patch: "As far as I can tell, this driver must have produced this error for as long as it has been merged into the mainline kernel, but it was never part of the normal build tests: drivers/i2c/busses/i2c-nuc900.c: In function 'nuc900_i2c_probe': drivers/i2c/busses/i2c-nuc900.c:601:17: error: request for member 'apbfreq' in something not a structure or union ret = (i2c->clk.apbfreq)/(pdata->bus_freq * 5) - 1; ^ This is an attempt to get the driver to build and possibly work correctly, although I do wonder whether we should just remove it, as it has clearly never worked." I agree with removing it since nobody showed interest in Arnd's fixup patch. Reported-by: Arnd Bergmann Signed-off-by: Wolfram Sang Cc: Wan ZongShun Acked-by: Arnd Bergmann --- drivers/i2c/busses/Kconfig | 7 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-nuc900.c | 709 ---------------------------------------- 3 files changed, 717 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-nuc900.c (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9c750efa69a..7ccc51e85ba 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -570,13 +570,6 @@ config I2C_NOMADIK I2C interface from ST-Ericsson's Nomadik and Ux500 architectures, as well as the STA2X11 PCIe I/O HUB. -config I2C_NUC900 - tristate "NUC900 I2C Driver" - depends on ARCH_W90X900 - help - Say Y here to include support for I2C controller in the - Winbond/Nuvoton NUC900 based System-on-Chip devices. - config I2C_OCORES tristate "OpenCores I2C Controller" help diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 18d18ff9db9..413d062a08f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o -obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c deleted file mode 100644 index 36394d737fa..00000000000 --- a/drivers/i2c/busses/i2c-nuc900.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * linux/drivers/i2c/busses/i2c-nuc900.c - * - * Copyright (c) 2010 Nuvoton technology corporation. - * - * This driver based on S3C2410 I2C driver of Ben Dooks . - * Written by Wan ZongShun - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation;version 2 of the License. - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* nuc900 i2c registers offset */ - -#define CSR 0x00 -#define DIVIDER 0x04 -#define CMDR 0x08 -#define SWR 0x0C -#define RXR 0x10 -#define TXR 0x14 - -/* nuc900 i2c CSR register bits */ - -#define IRQEN 0x003 -#define I2CBUSY 0x400 -#define I2CSTART 0x018 -#define IRQFLAG 0x004 -#define ARBIT_LOST 0x200 -#define SLAVE_ACK 0x800 - -/* nuc900 i2c CMDR register bits */ - -#define I2C_CMD_START 0x10 -#define I2C_CMD_STOP 0x08 -#define I2C_CMD_READ 0x04 -#define I2C_CMD_WRITE 0x02 -#define I2C_CMD_NACK 0x01 - -/* i2c controller state */ - -enum nuc900_i2c_state { - STATE_IDLE, - STATE_START, - STATE_READ, - STATE_WRITE, - STATE_STOP -}; - -/* i2c controller private data */ - -struct nuc900_i2c { - spinlock_t lock; - wait_queue_head_t wait; - - struct i2c_msg *msg; - unsigned int msg_num; - unsigned int msg_idx; - unsigned int msg_ptr; - unsigned int irq; - - enum nuc900_i2c_state state; - - void __iomem *regs; - struct clk *clk; - struct device *dev; - struct resource *ioarea; - struct i2c_adapter adap; -}; - -/* nuc900_i2c_master_complete - * - * complete the message and wake up the caller, using the given return code, - * or zero to mean ok. -*/ - -static inline void nuc900_i2c_master_complete(struct nuc900_i2c *i2c, int ret) -{ - dev_dbg(i2c->dev, "master_complete %d\n", ret); - - i2c->msg_ptr = 0; - i2c->msg = NULL; - i2c->msg_idx++; - i2c->msg_num = 0; - if (ret) - i2c->msg_idx = ret; - - wake_up(&i2c->wait); -} - -/* irq enable/disable functions */ - -static inline void nuc900_i2c_disable_irq(struct nuc900_i2c *i2c) -{ - unsigned long tmp; - - tmp = readl(i2c->regs + CSR); - writel(tmp & ~IRQEN, i2c->regs + CSR); -} - -static inline void nuc900_i2c_enable_irq(struct nuc900_i2c *i2c) -{ - unsigned long tmp; - - tmp = readl(i2c->regs + CSR); - writel(tmp | IRQEN, i2c->regs + CSR); -} - - -/* nuc900_i2c_message_start - * - * put the start of a message onto the bus -*/ - -static void nuc900_i2c_message_start(struct nuc900_i2c *i2c, - struct i2c_msg *msg) -{ - unsigned int addr = (msg->addr & 0x7f) << 1; - - if (msg->flags & I2C_M_RD) - addr |= 0x1; - writel(addr & 0xff, i2c->regs + TXR); - writel(I2C_CMD_START | I2C_CMD_WRITE, i2c->regs + CMDR); -} - -static inline void nuc900_i2c_stop(struct nuc900_i2c *i2c, int ret) -{ - - dev_dbg(i2c->dev, "STOP\n"); - - /* stop the transfer */ - i2c->state = STATE_STOP; - writel(I2C_CMD_STOP, i2c->regs + CMDR); - - nuc900_i2c_master_complete(i2c, ret); - nuc900_i2c_disable_irq(i2c); -} - -/* helper functions to determine the current state in the set of - * messages we are sending -*/ - -/* is_lastmsg() - * - * returns TRUE if the current message is the last in the set -*/ - -static inline int is_lastmsg(struct nuc900_i2c *i2c) -{ - return i2c->msg_idx >= (i2c->msg_num - 1); -} - -/* is_msglast - * - * returns TRUE if we this is the last byte in the current message -*/ - -static inline int is_msglast(struct nuc900_i2c *i2c) -{ - return i2c->msg_ptr == i2c->msg->len-1; -} - -/* is_msgend - * - * returns TRUE if we reached the end of the current message -*/ - -static inline int is_msgend(struct nuc900_i2c *i2c) -{ - return i2c->msg_ptr >= i2c->msg->len; -} - -/* i2c_nuc900_irq_nextbyte - * - * process an interrupt and work out what to do - */ - -static void i2c_nuc900_irq_nextbyte(struct nuc900_i2c *i2c, - unsigned long iicstat) -{ - unsigned char byte; - - switch (i2c->state) { - - case STATE_IDLE: - dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__); - break; - - case STATE_STOP: - dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__); - nuc900_i2c_disable_irq(i2c); - break; - - case STATE_START: - /* last thing we did was send a start condition on the - * bus, or started a new i2c message - */ - - if (iicstat & SLAVE_ACK && - !(i2c->msg->flags & I2C_M_IGNORE_NAK)) { - /* ack was not received... */ - - dev_dbg(i2c->dev, "ack was not received\n"); - nuc900_i2c_stop(i2c, -ENXIO); - break; - } - - if (i2c->msg->flags & I2C_M_RD) - i2c->state = STATE_READ; - else - i2c->state = STATE_WRITE; - - /* terminate the transfer if there is nothing to do - * as this is used by the i2c probe to find devices. - */ - - if (is_lastmsg(i2c) && i2c->msg->len == 0) { - nuc900_i2c_stop(i2c, 0); - break; - } - - if (i2c->state == STATE_READ) - goto prepare_read; - - /* fall through to the write state, as we will need to - * send a byte as well - */ - - case STATE_WRITE: - /* we are writing data to the device... check for the - * end of the message, and if so, work out what to do - */ - - if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) { - if (iicstat & SLAVE_ACK) { - dev_dbg(i2c->dev, "WRITE: No Ack\n"); - - nuc900_i2c_stop(i2c, -ECONNREFUSED); - break; - } - } - -retry_write: - - if (!is_msgend(i2c)) { - byte = i2c->msg->buf[i2c->msg_ptr++]; - writeb(byte, i2c->regs + TXR); - writel(I2C_CMD_WRITE, i2c->regs + CMDR); - - } else if (!is_lastmsg(i2c)) { - /* we need to go to the next i2c message */ - - dev_dbg(i2c->dev, "WRITE: Next Message\n"); - - i2c->msg_ptr = 0; - i2c->msg_idx++; - i2c->msg++; - - /* check to see if we need to do another message */ - if (i2c->msg->flags & I2C_M_NOSTART) { - - if (i2c->msg->flags & I2C_M_RD) { - /* cannot do this, the controller - * forces us to send a new START - * when we change direction - */ - - nuc900_i2c_stop(i2c, -EINVAL); - } - - goto retry_write; - } else { - /* send the new start */ - nuc900_i2c_message_start(i2c, i2c->msg); - i2c->state = STATE_START; - } - - } else { - /* send stop */ - - nuc900_i2c_stop(i2c, 0); - } - break; - - case STATE_READ: - /* we have a byte of data in the data register, do - * something with it, and then work out whether we are - * going to do any more read/write - */ - - byte = readb(i2c->regs + RXR); - i2c->msg->buf[i2c->msg_ptr++] = byte; - -prepare_read: - if (is_msglast(i2c)) { - /* last byte of buffer */ - - if (is_lastmsg(i2c)) - writel(I2C_CMD_READ | I2C_CMD_NACK, - i2c->regs + CMDR); - - } else if (is_msgend(i2c)) { - /* ok, we've read the entire buffer, see if there - * is anything else we need to do - */ - - if (is_lastmsg(i2c)) { - /* last message, send stop and complete */ - dev_dbg(i2c->dev, "READ: Send Stop\n"); - - nuc900_i2c_stop(i2c, 0); - } else { - /* go to the next transfer */ - dev_dbg(i2c->dev, "READ: Next Transfer\n"); - - i2c->msg_ptr = 0; - i2c->msg_idx++; - i2c->msg++; - - writel(I2C_CMD_READ, i2c->regs + CMDR); - } - - } else { - writel(I2C_CMD_READ, i2c->regs + CMDR); - } - - break; - } -} - -/* nuc900_i2c_irq - * - * top level IRQ servicing routine -*/ - -static irqreturn_t nuc900_i2c_irq(int irqno, void *dev_id) -{ - struct nuc900_i2c *i2c = dev_id; - unsigned long status; - - status = readl(i2c->regs + CSR); - writel(status | IRQFLAG, i2c->regs + CSR); - - if (status & ARBIT_LOST) { - /* deal with arbitration loss */ - dev_err(i2c->dev, "deal with arbitration loss\n"); - goto out; - } - - if (i2c->state == STATE_IDLE) { - dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n"); - goto out; - } - - /* pretty much this leaves us with the fact that we've - * transmitted or received whatever byte we last sent - */ - - i2c_nuc900_irq_nextbyte(i2c, status); - - out: - return IRQ_HANDLED; -} - - -/* nuc900_i2c_set_master - * - * get the i2c bus for a master transaction -*/ - -static int nuc900_i2c_set_master(struct nuc900_i2c *i2c) -{ - int timeout = 400; - - while (timeout-- > 0) { - if (((readl(i2c->regs + SWR) & I2CSTART) == I2CSTART) && - ((readl(i2c->regs + CSR) & I2CBUSY) == 0)) { - return 0; - } - - msleep(1); - } - - return -ETIMEDOUT; -} - -/* nuc900_i2c_doxfer - * - * this starts an i2c transfer -*/ - -static int nuc900_i2c_doxfer(struct nuc900_i2c *i2c, - struct i2c_msg *msgs, int num) -{ - unsigned long iicstat, timeout; - int spins = 20; - int ret; - - ret = nuc900_i2c_set_master(i2c); - if (ret != 0) { - dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); - ret = -EAGAIN; - goto out; - } - - spin_lock_irq(&i2c->lock); - - i2c->msg = msgs; - i2c->msg_num = num; - i2c->msg_ptr = 0; - i2c->msg_idx = 0; - i2c->state = STATE_START; - - nuc900_i2c_message_start(i2c, msgs); - spin_unlock_irq(&i2c->lock); - - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); - - ret = i2c->msg_idx; - - /* having these next two as dev_err() makes life very - * noisy when doing an i2cdetect - */ - - if (timeout == 0) - dev_dbg(i2c->dev, "timeout\n"); - else if (ret != num) - dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); - - /* ensure the stop has been through the bus */ - - dev_dbg(i2c->dev, "waiting for bus idle\n"); - - /* first, try busy waiting briefly */ - do { - iicstat = readl(i2c->regs + CSR); - } while ((iicstat & I2CBUSY) && --spins); - - /* if that timed out sleep */ - if (!spins) { - msleep(1); - iicstat = readl(i2c->regs + CSR); - } - - if (iicstat & I2CBUSY) - dev_warn(i2c->dev, "timeout waiting for bus idle\n"); - - out: - return ret; -} - -/* nuc900_i2c_xfer - * - * first port of call from the i2c bus code when an message needs - * transferring across the i2c bus. -*/ - -static int nuc900_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct nuc900_i2c *i2c = (struct nuc900_i2c *)adap->algo_data; - int retry; - int ret; - - nuc900_i2c_enable_irq(i2c); - - for (retry = 0; retry < adap->retries; retry++) { - - ret = nuc900_i2c_doxfer(i2c, msgs, num); - - if (ret != -EAGAIN) - return ret; - - dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); - - udelay(100); - } - - return -EREMOTEIO; -} - -/* declare our i2c functionality */ -static u32 nuc900_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | - I2C_FUNC_PROTOCOL_MANGLING; -} - -/* i2c bus registration info */ - -static const struct i2c_algorithm nuc900_i2c_algorithm = { - .master_xfer = nuc900_i2c_xfer, - .functionality = nuc900_i2c_func, -}; - -/* nuc900_i2c_probe - * - * called by the bus driver when a suitable device is found -*/ - -static int nuc900_i2c_probe(struct platform_device *pdev) -{ - struct nuc900_i2c *i2c; - struct nuc900_platform_i2c *pdata; - struct resource *res; - int ret; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } - - i2c = kzalloc(sizeof(struct nuc900_i2c), GFP_KERNEL); - if (!i2c) { - dev_err(&pdev->dev, "no memory for state\n"); - return -ENOMEM; - } - - strlcpy(i2c->adap.name, "nuc900-i2c0", sizeof(i2c->adap.name)); - i2c->adap.owner = THIS_MODULE; - i2c->adap.algo = &nuc900_i2c_algorithm; - i2c->adap.retries = 2; - i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - - spin_lock_init(&i2c->lock); - init_waitqueue_head(&i2c->wait); - - /* find the clock and enable it */ - - i2c->dev = &pdev->dev; - i2c->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&pdev->dev, "cannot get clock\n"); - ret = -ENOENT; - goto err_noclk; - } - - dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); - - clk_enable(i2c->clk); - - /* map the registers */ - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "cannot find IO resource\n"); - ret = -ENOENT; - goto err_clk; - } - - i2c->ioarea = request_mem_region(res->start, resource_size(res), - pdev->name); - - if (i2c->ioarea == NULL) { - dev_err(&pdev->dev, "cannot request IO\n"); - ret = -ENXIO; - goto err_clk; - } - - i2c->regs = ioremap(res->start, resource_size(res)); - - if (i2c->regs == NULL) { - dev_err(&pdev->dev, "cannot map IO\n"); - ret = -ENXIO; - goto err_ioarea; - } - - dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", - i2c->regs, i2c->ioarea, res); - - /* setup info block for the i2c core */ - - i2c->adap.algo_data = i2c; - i2c->adap.dev.parent = &pdev->dev; - - mfp_set_groupg(&pdev->dev, NULL); - - clk_get_rate(i2c->clk); - - ret = (i2c->clk.apbfreq)/(pdata->bus_freq * 5) - 1; - writel(ret & 0xffff, i2c->regs + DIVIDER); - - /* find the IRQ for this unit (note, this relies on the init call to - * ensure no current IRQs pending - */ - - i2c->irq = ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_err(&pdev->dev, "cannot find IRQ\n"); - goto err_iomap; - } - - ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED, - dev_name(&pdev->dev), i2c); - - if (ret != 0) { - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_iomap; - } - - /* Note, previous versions of the driver used i2c_add_adapter() - * to add the bus at any number. We now pass the bus number via - * the platform data, so if unset it will now default to always - * being bus 0. - */ - - i2c->adap.nr = pdata->bus_num; - - ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto err_irq; - } - - platform_set_drvdata(pdev, i2c); - - dev_info(&pdev->dev, "%s: NUC900 I2C adapter\n", - dev_name(&i2c->adap.dev)); - return 0; - - err_irq: - free_irq(i2c->irq, i2c); - - err_iomap: - iounmap(i2c->regs); - - err_ioarea: - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - - err_clk: - clk_disable(i2c->clk); - clk_put(i2c->clk); - - err_noclk: - kfree(i2c); - return ret; -} - -/* nuc900_i2c_remove - * - * called when device is removed from the bus -*/ - -static int nuc900_i2c_remove(struct platform_device *pdev) -{ - struct nuc900_i2c *i2c = platform_get_drvdata(pdev); - - i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq, i2c); - - clk_disable(i2c->clk); - clk_put(i2c->clk); - - iounmap(i2c->regs); - - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - kfree(i2c); - - return 0; -} - -static struct platform_driver nuc900_i2c_driver = { - .probe = nuc900_i2c_probe, - .remove = nuc900_i2c_remove, - .driver = { - .owner = THIS_MODULE, - .name = "nuc900-i2c0", - }, -}; - -static int __init i2c_adap_nuc900_init(void) -{ - return platform_driver_register(&nuc900_i2c_driver); -} - -static void __exit i2c_adap_nuc900_exit(void) -{ - platform_driver_unregister(&nuc900_i2c_driver); -} -subsys_initcall(i2c_adap_nuc900_init); -module_exit(i2c_adap_nuc900_exit); - -MODULE_DESCRIPTION("NUC900 I2C Bus driver"); -MODULE_AUTHOR("Wan ZongShun, "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-i2c0"); -- cgit v1.2.3-70-g09d2 From f537295a58ddc4460b9857c6e4a6959685447f3b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 15 May 2014 17:37:22 +0300 Subject: i2c: designware: Disable device on system suspend Userspace can initiate system suspend on arbitrary times which means that device drivers must make sure that their device gets quiesced before system suspend is entered. Therefore disable the I2C host controller in the driver system suspend hook. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 9c780261434..f72102f389c 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -253,6 +253,7 @@ static int dw_i2c_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); + i2c_dw_disable(i_dev); clk_disable_unprepare(i_dev->clk); return 0; -- cgit v1.2.3-70-g09d2 From 1fc2fe204cb9d8010e70716aa48b5c3db6379da3 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 15 May 2014 17:37:23 +0300 Subject: i2c: designware: Add runtime PM hooks It is possible that after entering runtime PM suspend the controller context is lost due the fact that its power is removed. This happens for example on Asus T100, an Intel Baytrail based tablet/laptop. In order to get the controller back to functional state, we need to implement runtime PM hooks which will re-initialize the hardware during runtime PM resume. We can re-use the existing system suspend hooks as the steps to resume/suspend the controller are the same. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index f72102f389c..402ec3970fe 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -247,7 +247,7 @@ static const struct of_device_id dw_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, dw_i2c_of_match); #endif -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM static int dw_i2c_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -269,13 +269,11 @@ static int dw_i2c_resume(struct device *dev) return 0; } - -static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume); -#define DW_I2C_DEV_PM_OPS (&dw_i2c_dev_pm_ops) -#else -#define DW_I2C_DEV_PM_OPS NULL #endif +static UNIVERSAL_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, + dw_i2c_resume, NULL); + /* work with hotplug and coldplug */ MODULE_ALIAS("platform:i2c_designware"); @@ -287,7 +285,7 @@ static struct platform_driver dw_i2c_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(dw_i2c_of_match), .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), - .pm = DW_I2C_DEV_PM_OPS, + .pm = &dw_i2c_dev_pm_ops, }, }; -- cgit v1.2.3-70-g09d2 From 157a801e5042c7da5323c7d77bd818c7d845af14 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 15 May 2014 17:37:24 +0300 Subject: i2c: designware-pci: Add Haswell PCI IDs Intel Haswell has the same I2C host controller than Baytrail and it can also be enumerated as a PCI device. Add the PCI IDs to the driver list. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 85056c22d21..3356f7ab9f7 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -56,6 +56,7 @@ enum dw_pci_ctl_id_t { medfield_5, baytrail, + haswell, }; struct dw_scl_sda_cfg { @@ -95,6 +96,15 @@ static struct dw_scl_sda_cfg byt_config = { .sda_hold = 0x6, }; +/* Haswell HCNT/LCNT/SDA hold time */ +static struct dw_scl_sda_cfg hsw_config = { + .ss_hcnt = 0x01b0, + .fs_hcnt = 0x48, + .ss_lcnt = 0x01fb, + .fs_lcnt = 0xa0, + .sda_hold = 0x9, +}; + static struct dw_pci_controller dw_pci_controllers[] = { [moorestown_0] = { .bus_num = 0, @@ -168,6 +178,15 @@ static struct dw_pci_controller dw_pci_controllers[] = { .functionality = I2C_FUNC_10BIT_ADDR, .scl_sda_cfg = &byt_config, }, + [haswell] = { + .bus_num = -1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, + .tx_fifo_depth = 32, + .rx_fifo_depth = 32, + .clk_khz = 100000, + .functionality = I2C_FUNC_10BIT_ADDR, + .scl_sda_cfg = &hsw_config, + }, }; static struct i2c_algorithm i2c_dw_algo = { .master_xfer = i2c_dw_xfer, @@ -328,6 +347,9 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0F45), baytrail }, { PCI_VDEVICE(INTEL, 0x0F46), baytrail }, { PCI_VDEVICE(INTEL, 0x0F47), baytrail }, + /* Haswell */ + { PCI_VDEVICE(INTEL, 0x9c61), haswell }, + { PCI_VDEVICE(INTEL, 0x9c62), haswell }, { 0,} }; MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); -- cgit v1.2.3-70-g09d2 From 46797a2adbf0cdc3be17707dc64e872eeed86a8a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 13 May 2014 10:51:58 +0900 Subject: i2c: remove unnecessary OOM messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. For example, k.alloc and v.alloc failures use dump_stack(). Signed-off-by: Jingoo Han Acked-by: Guenter Roeck Reviewed-by: Jean Delvare Acked-by: Uwe Kleine-König Acked-by: Felipe Balbi Acked-by: Laurent Pinchart Acked-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 4 +--- drivers/i2c/busses/i2c-diolan-u2c.c | 1 - drivers/i2c/busses/i2c-efm32.c | 4 +--- drivers/i2c/busses/i2c-eg20t.c | 4 +--- drivers/i2c/busses/i2c-exynos5.c | 4 +--- drivers/i2c/busses/i2c-imx.c | 4 +--- drivers/i2c/busses/i2c-omap.c | 4 +--- drivers/i2c/busses/i2c-rcar.c | 4 +--- drivers/i2c/busses/i2c-s3c2410.c | 8 ++------ drivers/i2c/busses/i2c-simtec.c | 4 +--- drivers/i2c/busses/i2c-sirf.c | 1 - drivers/i2c/busses/i2c-stu300.c | 4 +--- drivers/i2c/busses/i2c-tegra.c | 4 +--- drivers/i2c/busses/i2c-wmt.c | 4 +--- drivers/i2c/busses/scx200_acb.c | 4 +--- 15 files changed, 14 insertions(+), 44 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index c60719577fc..214ff9700ef 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -225,10 +225,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - dev_err(&pdev->dev, "Cannot allocate i2c_dev\n"); + if (!i2c_dev) return -ENOMEM; - } platform_set_drvdata(pdev, i2c_dev); i2c_dev->dev = &pdev->dev; init_completion(&i2c_dev->completion); diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index 721f7ebf9a3..b19a310bf9b 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -455,7 +455,6 @@ static int diolan_u2c_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - dev_err(&interface->dev, "no memory for device state\n"); ret = -ENOMEM; goto error; } diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index 777ed409a24..f7eccd682de 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -320,10 +320,8 @@ static int efm32_i2c_probe(struct platform_device *pdev) return -EINVAL; ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) { - dev_dbg(&pdev->dev, "failed to allocate private data\n"); + if (!ddata) return -ENOMEM; - } platform_set_drvdata(pdev, ddata); init_completion(&ddata->done); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index ff775ac29e4..a44ea13d143 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -751,10 +751,8 @@ static int pch_i2c_probe(struct pci_dev *pdev, pch_pci_dbg(pdev, "Entered.\n"); adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL); - if (adap_info == NULL) { - pch_pci_err(pdev, "Memory allocation FAILED\n"); + if (adap_info == NULL) return -ENOMEM; - } ret = pci_enable_device(pdev); if (ret) { diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index ba1faf0ef96..63d22920285 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -662,10 +662,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev) int ret; i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); - if (!i2c) { - dev_err(&pdev->dev, "no memory for state\n"); + if (!i2c) return -ENOMEM; - } if (of_property_read_u32(np, "clock-frequency", &op_clock)) { i2c->speed_mode = HSI2C_FAST_SPD; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index fe53207a6eb..aa8bc146718 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -667,10 +667,8 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct), GFP_KERNEL); - if (!i2c_imx) { - dev_err(&pdev->dev, "can't allocate interface\n"); + if (!i2c_imx) return -ENOMEM; - } if (of_id) i2c_imx->hwdata = of_id->data; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 85f8eac9ba1..b182793a405 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1114,10 +1114,8 @@ omap_i2c_probe(struct platform_device *pdev) } dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Menory allocation failed\n"); + if (!dev) return -ENOMEM; - } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 71e88d05550..89940592367 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -509,10 +509,8 @@ static int rcar_i2c_probe(struct platform_device *pdev) int irq, ret; priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); - if (!priv) { - dev_err(dev, "no mem for private data\n"); + if (!priv) return -ENOMEM; - } priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index bb3a9964f7e..e828a1dba0e 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1114,16 +1114,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) } i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL); - if (!i2c) { - dev_err(&pdev->dev, "no memory for state\n"); + if (!i2c) return -ENOMEM; - } i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!i2c->pdata) { - dev_err(&pdev->dev, "no memory for platform data\n"); + if (!i2c->pdata) return -ENOMEM; - } i2c->quirks = s3c24xx_get_device_quirks(pdev); if (pdata) diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 294c80f21d6..964e5c6f84a 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -77,10 +77,8 @@ static int simtec_i2c_probe(struct platform_device *dev) int ret; pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL); - if (pd == NULL) { - dev_err(&dev->dev, "cannot allocate private data\n"); + if (pd == NULL) return -ENOMEM; - } platform_set_drvdata(dev, pd); diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 8e3be7ed058..a3216defc1d 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -307,7 +307,6 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL); if (!siic) { - dev_err(&pdev->dev, "Can't allocate driver data\n"); err = -ENOMEM; goto out; } diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 29b1fb77894..fefb1c19ec1 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -868,10 +868,8 @@ static int stu300_probe(struct platform_device *pdev) int ret = 0; dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "could not allocate device struct\n"); + if (!dev) return -ENOMEM; - } bus_nr = pdev->id; dev->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 00f04cb5b4e..f1bb2fc0679 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -732,10 +732,8 @@ static int tegra_i2c_probe(struct platform_device *pdev) } i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev"); + if (!i2c_dev) return -ENOMEM; - } i2c_dev->base = base; i2c_dev->div_clk = div_clk; diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 2c8a3e4f900..889a212b6c3 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -379,10 +379,8 @@ static int wmt_i2c_probe(struct platform_device *pdev) u32 clk_rate; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - dev_err(&pdev->dev, "device memory allocation failed\n"); + if (!i2c_dev) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index cb66f9586f7..ff3f5747e43 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -431,10 +431,8 @@ static struct scx200_acb_iface *scx200_create_iface(const char *text, struct i2c_adapter *adapter; iface = kzalloc(sizeof(*iface), GFP_KERNEL); - if (!iface) { - pr_err("can't allocate memory\n"); + if (!iface) return NULL; - } adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); -- cgit v1.2.3-70-g09d2 From eae45e5dd229d5c6f0aed9789a5d1e84f7ea6100 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 15 May 2014 15:46:11 +0900 Subject: i2c: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Acked-by: Peter Korsgaard Acked-by: Maxime Coquelin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 2 +- drivers/i2c/busses/i2c-pxa.c | 2 +- drivers/i2c/busses/i2c-riic.c | 2 +- drivers/i2c/busses/i2c-st.c | 2 +- drivers/i2c/busses/i2c-wmt.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1f6369f14fb..0e10cc6182f 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -250,7 +250,7 @@ static struct i2c_adapter ocores_adapter = { .algo = &ocores_algorithm, }; -static struct of_device_id ocores_i2c_match[] = { +static const struct of_device_id ocores_i2c_match[] = { { .compatible = "opencores,i2c-ocores", .data = (void *)TYPE_OCORES, diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index bbe6dfbc5c0..be671f7a0e0 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1084,7 +1084,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -static struct of_device_id i2c_pxa_dt_ids[] = { +static const struct of_device_id i2c_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX }, diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 9e1f8bacfb3..af3b3d032a9 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -404,7 +404,7 @@ static int riic_i2c_remove(struct platform_device *pdev) return 0; } -static struct of_device_id riic_i2c_dt_ids[] = { +static const struct of_device_id riic_i2c_dt_ids[] = { { .compatible = "renesas,riic-rz" }, { /* Sentinel */ }, }; diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 872016196ef..95b94767038 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -847,7 +847,7 @@ static int st_i2c_remove(struct platform_device *pdev) return 0; } -static struct of_device_id st_i2c_match[] = { +static const struct of_device_id st_i2c_match[] = { { .compatible = "st,comms-ssc-i2c", }, { .compatible = "st,comms-ssc4-i2c", }, {}, diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 889a212b6c3..f80a38c2072 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -452,7 +452,7 @@ static int wmt_i2c_remove(struct platform_device *pdev) return 0; } -static struct of_device_id wmt_i2c_dt_ids[] = { +static const struct of_device_id wmt_i2c_dt_ids[] = { { .compatible = "wm,wm8505-i2c" }, { /* Sentinel */ }, }; -- cgit v1.2.3-70-g09d2 From 9d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 30 Apr 2014 10:44:09 -0700 Subject: i2c: ChromeOS EC tunnel driver On ARM Chromebooks we have a few devices that are accessed by both the AP (the main "Application Processor") and the EC (the Embedded Controller). These are: * The battery (sbs-battery). * The power management unit tps65090. On the original Samsung ARM Chromebook these devices were on an I2C bus that was shared between the AP and the EC and arbitrated using some extranal GPIOs (see i2c-arb-gpio-challenge). The original arbitration scheme worked well enough but had some downsides: * It was nonstandard (not using standard I2C multimaster) * It only worked if the EC-AP communication was I2C * It was relatively hard to debug problems (hard to tell if i2c issues were caused by the EC, the AP, or some device on the bus). On the HP Chromebook 11 the design was changed to: * The AP/EC comms were still i2c, but the battery/tps65090 were no longer on the bus used for AP/EC communication. The battery was exposed to the AP through a limited i2c tunnel and tps65090 was exposed to the AP through a custom Linux driver. On the Samsung ARM Chromebook 2 the scheme is changed yet again, now: * The AP/EC comms are now using SPI for faster speeds. * The EC's i2c bus is exposed to the AP through a full i2c tunnel. The upstream "tegra124-venice2" uses the same scheme as the Samsung ARM Chromebook 2, though it has a different set of components on the other side of the bus. This driver supports the scheme used by the Samsung ARM Chromebook 2. Future patches to this driver could add support for the battery tunnel on the HP Chromebook 11 (and perhaps could even be used to access tps65090 on the HP Chromebook 11 instead of using a special driver, but I haven't researched that enough). Signed-off-by: Vincent Palatin Signed-off-by: Simon Glass Signed-off-by: Doug Anderson Reviewed-by: Wolfram Sang Signed-off-by: Lee Jones --- .../devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt | 39 +++ drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-cros-ec-tunnel.c | 318 +++++++++++++++++++++ drivers/mfd/cros_ec.c | 5 + 5 files changed, 372 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt create mode 100644 drivers/i2c/busses/i2c-cros-ec-tunnel.c (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt b/Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt new file mode 100644 index 00000000000..898f030eba6 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt @@ -0,0 +1,39 @@ +I2C bus that tunnels through the ChromeOS EC (cros-ec) +====================================================== +On some ChromeOS board designs we've got a connection to the EC (embedded +controller) but no direct connection to some devices on the other side of +the EC (like a battery and PMIC). To get access to those devices we need +to tunnel our i2c commands through the EC. + +The node for this device should be under a cros-ec node like google,cros-ec-spi +or google,cros-ec-i2c. + + +Required properties: +- compatible: google,cros-ec-i2c-tunnel +- google,remote-bus: The EC bus we'd like to talk to. + +Optional child nodes: +- One node per I2C device connected to the tunnelled I2C bus. + + +Example: + cros-ec@0 { + compatible = "google,cros-ec-spi"; + + ... + + i2c-tunnel { + compatible = "google,cros-ec-i2c-tunnel"; + #address-cells = <1>; + #size-cells = <0>; + + google,remote-bus = <0>; + + battery: sbs-battery@b { + compatible = "sbs,sbs-battery"; + reg = <0xb>; + sbs,poll-retry-count = <1>; + }; + }; + } diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c94db1c5e35..9a0a6cc7f4b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -993,6 +993,15 @@ config I2C_SIBYTE help Supports the SiByte SOC on-chip I2C interfaces (2 channels). +config I2C_CROS_EC_TUNNEL + tristate "ChromeOS EC tunnel I2C bus" + depends on MFD_CROS_EC + help + If you say yes here you get an I2C bus that will tunnel i2c commands + through to the other side of the ChromeOS EC to the i2c bus + connected there. This will work whatever the interface used to + talk to the EC (SPI, I2C or LPC). + config SCx200_I2C tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)" depends on SCx200_GPIO diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 18d18ff9db9..e110ca93291 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o # Other I2C/SMBus bus drivers obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o +obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c new file mode 100644 index 00000000000..8e7a71487bb --- /dev/null +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2013 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Expose an I2C passthrough to the ChromeOS EC. + */ + +#include +#include +#include +#include +#include +#include + +/** + * struct ec_i2c_device - Driver data for I2C tunnel + * + * @dev: Device node + * @adap: I2C adapter + * @ec: Pointer to EC device + * @remote_bus: The EC bus number we tunnel to on the other side. + * @request_buf: Buffer for transmitting data; we expect most transfers to fit. + * @response_buf: Buffer for receiving data; we expect most transfers to fit. + */ + +struct ec_i2c_device { + struct device *dev; + struct i2c_adapter adap; + struct cros_ec_device *ec; + + u16 remote_bus; + + u8 request_buf[256]; + u8 response_buf[256]; +}; + +/** + * ec_i2c_count_message - Count bytes needed for ec_i2c_construct_message + * + * @i2c_msgs: The i2c messages to read + * @num: The number of i2c messages. + * + * Returns the number of bytes the messages will take up. + */ +static int ec_i2c_count_message(const struct i2c_msg i2c_msgs[], int num) +{ + int i; + int size; + + size = sizeof(struct ec_params_i2c_passthru); + size += num * sizeof(struct ec_params_i2c_passthru_msg); + for (i = 0; i < num; i++) + if (!(i2c_msgs[i].flags & I2C_M_RD)) + size += i2c_msgs[i].len; + + return size; +} + +/** + * ec_i2c_construct_message - construct a message to go to the EC + * + * This function effectively stuffs the standard i2c_msg format of Linux into + * a format that the EC understands. + * + * @buf: The buffer to fill. We assume that the buffer is big enough. + * @i2c_msgs: The i2c messages to read. + * @num: The number of i2c messages. + * @bus_num: The remote bus number we want to talk to. + * + * Returns 0 or a negative error number. + */ +static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[], + int num, u16 bus_num) +{ + struct ec_params_i2c_passthru *params; + u8 *out_data; + int i; + + out_data = buf + sizeof(struct ec_params_i2c_passthru) + + num * sizeof(struct ec_params_i2c_passthru_msg); + + params = (struct ec_params_i2c_passthru *)buf; + params->port = bus_num; + params->num_msgs = num; + for (i = 0; i < num; i++) { + const struct i2c_msg *i2c_msg = &i2c_msgs[i]; + struct ec_params_i2c_passthru_msg *msg = ¶ms->msg[i]; + + msg->len = i2c_msg->len; + msg->addr_flags = i2c_msg->addr; + + if (i2c_msg->flags & I2C_M_TEN) + msg->addr_flags |= EC_I2C_FLAG_10BIT; + + if (i2c_msg->flags & I2C_M_RD) { + msg->addr_flags |= EC_I2C_FLAG_READ; + } else { + memcpy(out_data, i2c_msg->buf, msg->len); + out_data += msg->len; + } + } + + return 0; +} + +/** + * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response + * + * @i2c_msgs: The i2c messages to to fill up. + * @num: The number of i2c messages expected. + * + * Returns the number of response bytes expeced. + */ +static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num) +{ + int size; + int i; + + size = sizeof(struct ec_response_i2c_passthru); + for (i = 0; i < num; i++) + if (i2c_msgs[i].flags & I2C_M_RD) + size += i2c_msgs[i].len; + + return size; +} + +/** + * ec_i2c_parse_response - Parse a response from the EC + * + * We'll take the EC's response and copy it back into msgs. + * + * @buf: The buffer to parse. + * @i2c_msgs: The i2c messages to to fill up. + * @num: The number of i2c messages; will be modified to include the actual + * number received. + * + * Returns 0 or a negative error number. + */ +static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[], + int *num) +{ + const struct ec_response_i2c_passthru *resp; + const u8 *in_data; + int i; + + in_data = buf + sizeof(struct ec_response_i2c_passthru); + + resp = (const struct ec_response_i2c_passthru *)buf; + if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT) + return -ETIMEDOUT; + else if (resp->i2c_status & EC_I2C_STATUS_ERROR) + return -EREMOTEIO; + + /* Other side could send us back fewer messages, but not more */ + if (resp->num_msgs > *num) + return -EPROTO; + *num = resp->num_msgs; + + for (i = 0; i < *num; i++) { + struct i2c_msg *i2c_msg = &i2c_msgs[i]; + + if (i2c_msgs[i].flags & I2C_M_RD) { + memcpy(i2c_msg->buf, in_data, i2c_msg->len); + in_data += i2c_msg->len; + } + } + + return 0; +} + +static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], + int num) +{ + struct ec_i2c_device *bus = adap->algo_data; + struct device *dev = bus->dev; + const u16 bus_num = bus->remote_bus; + int request_len; + int response_len; + u8 *request = NULL; + u8 *response = NULL; + int result; + + request_len = ec_i2c_count_message(i2c_msgs, num); + if (request_len < 0) { + dev_warn(dev, "Error constructing message %d\n", request_len); + result = request_len; + goto exit; + } + response_len = ec_i2c_count_response(i2c_msgs, num); + if (response_len < 0) { + /* Unexpected; no errors should come when NULL response */ + dev_warn(dev, "Error preparing response %d\n", response_len); + result = response_len; + goto exit; + } + + if (request_len <= ARRAY_SIZE(bus->request_buf)) { + request = bus->request_buf; + } else { + request = kzalloc(request_len, GFP_KERNEL); + if (request == NULL) { + result = -ENOMEM; + goto exit; + } + } + if (response_len <= ARRAY_SIZE(bus->response_buf)) { + response = bus->response_buf; + } else { + response = kzalloc(response_len, GFP_KERNEL); + if (response == NULL) { + result = -ENOMEM; + goto exit; + } + } + + ec_i2c_construct_message(request, i2c_msgs, num, bus_num); + result = bus->ec->command_sendrecv(bus->ec, EC_CMD_I2C_PASSTHRU, + request, request_len, + response, response_len); + if (result) + goto exit; + + result = ec_i2c_parse_response(response, i2c_msgs, &num); + if (result < 0) + goto exit; + + /* Indicate success by saying how many messages were sent */ + result = num; +exit: + if (request != bus->request_buf) + kfree(request); + if (response != bus->response_buf) + kfree(response); + + return result; +} + +static u32 ec_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ec_i2c_algorithm = { + .master_xfer = ec_i2c_xfer, + .functionality = ec_i2c_functionality, +}; + +static int ec_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct ec_i2c_device *bus = NULL; + u32 remote_bus; + int err; + + if (!ec->command_sendrecv) { + dev_err(dev, "Missing sendrecv\n"); + return -EINVAL; + } + + bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); + if (bus == NULL) + return -ENOMEM; + + err = of_property_read_u32(np, "google,remote-bus", &remote_bus); + if (err) { + dev_err(dev, "Couldn't read remote-bus property\n"); + return err; + } + bus->remote_bus = remote_bus; + + bus->ec = ec; + bus->dev = dev; + + bus->adap.owner = THIS_MODULE; + strlcpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name)); + bus->adap.algo = &ec_i2c_algorithm; + bus->adap.algo_data = bus; + bus->adap.dev.parent = &pdev->dev; + bus->adap.dev.of_node = np; + + err = i2c_add_adapter(&bus->adap); + if (err) { + dev_err(dev, "cannot register i2c adapter\n"); + return err; + } + platform_set_drvdata(pdev, bus); + + return err; +} + +static int ec_i2c_remove(struct platform_device *dev) +{ + struct ec_i2c_device *bus = platform_get_drvdata(dev); + + i2c_del_adapter(&bus->adap); + + return 0; +} + +static struct platform_driver ec_i2c_tunnel_driver = { + .probe = ec_i2c_probe, + .remove = ec_i2c_remove, + .driver = { + .name = "cros-ec-i2c-tunnel", + }, +}; + +module_platform_driver(ec_i2c_tunnel_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EC I2C tunnel driver"); +MODULE_ALIAS("platform:cros-ec-i2c-tunnel"); diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 8b6fb34c9b3..38fe9bf0d16 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -90,6 +90,11 @@ static const struct mfd_cell cros_devs[] = { .id = 1, .of_compatible = "google,cros-ec-keyb", }, + { + .name = "cros-ec-i2c-tunnel", + .id = 2, + .of_compatible = "google,cros-ec-i2c-tunnel", + }, }; int cros_ec_register(struct cros_ec_device *ec_dev) -- cgit v1.2.3-70-g09d2 From 0709dc9711ae6d0559818c31b533a441564dad9b Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 3 Jun 2014 13:02:06 +0800 Subject: i2c: bfin: turn to Resource-managed API in probe function No need to free managed resources any more. Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 44 +++++++++++---------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index e6d5162b637..3e271e7558d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -620,35 +620,27 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) int rc; unsigned int clkhilow; - iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL); + iface = devm_kzalloc(&pdev->dev, sizeof(struct bfin_twi_iface), + GFP_KERNEL); if (!iface) { dev_err(&pdev->dev, "Cannot allocate memory\n"); - rc = -ENOMEM; - goto out_error_nomem; + return -ENOMEM; } spin_lock_init(&(iface->lock)); /* Find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - rc = -ENOENT; - goto out_error_get_res; - } - - iface->regs_base = ioremap(res->start, resource_size(res)); - if (iface->regs_base == NULL) { + iface->regs_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(iface->regs_base)) { dev_err(&pdev->dev, "Cannot map IO\n"); - rc = -ENXIO; - goto out_error_ioremap; + return PTR_ERR(iface->regs_base); } iface->irq = platform_get_irq(pdev, 0); if (iface->irq < 0) { dev_err(&pdev->dev, "No IRQ specified\n"); - rc = -ENOENT; - goto out_error_no_irq; + return -ENOENT; } p_adap = &iface->adap; @@ -666,15 +658,15 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) "i2c-bfin-twi"); if (rc) { dev_err(&pdev->dev, "Can't setup pin mux!\n"); - goto out_error_pin_mux; + return -EBUSY; } - rc = request_irq(iface->irq, bfin_twi_interrupt_entry, + rc = devm_request_irq(&pdev->dev, iface->irq, bfin_twi_interrupt_entry, 0, pdev->name, iface); if (rc) { dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); rc = -ENODEV; - goto out_error_req_irq; + goto out_error; } /* Set TWI internal clock as 10MHz */ @@ -695,7 +687,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) { dev_err(&pdev->dev, "Can't add i2c adapter!\n"); - goto out_error_add_adapter; + goto out_error; } platform_set_drvdata(pdev, iface); @@ -705,17 +697,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) return 0; -out_error_add_adapter: - free_irq(iface->irq, iface); -out_error_req_irq: -out_error_no_irq: +out_error: peripheral_free_list(dev_get_platdata(&pdev->dev)); -out_error_pin_mux: - iounmap(iface->regs_base); -out_error_ioremap: -out_error_get_res: - kfree(iface); -out_error_nomem: return rc; } @@ -724,10 +707,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev) struct bfin_twi_iface *iface = platform_get_drvdata(pdev); i2c_del_adapter(&(iface->adap)); - free_irq(iface->irq, iface); peripheral_free_list(dev_get_platdata(&pdev->dev)); - iounmap(iface->regs_base); - kfree(iface); return 0; } -- cgit v1.2.3-70-g09d2 From d49019a0696b0a234d304a7b3e1e545e850f4691 Mon Sep 17 00:00:00 2001 From: Valentin Longchamp Date: Tue, 3 Jun 2014 11:00:32 +0200 Subject: i2c: mpc: insert DR read in i2c_fixup() The mpc_i2c_fixup function is called when the bus is not released by a slave. The function generates 9 pulses that should lead the slave to release the bus. The sequence that generates the pulses disables/enables the I2C module that controls the blocked bus. We have found out on the P2041 SoC that this could cause the CPU to hang (for a short delay). To avoid this, this patch introduces a read to the I2CDR register between the re-enablement of the I2C module in master mode and its returning to the slave mode instead of the delay (the final delay, between the pulses is kept), as proposed in procedure from the P2041 reference manual (16.6.2.3), and the other manuals from the mpc83xx and mpc85xx families. Signed-off-by: Rainer Boschung Signed-off-by: Valentin Longchamp Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index f5391633b53..6a32aa095f8 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -115,7 +115,7 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c) for (k = 9; k; k--) { writeccr(i2c, 0); writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN); - udelay(delay_val); + readb(i2c->base + MPC_I2C_DR); writeccr(i2c, CCR_MEN); udelay(delay_val << 1); } -- cgit v1.2.3-70-g09d2 From 4807e8459bce425973c6c6a4f3bb2bb9b7aa0a36 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 3 Jun 2014 13:15:26 +0200 Subject: i2c: mux: pca954x: Use the descriptor-based GPIO API The ID-based GPIO API pushes handling of GPIO polarity to drivers. Simplify the driver by switching to the descriptor-based GPIO API. This also fixes a mismatch between the pca954x DT bindings that document a "reset-gpios" property and the driver that requests a "reset-gpio" property. Signed-off-by: Laurent Pinchart Reviewed-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 550bd36aa5d..c2c443f6640 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -186,7 +186,7 @@ static int pca954x_probe(struct i2c_client *client, { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct gpio_desc *gpio; int num, force, class; struct pca954x *data; int ret; @@ -200,21 +200,10 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - if (IS_ENABLED(CONFIG_OF) && np) { - enum of_gpio_flags flags; - int gpio; - - /* Get the mux out of reset if a reset GPIO is specified. */ - gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); - if (gpio_is_valid(gpio)) { - ret = devm_gpio_request_one(&client->dev, gpio, - flags & OF_GPIO_ACTIVE_LOW ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, - "pca954x reset"); - if (ret < 0) - return ret; - } - } + /* Get the mux out of reset if a reset GPIO is specified. */ + gpio = devm_gpiod_get(&client->dev, "reset"); + if (!IS_ERR(gpio)) + gpiod_direction_output(gpio, 0); /* Write the mux register at addr to verify * that the mux is in fact present. This also -- cgit v1.2.3-70-g09d2 From 642653d16a0f8e78b7a25d930b62aa771ebc939c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Jun 2014 18:56:32 +0200 Subject: i2c: pca954x: Fix compilation without CONFIG_GPIOLIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pca954x driver recently switched to the GPIO descriptor API without including the correct header. This breaks compilation without CONFIG_GPIOLIB. drivers/i2c/muxes/i2c-mux-pca954x.c: In function ‘pca954x_probe’: drivers/i2c/muxes/i2c-mux-pca954x.c:204:2: error: implicit declaration of function ‘devm_gpiod_get’ [-Werror=implicit-function-declaration] gpio = devm_gpiod_get(&client->dev, "reset"); ^ drivers/i2c/muxes/i2c-mux-pca954x.c:204:7: warning: assignment makes pointer from integer without a cast [enabled by default] gpio = devm_gpiod_get(&client->dev, "reset"); ^ drivers/i2c/muxes/i2c-mux-pca954x.c:206:3: error: implicit declaration of function ‘gpiod_direction_output’ [-Werror=implicit-function-declaration] gpiod_direction_output(gpio, 0); ^ cc1: some warnings being treated as errors make[3]: *** [drivers/i2c/muxes/i2c-mux-pca954x.o] Error 1 Fix it by including the right header. Reported-by: Jim Davis Signed-off-by: Laurent Pinchart Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index c2c443f6640..9bd4212782a 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -36,12 +36,11 @@ */ #include -#include +#include #include #include #include #include -#include #include #define PCA954X_MAX_NCHANS 8 -- cgit v1.2.3-70-g09d2 From c41aa3ce938b684d853f1004072b6116a41bb1ce Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Wed, 11 Jun 2014 22:34:37 +0200 Subject: i2c: rk3x: add driver for Rockchip RK3xxx SoC I2C adapter Driver for the native I2C adapter found in Rockchip RK3xxx SoCs. Configuration is only possible through devicetree. The driver is interrupt driven and supports the I2C_M_IGNORE_NAK mangling bit. Signed-off-by: Max Schwarz Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 42 ++ drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-rk3x.c | 762 +++++++++++++++++++++ 4 files changed, 815 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt create mode 100644 drivers/i2c/busses/i2c-rk3x.c (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt new file mode 100644 index 00000000000..dde6c22ce91 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt @@ -0,0 +1,42 @@ +* Rockchip RK3xxx I2C controller + +This driver interfaces with the native I2C controller present in Rockchip +RK3xxx SoCs. + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c" or + "rockchip,rk3288-i2c". + - interrupts : interrupt number + - clocks : parent clock + +Required on RK3066, RK3188 : + + - rockchip,grf : the phandle of the syscon node for the general register + file (GRF) + - on those SoCs an alias with the correct I2C bus ID (bit offset in the GRF) + is also required. + +Optional properties : + + - clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used. + +Example: + +aliases { + i2c0 = &i2c0; +} + +i2c0: i2c@2002d000 { + compatible = "rockchip,rk3188-i2c"; + reg = <0x2002d000 0x1000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clock-names = "i2c"; + clocks = <&cru PCLK_I2C0>; +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 620d1004a1e..759ee30dc63 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -676,6 +676,16 @@ config I2C_RIIC This driver can also be built as a module. If so, the module will be called i2c-riic. +config I2C_RK3X + tristate "Rockchip RK3xxx I2C adapter" + depends on OF + help + Say Y here to include support for the I2C adapter in Rockchip RK3xxx + SoCs. + + This driver can also be built as a module. If so, the module will + be called i2c-rk3x. + config HAVE_S3C2410_I2C bool help diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 298692cc600..8ac83374cf7 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o +obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c new file mode 100644 index 00000000000..9e3084c5e34 --- /dev/null +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -0,0 +1,762 @@ +/* + * Driver for I2C adapter in Rockchip RK3xxx SoC + * + * Max Schwarz + * based on the patches by Rockchip Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Register Map */ +#define REG_CON 0x00 /* control register */ +#define REG_CLKDIV 0x04 /* clock divisor register */ +#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */ +#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */ +#define REG_MTXCNT 0x10 /* number of bytes to be transmitted */ +#define REG_MRXCNT 0x14 /* number of bytes to be received */ +#define REG_IEN 0x18 /* interrupt enable */ +#define REG_IPD 0x1c /* interrupt pending */ +#define REG_FCNT 0x20 /* finished count */ + +/* Data buffer offsets */ +#define TXBUFFER_BASE 0x100 +#define RXBUFFER_BASE 0x200 + +/* REG_CON bits */ +#define REG_CON_EN BIT(0) +enum { + REG_CON_MOD_TX = 0, /* transmit data */ + REG_CON_MOD_REGISTER_TX, /* select register and restart */ + REG_CON_MOD_RX, /* receive data */ + REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes + * register addr */ +}; +#define REG_CON_MOD(mod) ((mod) << 1) +#define REG_CON_MOD_MASK (BIT(1) | BIT(2)) +#define REG_CON_START BIT(3) +#define REG_CON_STOP BIT(4) +#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ +#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ + +/* REG_MRXADDR bits */ +#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ + +/* REG_IEN/REG_IPD bits */ +#define REG_INT_BTF BIT(0) /* a byte was transmitted */ +#define REG_INT_BRF BIT(1) /* a byte was received */ +#define REG_INT_MBTF BIT(2) /* master data transmit finished */ +#define REG_INT_MBRF BIT(3) /* master data receive finished */ +#define REG_INT_START BIT(4) /* START condition generated */ +#define REG_INT_STOP BIT(5) /* STOP condition generated */ +#define REG_INT_NAKRCV BIT(6) /* NACK received */ +#define REG_INT_ALL 0x7f + +/* Constants */ +#define WAIT_TIMEOUT 200 /* ms */ +#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ + +enum rk3x_i2c_state { + STATE_IDLE, + STATE_START, + STATE_READ, + STATE_WRITE, + STATE_STOP +}; + +/** + * @grf_offset: offset inside the grf regmap for setting the i2c type + */ +struct rk3x_i2c_soc_data { + int grf_offset; +}; + +struct rk3x_i2c { + struct i2c_adapter adap; + struct device *dev; + struct rk3x_i2c_soc_data *soc_data; + + /* Hardware resources */ + void __iomem *regs; + struct clk *clk; + + /* Settings */ + unsigned int scl_frequency; + + /* Synchronization & notification */ + spinlock_t lock; + wait_queue_head_t wait; + bool busy; + + /* Current message */ + struct i2c_msg *msg; + u8 addr; + unsigned int mode; + bool is_last_msg; + + /* I2C state machine */ + enum rk3x_i2c_state state; + unsigned int processed; /* sent/received bytes */ + int error; +}; + +static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value, + unsigned int offset) +{ + writel(value, i2c->regs + offset); +} + +static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset) +{ + return readl(i2c->regs + offset); +} + +/* Reset all interrupt pending bits */ +static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) +{ + i2c_writel(i2c, REG_INT_ALL, REG_IPD); +} + +/** + * Generate a START condition, which triggers a REG_INT_START interrupt. + */ +static void rk3x_i2c_start(struct rk3x_i2c *i2c) +{ + u32 val; + + rk3x_i2c_clean_ipd(i2c); + i2c_writel(i2c, REG_INT_START, REG_IEN); + + /* enable adapter with correct mode, send START condition */ + val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; + + /* if we want to react to NACK, set ACTACK bit */ + if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) + val |= REG_CON_ACTACK; + + i2c_writel(i2c, val, REG_CON); +} + +/** + * Generate a STOP condition, which triggers a REG_INT_STOP interrupt. + * + * @error: Error code to return in rk3x_i2c_xfer + */ +static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) +{ + unsigned int ctrl; + + i2c->processed = 0; + i2c->msg = NULL; + i2c->error = error; + + if (i2c->is_last_msg) { + /* Enable stop interrupt */ + i2c_writel(i2c, REG_INT_STOP, REG_IEN); + + i2c->state = STATE_STOP; + + ctrl = i2c_readl(i2c, REG_CON); + ctrl |= REG_CON_STOP; + i2c_writel(i2c, ctrl, REG_CON); + } else { + /* Signal rk3x_i2c_xfer to start the next message. */ + i2c->busy = false; + i2c->state = STATE_IDLE; + + /* + * The HW is actually not capable of REPEATED START. But we can + * get the intended effect by resetting its internal state + * and issuing an ordinary START. + */ + i2c_writel(i2c, 0, REG_CON); + + /* signal that we are finished with the current msg */ + wake_up(&i2c->wait); + } +} + +/** + * Setup a read according to i2c->msg + */ +static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) +{ + unsigned int len = i2c->msg->len - i2c->processed; + u32 con; + + con = i2c_readl(i2c, REG_CON); + + /* + * The hw can read up to 32 bytes at a time. If we need more than one + * chunk, send an ACK after the last byte of the current chunk. + */ + if (unlikely(len > 32)) { + len = 32; + con &= ~REG_CON_LASTACK; + } else { + con |= REG_CON_LASTACK; + } + + /* make sure we are in plain RX mode if we read a second chunk */ + if (i2c->processed != 0) { + con &= ~REG_CON_MOD_MASK; + con |= REG_CON_MOD(REG_CON_MOD_RX); + } + + i2c_writel(i2c, con, REG_CON); + i2c_writel(i2c, len, REG_MRXCNT); +} + +/** + * Fill the transmit buffer with data from i2c->msg + */ +static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) +{ + unsigned int i, j; + u32 cnt = 0; + u32 val; + u8 byte; + + for (i = 0; i < 8; ++i) { + val = 0; + for (j = 0; j < 4; ++j) { + if (i2c->processed == i2c->msg->len) + break; + + if (i2c->processed == 0 && cnt == 0) + byte = (i2c->addr & 0x7f) << 1; + else + byte = i2c->msg->buf[i2c->processed++]; + + val |= byte << (j * 8); + cnt++; + } + + i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i); + + if (i2c->processed == i2c->msg->len) + break; + } + + i2c_writel(i2c, cnt, REG_MTXCNT); +} + + +/* IRQ handlers for individual states */ + +static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd) +{ + if (!(ipd & REG_INT_START)) { + rk3x_i2c_stop(i2c, -EIO); + dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_START, REG_IPD); + + /* disable start bit */ + i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON); + + /* enable appropriate interrupts and transition */ + if (i2c->mode == REG_CON_MOD_TX) { + i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_WRITE; + rk3x_i2c_fill_transmit_buf(i2c); + } else { + /* in any other case, we are going to be reading. */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_READ; + rk3x_i2c_prepare_read(i2c); + } +} + +static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd) +{ + if (!(ipd & REG_INT_MBTF)) { + rk3x_i2c_stop(i2c, -EIO); + dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_MBTF, REG_IPD); + + /* are we finished? */ + if (i2c->processed == i2c->msg->len) + rk3x_i2c_stop(i2c, i2c->error); + else + rk3x_i2c_fill_transmit_buf(i2c); +} + +static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) +{ + unsigned int i; + unsigned int len = i2c->msg->len - i2c->processed; + u32 uninitialized_var(val); + u8 byte; + + /* we only care for MBRF here. */ + if (!(ipd & REG_INT_MBRF)) + return; + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_MBRF, REG_IPD); + + /* read the data from receive buffer */ + for (i = 0; i < len; ++i) { + if (i % 4 == 0) + val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4); + + byte = (val >> ((i % 4) * 8)) & 0xff; + i2c->msg->buf[i2c->processed++] = byte; + } + + /* are we finished? */ + if (i2c->processed == i2c->msg->len) + rk3x_i2c_stop(i2c, i2c->error); + else + rk3x_i2c_prepare_read(i2c); +} + +static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd) +{ + unsigned int con; + + if (!(ipd & REG_INT_STOP)) { + rk3x_i2c_stop(i2c, -EIO); + dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_STOP, REG_IPD); + + /* disable STOP bit */ + con = i2c_readl(i2c, REG_CON); + con &= ~REG_CON_STOP; + i2c_writel(i2c, con, REG_CON); + + i2c->busy = false; + i2c->state = STATE_IDLE; + + /* signal rk3x_i2c_xfer that we are finished */ + wake_up(&i2c->wait); +} + +static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) +{ + struct rk3x_i2c *i2c = dev_id; + unsigned int ipd; + + spin_lock(&i2c->lock); + + ipd = i2c_readl(i2c, REG_IPD); + if (i2c->state == STATE_IDLE) { + dev_warn(i2c->dev, "irq in STATE_IDLE, ipd = 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + goto out; + } + + dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd); + + /* Clean interrupt bits we don't care about */ + ipd &= ~(REG_INT_BRF | REG_INT_BTF); + + if (ipd & REG_INT_NAKRCV) { + /* + * We got a NACK in the last operation. Depending on whether + * IGNORE_NAK is set, we have to stop the operation and report + * an error. + */ + i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD); + + ipd &= ~REG_INT_NAKRCV; + + if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) + rk3x_i2c_stop(i2c, -ENXIO); + } + + /* is there anything left to handle? */ + if (unlikely(ipd == 0)) + goto out; + + switch (i2c->state) { + case STATE_START: + rk3x_i2c_handle_start(i2c, ipd); + break; + case STATE_WRITE: + rk3x_i2c_handle_write(i2c, ipd); + break; + case STATE_READ: + rk3x_i2c_handle_read(i2c, ipd); + break; + case STATE_STOP: + rk3x_i2c_handle_stop(i2c, ipd); + break; + case STATE_IDLE: + break; + } + +out: + spin_unlock(&i2c->lock); + return IRQ_HANDLED; +} + +static void rk3x_i2c_set_scl_rate(struct rk3x_i2c *i2c, unsigned long scl_rate) +{ + unsigned long i2c_rate = clk_get_rate(i2c->clk); + unsigned int div; + + /* SCL rate = (clk rate) / (8 * DIV) */ + div = DIV_ROUND_UP(i2c_rate, scl_rate * 8); + + /* The lower and upper half of the CLKDIV reg describe the length of + * SCL low & high periods. */ + div = DIV_ROUND_UP(div, 2); + + i2c_writel(i2c, (div << 16) | (div & 0xffff), REG_CLKDIV); +} + +/** + * Setup I2C registers for an I2C operation specified by msgs, num. + * + * Must be called with i2c->lock held. + * + * @msgs: I2C msgs to process + * @num: Number of msgs + * + * returns: Number of I2C msgs processed or negative in case of error + */ +static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) +{ + u32 addr = (msgs[0].addr & 0x7f) << 1; + int ret = 0; + + /* + * The I2C adapter can issue a small (len < 4) write packet before + * reading. This speeds up SMBus-style register reads. + * The MRXADDR/MRXRADDR hold the slave address and the slave register + * address in this case. + */ + + if (num >= 2 && msgs[0].len < 4 && + !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { + u32 reg_addr = 0; + int i; + + dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n", + addr >> 1); + + /* Fill MRXRADDR with the register address(es) */ + for (i = 0; i < msgs[0].len; ++i) { + reg_addr |= msgs[0].buf[i] << (i * 8); + reg_addr |= REG_MRXADDR_VALID(i); + } + + /* msgs[0] is handled by hw. */ + i2c->msg = &msgs[1]; + + i2c->mode = REG_CON_MOD_REGISTER_TX; + + i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR); + i2c_writel(i2c, reg_addr, REG_MRXRADDR); + + ret = 2; + } else { + /* + * We'll have to do it the boring way and process the msgs + * one-by-one. + */ + + if (msgs[0].flags & I2C_M_RD) { + addr |= 1; /* set read bit */ + + /* + * We have to transmit the slave addr first. Use + * MOD_REGISTER_TX for that purpose. + */ + i2c->mode = REG_CON_MOD_REGISTER_TX; + i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), + REG_MRXADDR); + i2c_writel(i2c, 0, REG_MRXRADDR); + } else { + i2c->mode = REG_CON_MOD_TX; + } + + i2c->msg = &msgs[0]; + + ret = 1; + } + + i2c->addr = msgs[0].addr; + i2c->busy = true; + i2c->state = STATE_START; + i2c->processed = 0; + i2c->error = 0; + + rk3x_i2c_clean_ipd(i2c); + + return ret; +} + +static int rk3x_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; + unsigned long timeout, flags; + int ret = 0; + int i; + + spin_lock_irqsave(&i2c->lock, flags); + + clk_enable(i2c->clk); + + /* The clock rate might have changed, so setup the divider again */ + rk3x_i2c_set_scl_rate(i2c, i2c->scl_frequency); + + i2c->is_last_msg = false; + + /* + * Process msgs. We can handle more than one message at once (see + * rk3x_i2c_setup()). + */ + for (i = 0; i < num; i += ret) { + ret = rk3x_i2c_setup(i2c, msgs + i, num - i); + + if (ret < 0) { + dev_err(i2c->dev, "rk3x_i2c_setup() failed\n"); + break; + } + + if (i + ret >= num) + i2c->is_last_msg = true; + + spin_unlock_irqrestore(&i2c->lock, flags); + + rk3x_i2c_start(i2c); + + timeout = wait_event_timeout(i2c->wait, !i2c->busy, + msecs_to_jiffies(WAIT_TIMEOUT)); + + spin_lock_irqsave(&i2c->lock, flags); + + if (timeout == 0) { + dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n", + i2c_readl(i2c, REG_IPD), i2c->state); + + /* Force a STOP condition without interrupt */ + i2c_writel(i2c, 0, REG_IEN); + i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON); + + i2c->state = STATE_IDLE; + + ret = -ETIMEDOUT; + break; + } + + if (i2c->error) { + ret = i2c->error; + break; + } + } + + clk_disable(i2c->clk); + spin_unlock_irqrestore(&i2c->lock, flags); + + return ret; +} + +static u32 rk3x_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; +} + +static const struct i2c_algorithm rk3x_i2c_algorithm = { + .master_xfer = rk3x_i2c_xfer, + .functionality = rk3x_i2c_func, +}; + +static struct rk3x_i2c_soc_data soc_data[3] = { + { .grf_offset = 0x154 }, /* rk3066 */ + { .grf_offset = 0x0a4 }, /* rk3188 */ + { .grf_offset = -1 }, /* no I2C switching needed */ +}; + +static const struct of_device_id rk3x_i2c_match[] = { + { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] }, + { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] }, + { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, +}; + +static int rk3x_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + struct rk3x_i2c *i2c; + struct resource *mem; + int ret = 0; + int bus_nr; + u32 value; + int irq; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + match = of_match_node(rk3x_i2c_match, np); + i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data; + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->scl_frequency)) { + dev_info(&pdev->dev, "using default SCL frequency: %d\n", + DEFAULT_SCL_RATE); + i2c->scl_frequency = DEFAULT_SCL_RATE; + } + + if (i2c->scl_frequency == 0 || i2c->scl_frequency > 400 * 1000) { + dev_warn(&pdev->dev, "invalid SCL frequency specified.\n"); + dev_warn(&pdev->dev, "using default SCL frequency: %d\n", + DEFAULT_SCL_RATE); + i2c->scl_frequency = DEFAULT_SCL_RATE; + } + + strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &rk3x_i2c_algorithm; + i2c->adap.retries = 3; + i2c->adap.dev.of_node = np; + i2c->adap.algo_data = i2c; + i2c->adap.dev.parent = &pdev->dev; + + i2c->dev = &pdev->dev; + + spin_lock_init(&i2c->lock); + init_waitqueue_head(&i2c->wait); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(i2c->clk); + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); + + /* Try to set the I2C adapter number from dt */ + bus_nr = of_alias_get_id(np, "i2c"); + + /* + * Switch to new interface if the SoC also offers the old one. + * The control bit is located in the GRF register space. + */ + if (i2c->soc_data->grf_offset >= 0) { + struct regmap *grf; + + grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, + "rk3x-i2c needs 'rockchip,grf' property\n"); + return PTR_ERR(grf); + } + + if (bus_nr < 0) { + dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias"); + return -EINVAL; + } + + /* 27+i: write mask, 11+i: value */ + value = BIT(27 + bus_nr) | BIT(11 + bus_nr); + + ret = regmap_write(grf, i2c->soc_data->grf_offset, value); + if (ret != 0) { + dev_err(i2c->dev, "Could not write to GRF: %d\n", ret); + return ret; + } + } + + /* IRQ setup */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "cannot find rk3x IRQ\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq, + 0, dev_name(&pdev->dev), i2c); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request IRQ\n"); + return ret; + } + + platform_set_drvdata(pdev, i2c); + + ret = clk_prepare(i2c->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Could not prepare clock\n"); + return ret; + } + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register adapter\n"); + goto err_clk; + } + + dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); + + return 0; + +err_clk: + clk_unprepare(i2c->clk); + return ret; +} + +static int rk3x_i2c_remove(struct platform_device *pdev) +{ + struct rk3x_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + clk_unprepare(i2c->clk); + + return 0; +} + +static struct platform_driver rk3x_i2c_driver = { + .probe = rk3x_i2c_probe, + .remove = rk3x_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rk3x-i2c", + .of_match_table = rk3x_i2c_match, + }, +}; + +module_platform_driver(rk3x_i2c_driver); + +MODULE_DESCRIPTION("Rockchip RK3xxx I2C Bus driver"); +MODULE_AUTHOR("Max Schwarz "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 3e833490fae55633f6adc03a5e6172d47c01f3e4 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Wed, 11 Jun 2014 11:17:30 +0200 Subject: i2c: sunxi: add P2WI (Push/Pull 2 Wire Interface) controller support The P2WI controller looks like an SMBus controller which only supports byte data transfers. But, it differs from standard SMBus protocol on several aspects: - it supports only one slave device, and thus drop the address field - it adds a parity bit every 8bits of data - only one read access is required to read a byte (instead of a write followed by a read access in standard SMBus protocol) - there's no Ack bit after each byte transfer This means this bus cannot be used to interface with standard SMBus devices (the only known device to support this interface is the AXP221 PMIC). However the P2WI protocol is close enough to SMBus to be integrated in the I2C subsystem (see this thread [1] for detailed reasons that led to integrating this driver in the I2C subsystem). [1] http://www.spinics.net/lists/linux-i2c/msg15066.html Signed-off-by: Boris BREZILLON Acked-by: Maxime Ripard Acked-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 13 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-sun6i-p2wi.c | 345 ++++++++++++++++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 drivers/i2c/busses/i2c-sun6i-p2wi.c (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 759ee30dc63..9f7d5859cf6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -774,6 +774,19 @@ config I2C_STU300 This driver can also be built as a module. If so, the module will be called i2c-stu300. +config I2C_SUN6I_P2WI + tristate "Allwinner sun6i internal P2WI controller" + depends on RESET_CONTROLLER + depends on MACH_SUN6I || COMPILE_TEST + help + If you say yes to this option, support will be included for the + P2WI (Push/Pull 2 Wire Interface) controller embedded in some sunxi + SOCs. + The P2WI looks like an SMBus controller (which supports only byte + accesses), except that it only supports one slave device. + This interface is used to connect to specific PMIC devices (like the + AXP221). + config I2C_TEGRA tristate "NVIDIA Tegra internal I2C controller" depends on ARCH_TEGRA diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 8ac83374cf7..dd9a7f8e873 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o +obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_WMT) += i2c-wmt.o diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c new file mode 100644 index 00000000000..f1d3e6f1a40 --- /dev/null +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -0,0 +1,345 @@ +/* + * P2WI (Push-Pull Two Wire Interface) bus driver. + * + * Author: Boris BREZILLON + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * The P2WI controller looks like an SMBus controller which only supports byte + * data transfers. But, it differs from standard SMBus protocol on several + * aspects: + * - it supports only one slave device, and thus drop the address field + * - it adds a parity bit every 8bits of data + * - only one read access is required to read a byte (instead of a write + * followed by a read access in standard SMBus protocol) + * - there's no Ack bit after each byte transfer + * + * This means this bus cannot be used to interface with standard SMBus + * devices (the only known device to support this interface is the AXP221 + * PMIC). + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* P2WI registers */ +#define P2WI_CTRL 0x0 +#define P2WI_CCR 0x4 +#define P2WI_INTE 0x8 +#define P2WI_INTS 0xc +#define P2WI_DADDR0 0x10 +#define P2WI_DADDR1 0x14 +#define P2WI_DLEN 0x18 +#define P2WI_DATA0 0x1c +#define P2WI_DATA1 0x20 +#define P2WI_LCR 0x24 +#define P2WI_PMCR 0x28 + +/* CTRL fields */ +#define P2WI_CTRL_START_TRANS BIT(7) +#define P2WI_CTRL_ABORT_TRANS BIT(6) +#define P2WI_CTRL_GLOBAL_INT_ENB BIT(1) +#define P2WI_CTRL_SOFT_RST BIT(0) + +/* CLK CTRL fields */ +#define P2WI_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8) +#define P2WI_CCR_MAX_CLK_DIV 0xff +#define P2WI_CCR_CLK_DIV(v) ((v) & P2WI_CCR_MAX_CLK_DIV) + +/* STATUS fields */ +#define P2WI_INTS_TRANS_ERR_ID(v) (((v) >> 8) & 0xff) +#define P2WI_INTS_LOAD_BSY BIT(2) +#define P2WI_INTS_TRANS_ERR BIT(1) +#define P2WI_INTS_TRANS_OVER BIT(0) + +/* DATA LENGTH fields*/ +#define P2WI_DLEN_READ BIT(4) +#define P2WI_DLEN_DATA_LENGTH(v) ((v - 1) & 0x7) + +/* LINE CTRL fields*/ +#define P2WI_LCR_SCL_STATE BIT(5) +#define P2WI_LCR_SDA_STATE BIT(4) +#define P2WI_LCR_SCL_CTL BIT(3) +#define P2WI_LCR_SCL_CTL_EN BIT(2) +#define P2WI_LCR_SDA_CTL BIT(1) +#define P2WI_LCR_SDA_CTL_EN BIT(0) + +/* PMU MODE CTRL fields */ +#define P2WI_PMCR_PMU_INIT_SEND BIT(31) +#define P2WI_PMCR_PMU_INIT_DATA(v) (((v) & 0xff) << 16) +#define P2WI_PMCR_PMU_MODE_REG(v) (((v) & 0xff) << 8) +#define P2WI_PMCR_PMU_DEV_ADDR(v) ((v) & 0xff) + +#define P2WI_MAX_FREQ 6000000 + +struct p2wi { + struct i2c_adapter adapter; + struct completion complete; + unsigned int status; + void __iomem *regs; + struct clk *clk; + struct reset_control *rstc; + int slave_addr; +}; + +static irqreturn_t p2wi_interrupt(int irq, void *dev_id) +{ + struct p2wi *p2wi = dev_id; + unsigned long status; + + status = readl(p2wi->regs + P2WI_INTS); + p2wi->status = status; + + /* Clear interrupts */ + status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | + P2WI_INTS_TRANS_OVER); + writel(status, p2wi->regs + P2WI_INTS); + + complete(&p2wi->complete); + + return IRQ_HANDLED; +} + +static u32 p2wi_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_BYTE_DATA; +} + +static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + struct p2wi *p2wi = i2c_get_adapdata(adap); + unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1); + + if (p2wi->slave_addr >= 0 && addr != p2wi->slave_addr) { + dev_err(&adap->dev, "invalid P2WI address\n"); + return -EINVAL; + } + + if (!data) + return -EINVAL; + + writel(command, p2wi->regs + P2WI_DADDR0); + + if (read_write == I2C_SMBUS_READ) + dlen |= P2WI_DLEN_READ; + else + writel(data->byte, p2wi->regs + P2WI_DATA0); + + writel(dlen, p2wi->regs + P2WI_DLEN); + + if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) { + dev_err(&adap->dev, "P2WI bus busy\n"); + return -EBUSY; + } + + reinit_completion(&p2wi->complete); + + writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER, + p2wi->regs + P2WI_INTE); + + writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB, + p2wi->regs + P2WI_CTRL); + + wait_for_completion(&p2wi->complete); + + if (p2wi->status & P2WI_INTS_LOAD_BSY) { + dev_err(&adap->dev, "P2WI bus busy\n"); + return -EBUSY; + } + + if (p2wi->status & P2WI_INTS_TRANS_ERR) { + dev_err(&adap->dev, "P2WI bus xfer error\n"); + return -ENXIO; + } + + if (read_write == I2C_SMBUS_READ) + data->byte = readl(p2wi->regs + P2WI_DATA0); + + return 0; +} + +static const struct i2c_algorithm p2wi_algo = { + .smbus_xfer = p2wi_smbus_xfer, + .functionality = p2wi_functionality, +}; + +static const struct of_device_id p2wi_of_match_table[] = { + { .compatible = "allwinner,sun6i-a31-p2wi" }, + {} +}; +MODULE_DEVICE_TABLE(of, p2wi_of_match_table); + +static int p2wi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *childnp; + unsigned long parent_clk_freq; + u32 clk_freq = 100000; + struct resource *r; + struct p2wi *p2wi; + u32 slave_addr; + int clk_div; + int irq; + int ret; + + of_property_read_u32(np, "clock-frequency", &clk_freq); + if (clk_freq > P2WI_MAX_FREQ) { + dev_err(dev, + "required clock-frequency (%u Hz) is too high (max = 6MHz)", + clk_freq); + return -EINVAL; + } + + if (of_get_child_count(np) > 1) { + dev_err(dev, "P2WI only supports one slave device\n"); + return -EINVAL; + } + + p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL); + if (!p2wi) + return -ENOMEM; + + p2wi->slave_addr = -1; + + /* + * Authorize a p2wi node without any children to be able to use an + * i2c-dev from userpace. + * In this case the slave_addr is set to -1 and won't be checked when + * launching a P2WI transfer. + */ + childnp = of_get_next_available_child(np, NULL); + if (childnp) { + ret = of_property_read_u32(childnp, "reg", &slave_addr); + if (ret) { + dev_err(dev, "invalid slave address on node %s\n", + childnp->full_name); + return -EINVAL; + } + + p2wi->slave_addr = slave_addr; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + p2wi->regs = devm_ioremap_resource(dev, r); + if (IS_ERR(p2wi->regs)) + return PTR_ERR(p2wi->regs); + + snprintf(p2wi->adapter.name, sizeof(p2wi->adapter.name), pdev->name); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to retrieve irq: %d\n", ret); + return irq; + } + + p2wi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(p2wi->clk)) { + ret = PTR_ERR(p2wi->clk); + dev_err(dev, "failed to retrieve clk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(p2wi->clk); + if (ret) { + dev_err(dev, "failed to enable clk: %d\n", ret); + return ret; + } + + parent_clk_freq = clk_get_rate(p2wi->clk); + + p2wi->rstc = devm_reset_control_get(dev, NULL); + if (IS_ERR(p2wi->rstc)) { + ret = PTR_ERR(p2wi->rstc); + dev_err(dev, "failed to retrieve reset controller: %d\n", ret); + goto err_clk_disable; + } + + ret = reset_control_deassert(p2wi->rstc); + if (ret) { + dev_err(dev, "failed to deassert reset line: %d\n", ret); + goto err_clk_disable; + } + + init_completion(&p2wi->complete); + p2wi->adapter.dev.parent = dev; + p2wi->adapter.algo = &p2wi_algo; + p2wi->adapter.owner = THIS_MODULE; + p2wi->adapter.dev.of_node = pdev->dev.of_node; + platform_set_drvdata(pdev, p2wi); + i2c_set_adapdata(&p2wi->adapter, p2wi); + + ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi); + if (ret) { + dev_err(dev, "can't register interrupt handler irq%d: %d\n", + irq, ret); + goto err_reset_assert; + } + + writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL); + + clk_div = parent_clk_freq / clk_freq; + if (!clk_div) { + dev_warn(dev, + "clock-frequency is too high, setting it to %lu Hz\n", + parent_clk_freq); + clk_div = 1; + } else if (clk_div > P2WI_CCR_MAX_CLK_DIV) { + dev_warn(dev, + "clock-frequency is too low, setting it to %lu Hz\n", + parent_clk_freq / P2WI_CCR_MAX_CLK_DIV); + clk_div = P2WI_CCR_MAX_CLK_DIV; + } + + writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div), + p2wi->regs + P2WI_CCR); + + ret = i2c_add_adapter(&p2wi->adapter); + if (!ret) + return 0; + +err_reset_assert: + reset_control_assert(p2wi->rstc); + +err_clk_disable: + clk_disable_unprepare(p2wi->clk); + + return ret; +} + +static int p2wi_remove(struct platform_device *dev) +{ + struct p2wi *p2wi = platform_get_drvdata(dev); + + reset_control_assert(p2wi->rstc); + clk_disable_unprepare(p2wi->clk); + i2c_del_adapter(&p2wi->adapter); + + return 0; +} + +static struct platform_driver p2wi_driver = { + .probe = p2wi_probe, + .remove = p2wi_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-sunxi-p2wi", + .of_match_table = p2wi_of_match_table, + }, +}; +module_platform_driver(p2wi_driver); + +MODULE_AUTHOR("Boris BREZILLON "); +MODULE_DESCRIPTION("Allwinner P2WI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From c155ba884f68b5447529bc75bcb54e68130fd774 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 12 Jun 2014 08:52:17 +0200 Subject: i2c: sun6i-p2wi: use proper return value in probe Fixes: >> drivers/i2c/busses/i2c-sun6i-p2wi.c:243:10: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized] Reported-by: kbuild test robot Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sun6i-p2wi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index f1d3e6f1a40..5d2d67820c9 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -240,7 +240,7 @@ static int p2wi_probe(struct platform_device *pdev) snprintf(p2wi->adapter.name, sizeof(p2wi->adapter.name), pdev->name); irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "failed to retrieve irq: %d\n", ret); + dev_err(dev, "failed to retrieve irq: %d\n", irq); return irq; } -- cgit v1.2.3-70-g09d2 From c51bd6acf59f24f2ec4334689329f1741f071621 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Jun 2014 23:56:09 +0200 Subject: i2c: rk3x: add NULL entry to the end of_device_id array drivers/i2c/busses/i2c-rk3x.c:610:69-70: rk3x_i2c_match is not NULL terminated at line 610 Make sure of_device_id tables are NULL terminated Generated by: /kbuild/src/linux/scripts/coccinelle/misc/of_table.cocci Signed-off-by: Dan Carpenter Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 9e3084c5e34..a9791509966 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -608,6 +608,7 @@ static const struct of_device_id rk3x_i2c_match[] = { { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] }, { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] }, { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, + {}, }; static int rk3x_i2c_probe(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From 4632a93f015caf6d7db4352f37aab74a39e60d7a Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 13 Jun 2014 12:23:48 +0200 Subject: i2c: sun6-p2wi: fix call to snprintf Fixes possible issue in case pdev name contains formatting characters. Signed-off-by: Boris BREZILLON Reported-by: Kees Cook Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sun6i-p2wi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index 5d2d67820c9..09de4fd12d5 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -237,7 +237,7 @@ static int p2wi_probe(struct platform_device *pdev) if (IS_ERR(p2wi->regs)) return PTR_ERR(p2wi->regs); - snprintf(p2wi->adapter.name, sizeof(p2wi->adapter.name), pdev->name); + strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name)); irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "failed to retrieve irq: %d\n", irq); -- cgit v1.2.3-70-g09d2 From e556756a6326d55dcbb476d471dcda36814fd696 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 9 Jun 2014 15:11:13 +0200 Subject: i2c: mux: pca954x: fix dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver causes the following randconfig build error: drivers/i2c/muxes/i2c-mux-pca954x.c: In function ‘pca954x_probe’: drivers/i2c/muxes/i2c-mux-pca954x.c:204:2: error: implicit declaration of function ‘devm_gpiod_get’ [-Werror=implicit-function-declaration] gpio = devm_gpiod_get(&client->dev, "reset"); ^ drivers/i2c/muxes/i2c-mux-pca954x.c:204:7: warning: assignment makes pointer from integer without a cast [enabled by default] gpio = devm_gpiod_get(&client->dev, "reset"); ^ drivers/i2c/muxes/i2c-mux-pca954x.c:206:3: error: implicit declaration of function ‘gpiod_direction_output’ [-Werror=implicit-function-declaration] gpiod_direction_output(gpio, 0); ^ cc1: some warnings being treated as errors make[3]: *** [drivers/i2c/muxes/i2c-mux-pca954x.o] Error 1 This is because it is getting compiled without gpiolib, so introduce an explicit dependency. Reported-by: Jim Davis Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index f7f9865b8b8..f6d313e528d 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -40,6 +40,7 @@ config I2C_MUX_PCA9541 config I2C_MUX_PCA954x tristate "Philips PCA954x I2C Mux/switches" + depends on GPIOLIB help If you say yes here you get support for the Philips PCA954x I2C mux/switch devices. -- cgit v1.2.3-70-g09d2 From 098aebc30292c10b31f6aa58bf4fe2c4b26001f6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 24 Jun 2014 09:25:28 +0530 Subject: i2c: sun6i-p2wi: Remove duplicate inclusion of module.h module.h was included twice. Signed-off-by: Sachin Kamat Acked-by: Boris BREZILLON Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sun6i-p2wi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index 09de4fd12d5..4d75d475970 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -22,7 +22,6 @@ * */ #include -#include #include #include #include -- cgit v1.2.3-70-g09d2