From cf7505ef9cd1349dfff0b2aeb9bc62f54c14e03d Mon Sep 17 00:00:00 2001 From: Chuansheng Liu Date: Wed, 7 Nov 2012 01:18:37 +0800 Subject: i2c: nomadik: Fix the usage of wait_for_completion_timeout The return value of wait_for_completion_timeout() is always >= 0 with unsigned int type. So the condition "ret < 0" or "ret >= 0" is pointless. Signed-off-by: liu chuansheng Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 02c3115a2dfa..8b2ffcf45322 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -435,13 +435,6 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) timeout = wait_for_completion_timeout( &dev->xfer_complete, dev->adap.timeout); - if (timeout < 0) { - dev_err(&dev->adev->dev, - "wait_for_completion_timeout " - "returned %d waiting for event\n", timeout); - status = timeout; - } - if (timeout == 0) { /* Controller timed out */ dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n", @@ -523,13 +516,6 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) timeout = wait_for_completion_timeout( &dev->xfer_complete, dev->adap.timeout); - if (timeout < 0) { - dev_err(&dev->adev->dev, - "wait_for_completion_timeout " - "returned %d waiting for event\n", timeout); - status = timeout; - } - if (timeout == 0) { /* Controller timed out */ dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n", -- cgit v1.2.3-59-g8ed1b From b53f4baf8b26303fc75ef3b00cf5e7398b58efd4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 10 Oct 2012 23:32:36 -0700 Subject: i2c: rcar: used devm_request_and_ioremap() instead of devm_ioremap() Signed-off-by: Kuninori Morimoto Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index f9399d163af2..2bce56de39e4 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -642,7 +642,7 @@ static int __devinit rcar_i2c_probe(struct platform_device *pdev) if (ret < 0) return ret; - priv->io = devm_ioremap(dev, res->start, resource_size(res)); + priv->io = devm_request_and_ioremap(dev, res); if (!priv->io) { dev_err(dev, "cannot ioremap\n"); return -ENODEV; -- cgit v1.2.3-59-g8ed1b From 45fd5e4ad2052101b4ceda5fdf4b003c428ebdfc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 13 Nov 2012 11:24:15 +0100 Subject: i2c: rcar: fix section mismatch Give the driver struct a name according to the 'standard' to fix: WARNING: vmlinux.o(.data+0x11798): Section mismatch in reference from the variable rcar_i2c_drv to the function .devinit.text:rcar_i2c_probe() ... WARNING: vmlinux.o(.data+0x1179c): Section mismatch in reference from the variable rcar_i2c_drv to the function .devexit.text:rcar_i2c_remove() Reported-by: Simon Horman Signed-off-by: Wolfram Sang Cc: Kuninori Morimoto --- drivers/i2c/busses/i2c-rcar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 2bce56de39e4..72a8071a5556 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -693,7 +693,7 @@ static int __devexit rcar_i2c_remove(struct platform_device *pdev) return 0; } -static struct platform_driver rcar_i2c_drv = { +static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .owner = THIS_MODULE, @@ -702,7 +702,7 @@ static struct platform_driver rcar_i2c_drv = { .remove = __devexit_p(rcar_i2c_remove), }; -module_platform_driver(rcar_i2c_drv); +module_platform_driver(rcar_i2c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Renesas R-Car I2C bus driver"); -- cgit v1.2.3-59-g8ed1b From 970d494c323826d8bb21e8ed1796da15082808ec Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 8 Aug 2012 08:54:32 +0200 Subject: i2c: ocores: Use devm_request_and_ioremap() Replacing the devm_request_mem_region() and devm_ioremap_nocache() calls by a single call to devm_request_and_ioremap() simplifies the code. Signed-off-by: Thierry Reding Acked-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index bffd5501ac2d..1fad4aeb7902 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -283,18 +283,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "Memory region busy\n"); - return -EBUSY; - } - - i2c->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!i2c->base) { - dev_err(&pdev->dev, "Unable to map registers\n"); - return -EIO; - } + i2c->base = devm_request_and_ioremap(&pdev->dev, res); + if (!i2c->base) + return -EADDRNOTAVAIL; pdata = pdev->dev.platform_data; if (pdata) { -- cgit v1.2.3-59-g8ed1b From 58a7371a4dd9d03f77265ee2784781fc39096136 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Mon, 15 Oct 2012 15:51:17 +0800 Subject: i2c: i2c-gpio: fix name issue with multiple i2c gpio nodes When having multiple i2c-gpio nodes, the name for each is same. So add the patch to fix it. The adap->name printing information was added by myself without this patch the log information is as following ---<8--- adap->name = i2c-gpio-1 i2c-gpio i2c.2: using pins 30 (SDA) and 31 (SCL) adap->name = i2c-gpio-1 i2c-gpio i2c.3: using pins 64 (SDA) and 65 (SCL) --->8--- with this patch, the log information is as following ---<8--- adap->name = i2c.2 i2c-gpio i2c.2: using pins 30 (SDA) and 31 (SCL) adap->name = i2c.3 i2c-gpio i2c.3: using pins 64 (SDA) and 65 (SCL) --->8--- Signed-off-by: Bo Shen Reviewed-by: Stephen Warren [wsa: minor fixes to the commit mesage] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-gpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index e62d2d938628..257299a92df3 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -184,7 +184,11 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev) bit_data->data = pdata; adap->owner = THIS_MODULE; - snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + if (pdev->dev.of_node) + strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + else + snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->dev.parent = &pdev->dev; -- cgit v1.2.3-59-g8ed1b From 7c3fe64d133fbe4132d9966cd2f79a7193f13139 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 13 Nov 2012 16:43:21 +0100 Subject: i2c: at91: fix SMBus quick command The driver claims to support SMBus quick command but it was not the case. This patch fixes this issue. Without it, i2cdetect finds imaginary devices. And with some IP versions, trying to send 0 byte can cause issue when writing data to an EEPROM. Signed-off-by: Ludovic Desroches Acked-by: Jean-Christophe PLAGNIOL-VILLARD [wsa: improved the commit message] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index aa59a254be2c..c02bf208084f 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -39,6 +39,7 @@ #define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ #define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ #define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ #define AT91_TWI_SWRST 0x0080 /* Software Reset */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ @@ -212,7 +213,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) INIT_COMPLETION(dev->cmd_complete); dev->transfer_status = 0; - if (dev->msg->flags & I2C_M_RD) { + + if (!dev->buf_len) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { -- cgit v1.2.3-59-g8ed1b From 49839dc93970789cea46f5171cd7f6ec11af64c7 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 6 Nov 2012 16:31:32 +0000 Subject: Revert "ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints" This reverts commit 3db11feffc1ad2ab9dea27789e6b5b3032827adc (ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints). This commit causes I2C timeouts to appear on several OMAP3430/3530-based boards: http://marc.info/?l=linux-arm-kernel&m=135071372426971&w=2 http://marc.info/?l=linux-arm-kernel&m=135067558415214&w=2 http://marc.info/?l=linux-arm-kernel&m=135216013608196&w=2 and appears to have been sent for merging before one of its prerequisites was merged: http://marc.info/?l=linux-arm-kernel&m=135219411617621&w=2 Signed-off-by: Paul Walmsley Acked-by: Jean Pihet Signed-off-by: Wolfram Sang --- arch/arm/plat-omap/i2c.c | 21 +++++++++++++++++++++ drivers/i2c/busses/i2c-omap.c | 32 ++++++++++++++------------------ include/linux/i2c-omap.h | 1 + 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index a5683a84c6ee..6013831a043e 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #define OMAP_I2C_SIZE 0x3f @@ -127,6 +129,16 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS +/* + * XXX This function is a temporary compatibility wrapper - only + * needed until the I2C driver can be converted to call + * omap_pm_set_max_dev_wakeup_lat() and handle a return code. + */ +static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) +{ + omap_pm_set_max_mpu_wakeup_lat(dev, t); +} + static inline int omap2_i2c_add_bus(int bus_id) { int l; @@ -158,6 +170,15 @@ static inline int omap2_i2c_add_bus(int bus_id) dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; pdata->flags = dev_attr->flags; + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + * Only omap3 has support for constraints + */ + if (cpu_is_omap34xx()) + pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index db31eaed6ea5..0b0254312d21 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,7 +43,6 @@ #include #include #include -#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -187,8 +186,9 @@ struct omap_i2c_dev { int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum MPU wkup latency */ - struct pm_qos_request pm_qos_request; + u32 latency; /* maximum mpu wkup latency */ + void (*set_mpu_wkup_lat)(struct device *dev, + long latency); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -494,7 +494,9 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->threshold) / + (1000 * dev->speed / 8); } /* @@ -629,16 +631,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - */ - if (dev->latency) - pm_qos_add_request(&dev->pm_qos_request, - PM_QOS_CPU_DMA_LATENCY, - dev->latency); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -646,8 +640,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->latency) - pm_qos_remove_request(&dev->pm_qos_request); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); if (r == 0) r = num; @@ -1104,6 +1098,7 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } @@ -1159,8 +1154,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index df804ba73e0b..92a0dc75bc74 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,6 +34,7 @@ struct omap_i2c_bus_platform_data { u32 clkrate; u32 rev; u32 flags; + void (*set_mpu_wkup_lat)(struct device *dev, long set); }; #endif -- cgit v1.2.3-59-g8ed1b From d60ece5f010043422c5fbc3609714c4420c7c9bf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Nov 2012 16:22:45 +0200 Subject: i2c: omap: ensure writes to dev->buf_len are ordered if we allow compiler reorder our writes, we could fall into a situation where dev->buf_len is reset for no apparent reason. This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size, dev->buf_len was reset to zero before we had an oportunity to handle XDR Interrupt. Because dev->buf_len was zero, we entered omap_i2c_transmit_data() to transfer zero bytes, which would mean we would just silently exit omap_i2c_transmit_data() without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes. After adding the memory barrier, we also drop resetting dev->buf_len to zero in omap_i2c_xfer_msg() because both omap_i2c_transmit_data() and omap_i2c_receive_data() will act until dev->buf_len reaches zero, rendering the other write in omap_i2c_xfer_msg() redundant. This patch has been tested with pandaboard for a few iterations of the script mentioned above. Signed-off-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0b0254312d21..3525c9e62cb0 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -524,6 +524,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf = msg->buf; dev->buf_len = msg->len; + /* make sure writes to dev->buf_len are ordered */ + barrier(); + omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); /* Clear the FIFO Buffers */ @@ -581,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, */ timeout = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); - dev->buf_len = 0; if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); -- cgit v1.2.3-59-g8ed1b From 2d4b4520a5eaed6701b0c9f7540c8fd99a26e449 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Tue, 16 Oct 2012 15:23:20 +0000 Subject: i2c: omap: adopt pinctrl support Some GPIO expanders need some early pin control muxing. Due to legacy boards sometimes the driver uses subsys_initcall instead of module_init. This patch takes advantage of defer probe feature and pin control in order to wait until pin control probing before GPIO driver probing. It has been tested on OMAP5 board with TCA6424 driver. Signed-off-by: Sebastien Guiriec Acked-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 3525c9e62cb0..16afb289cca7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -213,6 +214,8 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; + + struct pinctrl *pins; }; static const u8 reg_map_ip_v1[] = { @@ -1104,6 +1107,16 @@ omap_i2c_probe(struct platform_device *pdev) dev->dtrev = pdata->rev; } + dev->pins = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(dev->pins)) { + if (PTR_ERR(dev->pins) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(&pdev->dev, "did not get pins for i2c error: %li\n", + PTR_ERR(dev->pins)); + dev->pins = NULL; + } + dev->dev = &pdev->dev; dev->irq = irq; -- cgit v1.2.3-59-g8ed1b From 47dcd0161a0b37bf0299473585fc5030d3f45b64 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:36 +0530 Subject: i2c: omap: Fix the revision register read The revision register on OMAP4 is a 16-bit lo and a 16-bit hi. Currently the driver reads only the lower 8-bits. Fix the same by preventing the truncating of the rev register for OMAP4. Also use the scheme bit ie bit-14 of the hi register to know if it is OMAP_I2C_IP_VERSION_2. On platforms previous to OMAP4 the offset 0x04 is IE register whose bit-14 reset value is 0, the code uses the same to its advantage. Also since the omap_i2c_read_reg uses reg_map_ip_* a raw_readw is done to fetch the revision register. The dev->regs is populated after reading the rev_hi. A NULL check has been added in the resume handler to prevent the access before the setting of the regs. Signed-off-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 61 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 16afb289cca7..bf0569eefeb8 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -49,9 +49,10 @@ #define OMAP_I2C_OMAP1_REV_2 0x20 /* I2C controller revisions present on specific hardware */ -#define OMAP_I2C_REV_ON_2430 0x36 -#define OMAP_I2C_REV_ON_3430_3530 0x3C -#define OMAP_I2C_REV_ON_3630_4430 0x40 +#define OMAP_I2C_REV_ON_2430 0x00000036 +#define OMAP_I2C_REV_ON_3430_3530 0x0000003C +#define OMAP_I2C_REV_ON_3630 0x00000040 +#define OMAP_I2C_REV_ON_4430_PLUS 0x50400002 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -203,7 +204,7 @@ struct omap_i2c_dev { * fifo_size==0 implies no fifo * if set, should be trsh+1 */ - u8 rev; + u32 rev; unsigned b_hw:1; /* bad h/w fixes */ unsigned receiver:1; /* true when we're in receiver mode */ u16 iestate; /* Saved interrupt register */ @@ -493,7 +494,7 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); - if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + if (dev->rev < OMAP_I2C_REV_ON_3630) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ @@ -1051,6 +1052,16 @@ static const struct of_device_id omap_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, omap_i2c_of_match); #endif +#define OMAP_I2C_SCHEME(rev) ((rev & 0xc000) >> 14) + +#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4) +#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf) + +#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7) +#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f) +#define OMAP_I2C_SCHEME_0 0 +#define OMAP_I2C_SCHEME_1 1 + static int __devinit omap_i2c_probe(struct platform_device *pdev) { @@ -1063,6 +1074,8 @@ omap_i2c_probe(struct platform_device *pdev) const struct of_device_id *match; int irq; int r; + u32 rev; + u16 minor, major; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1127,11 +1140,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - if (dev->dtrev == OMAP_I2C_IP_VERSION_2) - dev->regs = (u8 *)reg_map_ip_v2; - else - dev->regs = (u8 *)reg_map_ip_v1; - pm_runtime_enable(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(dev->dev); @@ -1140,7 +1148,31 @@ omap_i2c_probe(struct platform_device *pdev) if (IS_ERR_VALUE(r)) goto err_free_mem; - dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; + /* + * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2. + * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset. + * Also since the omap_i2c_read_reg uses reg_map_ip_* a + * raw_readw is done. + */ + rev = __raw_readw(dev->base + 0x04); + + switch (OMAP_I2C_SCHEME(rev)) { + case OMAP_I2C_SCHEME_0: + dev->regs = (u8 *)reg_map_ip_v1; + dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); + minor = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev); + major = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev); + break; + case OMAP_I2C_SCHEME_1: + /* FALLTHROUGH */ + default: + dev->regs = (u8 *)reg_map_ip_v2; + rev = (rev << 16) | + omap_i2c_read_reg(dev, OMAP_I2C_IP_V2_REVNB_LO); + minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev); + major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev); + dev->rev = rev; + } dev->errata = 0; @@ -1165,7 +1197,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + if (dev->rev < OMAP_I2C_REV_ON_3630) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ @@ -1209,7 +1241,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, - dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + dev->dtrev, major, minor, dev->speed); of_i2c_register_devices(adap); @@ -1275,6 +1307,9 @@ static int omap_i2c_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + if (!_dev->regs) + return 0; + if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0); omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate); -- cgit v1.2.3-59-g8ed1b From a748021ccbd2bb9b2b818a7fc67b19187d04bdf2 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:37 +0530 Subject: i2c: omap: use revision check for OMAP_I2C_FLAG_APPLY_ERRATA_I207 The errata i207 is enabled for 2430 and 3xxx. Use the revision check to enable the erratum instead. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index bf0569eefeb8..7c409606f20c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1176,7 +1176,8 @@ omap_i2c_probe(struct platform_device *pdev) dev->errata = 0; - if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + if (dev->rev >= OMAP_I2C_REV_ON_2430 && + dev->rev < OMAP_I2C_REV_ON_4430_PLUS) dev->errata |= I2C_OMAP_ERRATA_I207; if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) -- cgit v1.2.3-59-g8ed1b From cd10c74aeea76e60ec5ab15357266b76d8e50df1 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:38 +0530 Subject: i2c: omap: remove the dtrev The dtrev is used only for the comments. Remove the same and use the scheme instead to know if it is version2. Signed-off-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7c409606f20c..0ca50e71731b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -192,7 +192,6 @@ struct omap_i2c_dev { void (*set_mpu_wkup_lat)(struct device *dev, long latency); u32 speed; /* Speed of bus in kHz */ - u32 dtrev; /* extra revision from DT */ u32 flags; u16 cmd_err; u8 *buf; @@ -1075,7 +1074,7 @@ omap_i2c_probe(struct platform_device *pdev) int irq; int r; u32 rev; - u16 minor, major; + u16 minor, major, scheme; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1107,7 +1106,6 @@ omap_i2c_probe(struct platform_device *pdev) u32 freq = 100000; /* default to 100000 Hz */ pdata = match->data; - dev->dtrev = pdata->rev; dev->flags = pdata->flags; of_property_read_u32(node, "clock-frequency", &freq); @@ -1117,7 +1115,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->speed = pdata->clkrate; dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; - dev->dtrev = pdata->rev; } dev->pins = devm_pinctrl_get_select_default(&pdev->dev); @@ -1156,7 +1153,8 @@ omap_i2c_probe(struct platform_device *pdev) */ rev = __raw_readw(dev->base + 0x04); - switch (OMAP_I2C_SCHEME(rev)) { + scheme = OMAP_I2C_SCHEME(rev); + switch (scheme) { case OMAP_I2C_SCHEME_0: dev->regs = (u8 *)reg_map_ip_v1; dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); @@ -1241,8 +1239,8 @@ omap_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } - dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, - dev->dtrev, major, minor, dev->speed); + dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, + major, minor, dev->speed); of_i2c_register_devices(adap); -- cgit v1.2.3-59-g8ed1b From 2c88ab8c5af7d637d2a9d14b607fa6100fa64236 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:39 +0530 Subject: ARM: i2c: omap: Remove the i207 errata flag The commit [i2c: omap: use revision check for OMAP_I2C_FLAG_APPLY_ERRATA_I207] uses the revision id instead of the flag. So the flag can be safely removed. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- arch/arm/mach-omap2/omap_hwmod_2430_data.c | 3 +-- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 9 +++------ drivers/i2c/busses/i2c-omap.c | 3 +-- include/linux/i2c-omap.h | 1 - 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index c455e41b0237..b79ccf6efbe8 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -76,8 +76,7 @@ static struct omap_hwmod_class i2c_class = { static struct omap_i2c_dev_attr i2c_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_BUS_SHIFT_2 | + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2 | OMAP_I2C_FLAG_FORCE_19200_INT_CLK, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index f67b7ee07dd4..943222c40489 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -791,8 +791,7 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = { /* I2C1 */ static struct omap_i2c_dev_attr i2c1_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; @@ -818,8 +817,7 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = { /* I2C2 */ static struct omap_i2c_dev_attr i2c2_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; @@ -845,8 +843,7 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = { /* I2C3 */ static struct omap_i2c_dev_attr i2c3_dev_attr = { .fifo_depth = 64, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0ca50e71731b..11e645ab1e79 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1028,8 +1028,7 @@ static const struct i2c_algorithm omap_i2c_algo = { #ifdef CONFIG_OF static struct omap_i2c_bus_platform_data omap3_pdata = { .rev = OMAP_I2C_IP_VERSION_1, - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc75bc74..1b25c04f82d9 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -21,7 +21,6 @@ #define OMAP_I2C_FLAG_SIMPLE_CLOCK BIT(1) #define OMAP_I2C_FLAG_16BIT_DATA_REG BIT(2) #define OMAP_I2C_FLAG_RESET_REGS_POSTIDLE BIT(3) -#define OMAP_I2C_FLAG_APPLY_ERRATA_I207 BIT(4) #define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK BIT(5) #define OMAP_I2C_FLAG_FORCE_19200_INT_CLK BIT(6) /* how the CPU address bus must be translated for I2C unit access */ -- cgit v1.2.3-59-g8ed1b From 95dd3032663fab5a56331b066baf1757cb941b1a Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:40 +0530 Subject: i2c: omap: re-factor omap_i2c_init function re-factor omap_i2c_init() so that we can re-use it for resume. While at it also remove the bufstate variable as we write it in omap_i2c_resize_fifo for every transfer. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 75 ++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 11e645ab1e79..0195d9969df0 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -210,7 +210,6 @@ struct omap_i2c_dev { u16 pscstate; u16 scllstate; u16 sclhstate; - u16 bufstate; u16 syscstate; u16 westate; u16 errata; @@ -278,9 +277,34 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } +static void __omap_i2c_init(struct omap_i2c_dev *dev) +{ + + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + + /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ + omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); + + /* SCL low and high time values */ + omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); + omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); + if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + + /* Take the I2C module out of reset: */ + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + + /* + * Don't write to this register if the IE state is 0 as it can + * cause deadlock. + */ + if (dev->iestate) + omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); +} + static int omap_i2c_init(struct omap_i2c_dev *dev) { - u16 psc = 0, scll = 0, sclh = 0, buf = 0; + u16 psc = 0, scll = 0, sclh = 0; u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; unsigned long fclk_rate = 12000000; unsigned long timeout; @@ -330,11 +354,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * REVISIT: Some wkup sources might not be needed. */ dev->westate = OMAP_I2C_WE_ALL; - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, - dev->westate); } } - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* @@ -419,28 +440,17 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) sclh = fclk_rate / (dev->speed * 2) - 7 + psc; } - /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ - omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc); - - /* SCL low and high time values */ - omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); - omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - - /* Take the I2C module out of reset: */ - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - - /* Enable interrupts */ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) | ((dev->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); - omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); - if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { - dev->pscstate = psc; - dev->scllstate = scll; - dev->sclhstate = sclh; - dev->bufstate = buf; - } + + dev->pscstate = psc; + dev->scllstate = scll; + dev->sclhstate = sclh; + + __omap_i2c_init(dev); + return 0; } @@ -1308,23 +1318,8 @@ static int omap_i2c_runtime_resume(struct device *dev) if (!_dev->regs) return 0; - if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0); - omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate); - omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate); - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - } - - /* - * Don't write to this register if the IE state is 0 as it can - * cause deadlock. - */ - if (_dev->iestate) - omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate); + if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) + __omap_i2c_init(_dev); return 0; } -- cgit v1.2.3-59-g8ed1b From d6c842ad564c336d62d3d5777c520454f1473b8c Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:41 +0530 Subject: i2c: omap: make reset a seperate function Implement reset as a separate function. This will enable us to make sure that we don't do the calculation again on every transfer. Also at probe the reset is not added as the hwmod is doing that for us. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0195d9969df0..faaa05224904 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -302,15 +302,9 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); } -static int omap_i2c_init(struct omap_i2c_dev *dev) +static int omap_i2c_reset(struct omap_i2c_dev *dev) { - u16 psc = 0, scll = 0, sclh = 0; - u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; - unsigned long fclk_rate = 12000000; unsigned long timeout; - unsigned long internal_clk = 0; - struct clk *fclk; - if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { /* Disable I2C controller before soft reset */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, @@ -348,14 +342,27 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate); - /* - * Enabling all wakup sources to stop I2C freezing on - * WFI instruction. - * REVISIT: Some wkup sources might not be needed. - */ - dev->westate = OMAP_I2C_WE_ALL; } } + return 0; +} + +static int omap_i2c_init(struct omap_i2c_dev *dev) +{ + u16 psc = 0, scll = 0, sclh = 0; + u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; + unsigned long fclk_rate = 12000000; + unsigned long internal_clk = 0; + struct clk *fclk; + + if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { + /* + * Enabling all wakup sources to stop I2C freezing on + * WFI instruction. + * REVISIT: Some wkup sources might not be needed. + */ + dev->westate = OMAP_I2C_WE_ALL; + } if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* @@ -599,7 +606,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, OMAP_I2C_TIMEOUT); if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); - omap_i2c_init(dev); + omap_i2c_reset(dev); + __omap_i2c_init(dev); return -ETIMEDOUT; } @@ -609,7 +617,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, /* We have an error */ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { - omap_i2c_init(dev); + omap_i2c_reset(dev); + __omap_i2c_init(dev); return -EIO; } -- cgit v1.2.3-59-g8ed1b From 554c96744afd169886bd6fc2736fb0d9aaf634e8 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:42 +0530 Subject: i2c: omap: Restore i2c context always Currently the restore is done based on the flag OMAP_I2C_FLAG_RESET_REGS_POSTIDLE. This helps the following - The driver is always capable of restoring regardless of the off mode support being there or not. - While testing omap2430 it is found that in case of certain error paths (timeout) a reset is done. However the restore never happens as it is dependent on the POSTIDLE flag. The other option would be to call a restore in the reset case. As there are only a few registers to be restored the penalty in the idle case should not be much. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index faaa05224904..067a73922be3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1327,8 +1327,7 @@ static int omap_i2c_runtime_resume(struct device *dev) if (!_dev->regs) return 0; - if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) - __omap_i2c_init(_dev); + __omap_i2c_init(_dev); return 0; } -- cgit v1.2.3-59-g8ed1b From ca85e248b65649176e9e1edfbf5e791bc44ee52b Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:43 +0530 Subject: i2c: omap: cleanup the sysc write Currently after the reset the sysc is written with hardcoded values. The patch reads the sysc register and writes back the same value after reset. - Some unnecessary rev checks can be optimised. - Also due to whatever reason the hwmod flags are changed we will not reset the values. - In some of the cases the minor values of the 2430 register is different(0x37) in that case the autoidle setting may be missed. Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 067a73922be3..482c63d53685 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -305,7 +305,11 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) static int omap_i2c_reset(struct omap_i2c_dev *dev) { unsigned long timeout; + u16 sysc; + if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { + sysc = omap_i2c_read_reg(dev, OMAP_I2C_SYSC_REG); + /* Disable I2C controller before soft reset */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & @@ -327,22 +331,8 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) } /* SYSC register is cleared by the reset; rewrite it */ - if (dev->rev == OMAP_I2C_REV_ON_2430) { - - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, - SYSC_AUTOIDLE_MASK); + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { - dev->syscstate = SYSC_AUTOIDLE_MASK; - dev->syscstate |= SYSC_ENAWAKEUP_MASK; - dev->syscstate |= (SYSC_IDLEMODE_SMART << - __ffs(SYSC_SIDLEMODE_MASK)); - dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK << - __ffs(SYSC_CLOCKACTIVITY_MASK)); - - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, - dev->syscstate); - } } return 0; } -- cgit v1.2.3-59-g8ed1b From 27e0fbefa5ddebdd681d2be9824302d14494c5ff Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 14 Nov 2012 18:12:29 +0100 Subject: i2c: omap: don't save a value only needed for read-clearing Acked-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 482c63d53685..49b12fb00c90 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1291,14 +1291,13 @@ static int omap_i2c_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); - u16 iv; _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { - iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ + omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ } else { omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate); -- cgit v1.2.3-59-g8ed1b From 7b0e62920ac314eb819e68b7d2c51994b98b19ca Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:56:51 +0900 Subject: i2c: i2c-sh_mobile: calculate clock parameters at driver probing time Currently SCL clock parameters (ICCH/ICCL) are calculated in activate_ch(), which gets called every time sh_mobile_i2c_xfer() is processed, while each I2C bus speed is system-defined and in general those parameters do not have to be updated over I2C transactions. The only reason I could see having it transaction-time is to adjust ICCH/ICCL values according to the operating frequency of the I2C hardware block, in the face of DFS (Dynamic Frequency Scaling). However, this won't be necessary. The operating frequency of the I2C hardware block can change _even_ in the middle of I2C transactions. There is no way to prevent it from happening, and I2C hardware block can work with such dynamic frequency change, of course. Another is that ICCH/ICCL clock parameters optimized for the faster operating frequency, can also be applied to the slower operating frequency, as long as slave devices work. However, the converse is not true. It would violate SCL timing specs of the I2C standard. What we can do now is to calculate the ICCH/ICCL clock parameters according to the fastest operating clock of the I2C hardware block. And if that's the case, that calculation should be done just once at driver-module-init time. This patch moves ICCH/ICCL calculating part from activate_ch() into sh_mobile_i2c_init(), and call it from sh_mobile_i2c_probe(). Note that sh_mobile_i2c_init() just prepares clock parameters using the clock rate and platform data provided, but does _not_ make any hardware I/O accesses. We don't have to care about run-time PM maintenance here. Signed-off-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 8110ca45f342..309d0d592890 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -187,18 +187,15 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); } -static void activate_ch(struct sh_mobile_i2c_data *pd) +static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk; u_int32_t num; u_int32_t denom; u_int32_t tmp; - /* Wake up device and enable clock */ - pm_runtime_get_sync(pd->dev); - clk_enable(pd->clk); - /* Get clock rate after clock is enabled */ + clk_enable(pd->clk); i2c_clk = clk_get_rate(pd->clk); /* Calculate the value for iccl. From the data sheet: @@ -239,6 +236,15 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) pd->icic &= ~ICIC_ICCHB8; } + clk_disable(pd->clk); +} + +static void activate_ch(struct sh_mobile_i2c_data *pd) +{ + /* Wake up device and enable clock */ + pm_runtime_get_sync(pd->dev); + clk_enable(pd->clk); + /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); @@ -632,6 +638,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (size > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; + sh_mobile_i2c_init(pd); + /* Enable Runtime PM for this device. * * Also tell the Runtime PM core to ignore children -- cgit v1.2.3-59-g8ed1b From 23a612916a51cc3772ff46c9dc34a86c9c50840e Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:57:27 +0900 Subject: i2c: i2c-sh_mobile: optimize ICCH/ICCL values according to I2C bus speed ICCH/ICCL values is supposed to be calculated/optimized to strictly meet the timing specs required by the I2C standard. The resulting I2C bus speed does not matter at all, if it's less than 100 or 400 kHz. With this change, sh_mobile_i2c_icch() is virtually identical to sh_mobile_i2c_iccl(), but they're providing good descriptions of SH-/R-Mobile I2C hardware spec, and I'd leave them as separated. Also fix a typo in the comment, print icch/iccl values at probe, etc. Signed-off-by: Shinya Kuribayashi [wsa: squashed two patches for bisectability] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 126 ++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 309d0d592890..4dc0cc3611c2 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -122,9 +122,9 @@ struct sh_mobile_i2c_data { unsigned long bus_speed; struct clk *clk; u_int8_t icic; - u_int8_t iccl; - u_int8_t icch; u_int8_t flags; + u_int16_t iccl; + u_int16_t icch; spinlock_t lock; wait_queue_head_t wait; @@ -135,7 +135,8 @@ struct sh_mobile_i2c_data { #define IIC_FLAG_HAS_ICIC67 (1 << 0) -#define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */ +#define STANDARD_MODE 100000 +#define FAST_MODE 400000 /* Register offsets */ #define ICDR 0x00 @@ -187,55 +188,81 @@ 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) +{ + /* + * Conditional expression: + * ICCL >= COUNT_CLK * (tLOW + tf) + * + * SH-Mobile IIC hardware starts counting the LOW period of + * the SCL signal (tLOW) as soon as it pulls the SCL line. + * In order to meet the tLOW timing spec, we need to take into + * 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; +} + +static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int offset) +{ + /* + * Conditional expression: + * ICCH >= COUNT_CLK * (tHIGH + tf) + * + * SH-Mobile IIC hardware is aware of SCL transition period 'tr', + * and can ignore it. SH-Mobile IIC controller starts counting + * the HIGH period of the SCL signal (tHIGH) after the SCL input + * voltage increases at VIH. + * + * Afterward it turned out calculating ICCH using only tHIGH spec + * will result in violation of the tHD;STA timing spec. We need + * 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; +} + static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { - unsigned long i2c_clk; - u_int32_t num; - u_int32_t denom; - u_int32_t tmp; + unsigned long i2c_clk_khz; + u32 tHIGH, tLOW, tf; + int offset; /* Get clock rate after clock is enabled */ clk_enable(pd->clk); - i2c_clk = clk_get_rate(pd->clk); - - /* Calculate the value for iccl. From the data sheet: - * iccl = (p clock / transfer rate) * (L / (L + H)) - * where L and H are the SCL low/high ratio (5/4 in this case). - * We also round off the result. - */ - num = i2c_clk * 5; - denom = pd->bus_speed * 9; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->iccl = (u_int8_t)((num/denom) + 1); - else - pd->iccl = (u_int8_t)(num/denom); - - /* one more bit of ICCL in ICIC */ - if (pd->flags & IIC_FLAG_HAS_ICIC67) { - if ((num/denom) > 0xff) - pd->icic |= ICIC_ICCLB8; - else - pd->icic &= ~ICIC_ICCLB8; + i2c_clk_khz = clk_get_rate(pd->clk) / 1000; + + if (pd->bus_speed == STANDARD_MODE) { + 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; } - /* Calculate the value for icch. From the data sheet: - icch = (p clock / transfer rate) * (H / (L + H)) */ - num = i2c_clk * 4; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->icch = (u_int8_t)((num/denom) + 1); + pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf, offset); + /* one more bit of ICCL in ICIC */ + if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + pd->icic |= ICIC_ICCLB8; else - pd->icch = (u_int8_t)(num/denom); + pd->icic &= ~ICIC_ICCLB8; + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf, offset); /* one more bit of ICCH in ICIC */ - if (pd->flags & IIC_FLAG_HAS_ICIC67) { - if ((num/denom) > 0xff) - pd->icic |= ICIC_ICCHB8; - else - pd->icic &= ~ICIC_ICCHB8; - } + if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + pd->icic |= ICIC_ICCHB8; + else + pd->icic &= ~ICIC_ICCHB8; +out: clk_disable(pd->clk); } @@ -252,8 +279,8 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) iic_wr(pd, ICIC, 0); /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl); - iic_wr(pd, ICCH, pd->icch); + iic_wr(pd, ICCL, pd->iccl & 0xff); + iic_wr(pd, ICCH, pd->icch & 0xff); } static void deactivate_ch(struct sh_mobile_i2c_data *pd) @@ -457,8 +484,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl); - iic_wr(pd, ICCH, pd->icch); + iic_wr(pd, ICCL, pd->iccl & 0xff); + iic_wr(pd, ICCH, pd->icch & 0xff); pd->msg = usr_msg; pd->pos = -1; @@ -627,8 +654,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } - /* Use platformd data bus speed or NORMAL_SPEED */ - pd->bus_speed = NORMAL_SPEED; + /* Use platform data bus speed or STANDARD_MODE */ + pd->bus_speed = STANDARD_MODE; if (pdata && pdata->bus_speed) pd->bus_speed = pdata->bus_speed; @@ -675,8 +702,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_all; } - dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n", - adap->nr, pd->bus_speed); + dev_info(&dev->dev, + "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n", + adap->nr, pd->bus_speed, pd->iccl, pd->icch); of_i2c_register_devices(adap); return 0; -- cgit v1.2.3-59-g8ed1b From ebd5ac165f2aaefb767c53112c2010b0ff3df688 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:58:10 +0900 Subject: i2c: i2c-sh_mobile: support I2C hardware block with a faster operating clock On newer SH-/R-Mobile SoCs, a clock supply to the I2C hardware block, which is used to generate the SCL clock output, is getting faster than before, while on the other hand, the SCL clock control registers, ICCH and ICCL, stay unchanged in 9-bit-wide (8+1). On such silicons, the internal SCL clock counter gets incremented every 2 clocks of the operating clock. This patch makes it configurable through platform data. Signed-off-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 5 +++++ include/linux/i2c/i2c-sh_mobile.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 4dc0cc3611c2..4c283583bea0 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -120,6 +120,7 @@ struct sh_mobile_i2c_data { void __iomem *reg; struct i2c_adapter adap; unsigned long bus_speed; + unsigned int clks_per_count; struct clk *clk; u_int8_t icic; u_int8_t flags; @@ -231,6 +232,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) /* Get clock rate after clock is enabled */ clk_enable(pd->clk); i2c_clk_khz = clk_get_rate(pd->clk) / 1000; + i2c_clk_khz /= pd->clks_per_count; if (pd->bus_speed == STANDARD_MODE) { tLOW = 47; /* tLOW = 4.7 us */ @@ -658,6 +660,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->bus_speed = STANDARD_MODE; 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; /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. diff --git a/include/linux/i2c/i2c-sh_mobile.h b/include/linux/i2c/i2c-sh_mobile.h index beda7081aead..06e3089795fb 100644 --- a/include/linux/i2c/i2c-sh_mobile.h +++ b/include/linux/i2c/i2c-sh_mobile.h @@ -5,6 +5,7 @@ struct i2c_sh_mobile_platform_data { unsigned long bus_speed; + unsigned int clks_per_count; }; #endif /* __I2C_SH_MOBILE_H__ */ -- cgit v1.2.3-59-g8ed1b From 29fb08c300b5cb626b8a803440aab25d0983cab7 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:58:31 +0900 Subject: i2c: i2c-sh_mobile: fix spurious transfer request timed out Ensure that any of preceding register write operations to the I2C hardware block reached the module, and the write data is reflected in the registers, before leaving the interrupt handler. Otherwise, we'll suffer from spurious WAIT interrupts that lead to 'Transfer request timed out' message, and the transaction failed. Reported-by: Teppei Kamijou Signed-off-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 4c283583bea0..9411c1b892c0 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -469,6 +469,9 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) wake_up(&pd->wait); } + /* defeat write posting to avoid spurious WAIT interrupts */ + iic_rd(pd, ICSR); + return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 9b7a0c40de6c5c04371f8cdb9153a0a5a0af5243 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Oct 2012 18:23:53 +0200 Subject: i2c: mux: Add dt support to i2c-mux-gpio driver Allow the i2c-mux-gpio to be used by a device tree enabled device. The bindings are inspired by the one found in the i2c-mux-pinctrl driver. Signed-off-by: Maxime Ripard Reviewed-by: Stephen Warren Acked-by: Peter Korsgaard [wsa: fixed some whitespace] Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++++ drivers/i2c/muxes/i2c-mux-gpio.c | 145 ++++++++++++++++----- 2 files changed, 195 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 000000000000..66709a825541 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios used to control the muxer +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- idle-state: value to set the muxer to when idle. When no value is + given, it defaults to the last value used. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on their order in the device tree. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output using the list of +GPIOs, the first in the list holding the least-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +GPIOs will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made to a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 566a6757a33d..3b7bc06fe8a6 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include struct gpiomux { struct i2c_adapter *parent; @@ -57,29 +59,110 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, return !strcmp(chip->label, data); } +#ifdef CONFIG_OF +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + unsigned *values, *gpios; + int i = 0; + + if (!np) + return -ENODEV; + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(&pdev->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->data.parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data.n_values = of_get_child_count(np); + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.values) * mux->data.n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data.values = values; + + if (of_property_read_u32(np, "idle-state", &mux->data.idle)) + mux->data.idle = I2C_MUX_GPIO_NO_IDLE; + + mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios"); + if (mux->data.n_gpios < 0) { + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); + return -EINVAL; + } + + gpios = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.gpios) * mux->data.n_gpios, GFP_KERNEL); + if (!gpios) { + dev_err(&pdev->dev, "Cannot allocate gpios array"); + return -ENOMEM; + } + + for (i = 0; i < mux->data.n_gpios; i++) + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); + + mux->data.gpios = gpios; + + return 0; +} +#else +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; - struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); unsigned initial_state, gpio_base; int i, ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENODEV; + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); + return -ENOMEM; } + platform_set_drvdata(pdev, mux); + + if (!pdev->dev.platform_data) { + ret = i2c_mux_gpio_probe_dt(mux, pdev); + if (ret < 0) + return ret; + } else + memcpy(&mux->data, pdev->dev.platform_data, sizeof(mux->data)); + /* * If a GPIO chip name is provided, the GPIO pin numbers provided are * relative to its base GPIO number. Otherwise they are absolute. */ - if (pdata->gpio_chip) { + if (mux->data.gpio_chip) { struct gpio_chip *gpio; - gpio = gpiochip_find(pdata->gpio_chip, + gpio = gpiochip_find(mux->data.gpio_chip, match_gpio_chip_by_label); if (!gpio) return -EPROBE_DEFER; @@ -89,49 +172,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) gpio_base = 0; } - parent = i2c_get_adapter(pdata->parent); + parent = i2c_get_adapter(mux->data.parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - pdata->parent); + mux->data.parent); return -ENODEV; } - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); - if (!mux) { - ret = -ENOMEM; - goto alloc_failed; - } - mux->parent = parent; - mux->data = *pdata; mux->gpio_base = gpio_base; + mux->adap = devm_kzalloc(&pdev->dev, - sizeof(*mux->adap) * pdata->n_values, + sizeof(*mux->adap) * mux->data.n_values, GFP_KERNEL); if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); ret = -ENOMEM; goto alloc_failed; } - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { - initial_state = pdata->idle; + if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { + initial_state = mux->data.idle; deselect = i2c_mux_gpio_deselect; } else { - initial_state = pdata->values[0]; + initial_state = mux->data.values[0]; deselect = NULL; } - for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); + for (i = 0; i < mux->data.n_gpios; i++) { + ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(gpio_base + pdata->gpios[i], + gpio_direction_output(gpio_base + mux->data.gpios[i], initial_state & (1 << i)); } - for (i = 0; i < pdata->n_values; i++) { - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; - unsigned int class = pdata->classes ? pdata->classes[i] : 0; + for (i = 0; i < mux->data.n_values; i++) { + u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; + unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, class, @@ -144,19 +222,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%d port mux on %s adapter\n", - pdata->n_values, parent->name); - - platform_set_drvdata(pdev, mux); + mux->data.n_values, parent->name); return 0; add_adapter_failed: for (; i > 0; i--) i2c_del_mux_adapter(mux->adap[i - 1]); - i = pdata->n_gpios; + i = mux->data.n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(gpio_base + pdata->gpios[i - 1]); + gpio_free(gpio_base + mux->data.gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -180,12 +256,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { + { .compatible = "i2c-mux-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); + static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, .remove = __devexit_p(i2c_mux_gpio_remove), .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), }, }; -- cgit v1.2.3-59-g8ed1b From 2935e0e05a3e348f046f1b485e933b85d1479aaa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Nov 2012 09:33:38 +0100 Subject: i2c: s3c2410: Refactor ifdefs for PM_SLEEP Use the PM_SLEEP ifdef for system suspend and resume. This is partly in preparation for adding runtime operations and partly because a user may in theory choose to enable runtime suspend but not system suspend. Signed-off-by: Mark Brown Reviewed-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e0335f1fc60..f01cdf35f4c9 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1118,7 +1118,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int s3c24xx_i2c_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1141,10 +1141,14 @@ static int s3c24xx_i2c_resume(struct device *dev) return 0; } +#endif +#ifdef CONFIG_PM static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { +#ifdef CONFIG_PM_SLEEP .suspend_noirq = s3c24xx_i2c_suspend_noirq, .resume = s3c24xx_i2c_resume, +#endif }; #define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops) -- cgit v1.2.3-59-g8ed1b From a72ad456bb93a0114b4d6702421b35a9c548bd46 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Nov 2012 09:33:39 +0100 Subject: i2c: s3c2410: Convert to devm_request_and_ioremap() A small code saving and less error handling to worry about. Signed-off-by: Mark Brown Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index f01cdf35f4c9..f82d11f9b8f2 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -78,7 +78,6 @@ struct s3c24xx_i2c { void __iomem *regs; struct clk *clk; struct device *dev; - struct resource *ioarea; struct i2c_adapter adap; struct s3c2410_platform_i2c *pdata; @@ -988,25 +987,16 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) 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)); + i2c->regs = devm_request_and_ioremap(&pdev->dev, res); if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); ret = -ENXIO; - goto err_ioarea; + goto err_clk; } - dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", - i2c->regs, i2c->ioarea, res); + dev_dbg(&pdev->dev, "registers %p (%p)\n", + i2c->regs, res); /* setup info block for the i2c core */ @@ -1017,7 +1007,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_init(i2c); if (ret != 0) - goto err_iomap; + goto err_clk; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending @@ -1026,7 +1016,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->irq = ret = platform_get_irq(pdev, 0); if (ret <= 0) { dev_err(&pdev->dev, "cannot find IRQ\n"); - goto err_iomap; + goto err_clk; } ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, @@ -1034,7 +1024,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_iomap; + goto err_clk; } ret = s3c24xx_i2c_register_cpufreq(i2c); @@ -1074,13 +1064,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) 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_unprepare(i2c->clk); clk_put(i2c->clk); @@ -1109,11 +1092,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); - iounmap(i2c->regs); - - release_resource(i2c->ioarea); s3c24xx_i2c_dt_gpio_free(i2c); - kfree(i2c->ioarea); return 0; } -- cgit v1.2.3-59-g8ed1b From 2693ac69880a33d4d9df6f128415b65e745f00ba Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 13 Nov 2012 11:33:40 +0100 Subject: i2c: s3c2410: Add support for pinctrl This patch adds support for pin configuration using pinctrl subsystem to the i2c-s3c2410 driver. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/samsung-i2c.txt | 20 ++++++++++++++++---- drivers/i2c/busses/i2c-s3c2410.c | 12 ++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/samsung-i2c.txt b/Documentation/devicetree/bindings/i2c/samsung-i2c.txt index b6cb5a12c672..e9611ace8792 100644 --- a/Documentation/devicetree/bindings/i2c/samsung-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/samsung-i2c.txt @@ -13,11 +13,17 @@ Required properties: - interrupts: interrupt number to the cpu. - samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges. +Required for all cases except "samsung,s3c2440-hdmiphy-i2c": + - Samsung GPIO variant (deprecated): + - gpios: The order of the gpios should be the following: . + The gpio specifier depends on the gpio controller. Required in all + cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output + lines are permanently wired to the respective clienta + - Pinctrl variant (preferred, if available): + - pinctrl-0: Pin control group to be used for this controller. + - pinctrl-names: Should contain only one value - "default". + Optional properties: - - gpios: The order of the gpios should be the following: . - The gpio specifier depends on the gpio controller. Required in all - cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output - lines are permanently wired to the respective client - samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not specified, default value is 0. - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not @@ -31,8 +37,14 @@ Example: interrupts = <345>; samsung,i2c-sda-delay = <100>; samsung,i2c-max-bus-freq = <100000>; + /* Samsung GPIO variant begins here */ gpios = <&gpd1 2 0 /* SDA */ &gpd1 3 0 /* SCL */>; + /* Samsung GPIO variant ends here */ + /* Pinctrl variant begins here */ + pinctrl-0 = <&i2c3_bus>; + pinctrl-names = "default"; + /* Pinctrl variant ends here */ #address-cells = <1>; #size-cells = <0>; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index f82d11f9b8f2..40e2d40bbdb5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -82,6 +83,7 @@ struct s3c24xx_i2c { struct s3c2410_platform_i2c *pdata; int gpios[2]; + struct pinctrl *pctrl; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif @@ -860,9 +862,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) if (pdata->cfg_gpio) pdata->cfg_gpio(to_platform_device(i2c->dev)); - else - if (s3c24xx_i2c_parse_dt_gpio(i2c)) - return -EINVAL; + else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) + return -EINVAL; /* write slave address */ @@ -1003,6 +1004,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; + i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev); + /* initialise the i2c controller */ ret = s3c24xx_i2c_init(i2c); @@ -1092,7 +1095,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); - s3c24xx_i2c_dt_gpio_free(i2c); + if (pdev->dev.of_node && IS_ERR(i2c->pctrl)) + s3c24xx_i2c_dt_gpio_free(i2c); return 0; } -- cgit v1.2.3-59-g8ed1b From 9bcd04bfbbd5599de011176b846ed00ac15a234c Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:30 +0530 Subject: i2c: s3c2410: grab adapter lock while changing i2c clock We probably don't want to change I2C frequency while a transfer is in progress. The current implementation grabs a spinlock, but that only protected the writes to IICCON when starting a message, it didn't protect against clock changes in the middle of a transaction. Note: The i2c-core already grabs the adapter lock before calling s3c24xx_i2c_doxfer(), which ensures that only one caller is issuing a xfer at a time. This means it is not necessary to disable interrupts (spin_lock_irqsave) when changing frequencies, since there won't be any i2c interrupts if there is no on-going xfer. Lastly, i2c_lock_adapter() may cause the cpufreq_transition to sleep if if a xfer is in progress, but this is ok since cpufreq notifiers are called in a kernel thread, and there are already cases where it could sleep, such as when using i2c to update the output of a voltage regulator. Note: the cpufreq part of this change has no functional affect on exynos, where the i2c clock is independent of the cpufreq. But, there is a slight perfomance boost since we no longer need to lock/unlock an additional spinlock. Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 40e2d40bbdb5..86e60f598c51 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -60,7 +60,6 @@ enum s3c24xx_i2c_state { }; struct s3c24xx_i2c { - spinlock_t lock; wait_queue_head_t wait; unsigned int quirks; unsigned int suspended:1; @@ -541,8 +540,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, goto out; } - spin_lock_irq(&i2c->lock); - i2c->msg = msgs; i2c->msg_num = num; i2c->msg_ptr = 0; @@ -551,7 +548,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_enable_irq(i2c); s3c24xx_i2c_message_start(i2c, msgs); - spin_unlock_irq(&i2c->lock); timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); @@ -741,7 +737,6 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { struct s3c24xx_i2c *i2c = freq_to_i2c(nb); - unsigned long flags; unsigned int got; int delta_f; int ret; @@ -755,9 +750,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || (val == CPUFREQ_PRECHANGE && delta_f > 0)) { - spin_lock_irqsave(&i2c->lock, flags); + i2c_lock_adapter(&i2c->adap); ret = s3c24xx_i2c_clockrate(i2c, &got); - spin_unlock_irqrestore(&i2c->lock, flags); + i2c_unlock_adapter(&i2c->adap); if (ret < 0) dev_err(i2c->dev, "cannot find frequency\n"); @@ -962,7 +957,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; i2c->tx_setup = 50; - spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); /* find the clock and enable it */ -- cgit v1.2.3-59-g8ed1b From 0da2e7768b4c2b4dbbb148ebe1606b6b4698fca2 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:31 +0530 Subject: i2c: s3c2410: do not generate STOP for QUIRK_HDMIPHY The datasheet says that the STOP sequence should be: 1) I2CSTAT.5 = 0 - Clear BUSY (or 'generate STOP') 2) I2CCON.4 = 0 - Clear IRQPEND 3) Wait until the stop condition takes effect. 4*) I2CSTAT.4 = 0 - Clear TXRXEN Where, step "4*" is only for buses with the "HDMIPHY" quirk. However, after much experimentation, it appears that: a) normal buses automatically clear BUSY and transition from Master->Slave when they complete generating a STOP condition. Therefore, step (3) can be done in doxfer() by polling I2CCON.4 after starting the STOP generation here. b) HDMIPHY bus does neither, so there is no way to do step 3. There is no indication when this bus has finished generating STOP. In fact, we have found that as soon as the IRQPEND bit is cleared in step 2, the HDMIPHY bus generates the STOP condition, and then immediately starts transferring another data byte, even though the bus is supposedly stopped. This is presumably because the bus is still in "Master" mode, and its BUSY bit is still set. To avoid these extra post-STOP transactions on HDMI phy devices, we just disable Serial Output on the bus (I2CSTAT.4 = 0) directly, instead of first generating a proper STOP condition. This should float SDA & SCK terminating the transfer. Subsequent transfers start with a proper START condition, and proceed normally. The HDMIPHY bus is an internal bus that always has exactly two devices, the host as Master and the HDMIPHY device as the slave. Skipping the STOP condition has been tested on this bus and works. Also, since we disable the bus directly from the isr, we can skip the bus idle polling loop at the end of doxfer(). Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 86e60f598c51..a44e2130d3e0 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -235,8 +235,47 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) dev_dbg(i2c->dev, "STOP\n"); - /* stop the transfer */ - iicstat &= ~S3C2410_IICSTAT_START; + /* + * The datasheet says that the STOP sequence should be: + * 1) I2CSTAT.5 = 0 - Clear BUSY (or 'generate STOP') + * 2) I2CCON.4 = 0 - Clear IRQPEND + * 3) Wait until the stop condition takes effect. + * 4*) I2CSTAT.4 = 0 - Clear TXRXEN + * + * Where, step "4*" is only for buses with the "HDMIPHY" quirk. + * + * However, after much experimentation, it appears that: + * a) normal buses automatically clear BUSY and transition from + * Master->Slave when they complete generating a STOP condition. + * Therefore, step (3) can be done in doxfer() by polling I2CCON.4 + * after starting the STOP generation here. + * b) HDMIPHY bus does neither, so there is no way to do step 3. + * There is no indication when this bus has finished generating + * STOP. + * + * In fact, we have found that as soon as the IRQPEND bit is cleared in + * step 2, the HDMIPHY bus generates the STOP condition, and then + * immediately starts transferring another data byte, even though the + * bus is supposedly stopped. This is presumably because the bus is + * still in "Master" mode, and its BUSY bit is still set. + * + * To avoid these extra post-STOP transactions on HDMI phy devices, we + * just disable Serial Output on the bus (I2CSTAT.4 = 0) directly, + * instead of first generating a proper STOP condition. This should + * float SDA & SCK terminating the transfer. Subsequent transfers + * start with a proper START condition, and proceed normally. + * + * The HDMIPHY bus is an internal bus that always has exactly two + * devices, the host as Master and the HDMIPHY device as the slave. + * Skipping the STOP condition has been tested on this bus and works. + */ + if (i2c->quirks & QUIRK_HDMIPHY) { + /* Stop driving the I2C pins */ + iicstat &= ~S3C2410_IICSTAT_TXRXEN; + } else { + /* stop the transfer */ + iicstat &= ~S3C2410_IICSTAT_START; + } writel(iicstat, i2c->regs + S3C2410_IICSTAT); i2c->state = STATE_STOP; @@ -561,6 +600,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, else if (ret != num) dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + /* For QUIRK_HDMIPHY, bus is already disabled */ + if (i2c->quirks & QUIRK_HDMIPHY) + goto out; + /* ensure the stop has been through the bus */ dev_dbg(i2c->dev, "waiting for bus idle\n"); -- cgit v1.2.3-59-g8ed1b From fe724bf9f023384eb14431c0e49ec46017ba8e30 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:32 +0530 Subject: i2c: s3c2410: use exponential back off while polling for bus idle Usually, the i2c controller has finished emitting the i2c STOP before the driver reaches the bus idle polling loop. Optimize for this most common case by reading IICSTAT first and potentially skipping the loop. If the cpu is faster than the hardware, we wait for bus idle in a polling loop. However, since the duration of one iteration of the loop is dependent on cpu freq, and this i2c IP is used on many different systems, use a time based loop timeout (5 ms). We would like very low latencies to detect bus idle for the normal 'fast' case. However, if a device is slow to release the bus for some reason, it could hold off the STOP generation for up to several milliseconds. Rapidly polling for bus idle would seriously load the CPU while waiting for it to release the bus. So, use a partial exponential backoff as a compromise between idle detection latency and cpu load. Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 67 ++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index a44e2130d3e0..dd93d3d6510a 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -50,6 +50,9 @@ #define QUIRK_HDMIPHY (1 << 1) #define QUIRK_NO_GPIO (1 << 2) +/* Max time to wait for bus to become idle after a xfer (in us) */ +#define S3C2410_IDLE_TIMEOUT 5000 + /* i2c controller state */ enum s3c24xx_i2c_state { STATE_IDLE, @@ -557,6 +560,48 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) return -ETIMEDOUT; } +/* s3c24xx_i2c_wait_idle + * + * wait for the i2c bus to become idle. +*/ + +static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) +{ + unsigned long iicstat; + ktime_t start, now; + unsigned long delay; + + /* ensure the stop has been through the bus */ + + dev_dbg(i2c->dev, "waiting for bus idle\n"); + + start = now = ktime_get(); + + /* + * Most of the time, the bus is already idle within a few usec of the + * end of a transaction. However, really slow i2c devices can stretch + * the clock, delaying STOP generation. + * + * As a compromise between idle detection latency for the normal, fast + * case, and system load in the slow device case, use an exponential + * back off in the polling loop, up to 1/10th of the total timeout, + * then continue to poll at a constant rate up to the timeout. + */ + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + delay = 1; + while ((iicstat & S3C2410_IICSTAT_START) && + ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) { + usleep_range(delay, 2 * delay); + if (delay < S3C2410_IDLE_TIMEOUT / 10) + delay <<= 1; + now = ktime_get(); + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } + + if (iicstat & S3C2410_IICSTAT_START) + dev_warn(i2c->dev, "timeout waiting for bus idle\n"); +} + /* s3c24xx_i2c_doxfer * * this starts an i2c transfer @@ -565,8 +610,7 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long iicstat, timeout; - int spins = 20; + unsigned long timeout; int ret; if (i2c->suspended) @@ -604,24 +648,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, if (i2c->quirks & QUIRK_HDMIPHY) goto out; - /* ensure the stop has been through the bus */ - - dev_dbg(i2c->dev, "waiting for bus idle\n"); - - /* first, try busy waiting briefly */ - do { - cpu_relax(); - iicstat = readl(i2c->regs + S3C2410_IICSTAT); - } while ((iicstat & S3C2410_IICSTAT_START) && --spins); - - /* if that timed out sleep */ - if (!spins) { - msleep(1); - iicstat = readl(i2c->regs + S3C2410_IICSTAT); - } - - if (iicstat & S3C2410_IICSTAT_START) - dev_warn(i2c->dev, "timeout waiting for bus idle\n"); + s3c24xx_i2c_wait_idle(i2c); out: return ret; -- cgit v1.2.3-59-g8ed1b From 79f678edfe48db1f234b8de41e24987d6d25ac1a Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:33 +0530 Subject: i2c: s3c2410: do not special case HDMIPHY stuck bus detection Commit "i2c-s3c2410: Add HDMIPHY quirk for S3C2440" added support for HDMIPHY with some special handling in s3c24xx_i2c_set_master: "due to unknown reason (probably HW bug in HDMIPHY and/or the controller) a transfer fails to finish. The controller hangs after sending the last byte, the workaround for this bug is resetting the controller after each transfer" The "unknown reason" was that the proper sequence for generating a STOP condition wasn't being followed as per the datasheet. Since this is fixed by "PATCH: i2c-s3c2410: do not generate STOP for QUIRK_HDMIPHY buses", remove the special handling. Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index dd93d3d6510a..081e261ac847 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -532,13 +532,6 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) unsigned long iicstat; int timeout = 400; - /* the timeout for HDMIPHY is reduced to 10 ms because - * the hangup is expected to happen, so waiting 400 ms - * causes only unnecessary system hangup - */ - if (i2c->quirks & QUIRK_HDMIPHY) - timeout = 10; - while (timeout-- > 0) { iicstat = readl(i2c->regs + S3C2410_IICSTAT); @@ -548,15 +541,6 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) msleep(1); } - /* hang-up of bus dedicated for HDMIPHY occurred, resetting */ - if (i2c->quirks & QUIRK_HDMIPHY) { - writel(0, i2c->regs + S3C2410_IICCON); - writel(0, i2c->regs + S3C2410_IICSTAT); - writel(0, i2c->regs + S3C2410_IICDS); - - return 0; - } - return -ETIMEDOUT; } -- cgit v1.2.3-59-g8ed1b From 06e9eff129ec4251e5335ecaebe1aabba78091b6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Oct 2012 18:23:54 +0200 Subject: ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 This will allow to add the 3 Nuvoton NAU7802 ADCs and the NXP PCA9555 GPIO expander eventually. Signed-off-by: Maxime Ripard Acked-by: Shawn Guo Signed-off-by: Wolfram Sang --- arch/arm/boot/dts/imx28-cfa10049.dts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts index 05c892e931e3..319a6dbd9343 100644 --- a/arch/arm/boot/dts/imx28-cfa10049.dts +++ b/arch/arm/boot/dts/imx28-cfa10049.dts @@ -70,6 +70,30 @@ status = "okay"; }; + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@0 { + reg = <0>; + }; + + i2c@1 { + reg = <1>; + }; + + i2c@2 { + reg = <2>; + }; + + i2c@3 { + reg = <3>; + }; + }; + usbphy1: usbphy@8007e000 { status = "okay"; }; -- cgit v1.2.3-59-g8ed1b From 1ab3604595af478e9feea430318c22899015550c Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 15 Nov 2012 14:19:21 +0530 Subject: i2c: omap: Move the remove constraint Currently we just queue the transfer and release the qos constraints, however we do not wait for the transfer to complete to release the constraint. Move the remove constraint after the bus busy as we are sure that the transfers are completed by then. Acked-by: Jean Pihet Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 49b12fb00c90..248280136668 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -654,13 +654,14 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); - if (r == 0) r = num; omap_i2c_wait_for_bb(dev); + + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); + out: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); -- cgit v1.2.3-59-g8ed1b From f5f35a92e44a1f70fd8c77a42339318a5c8d9eb7 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 15 Nov 2012 16:50:58 +0100 Subject: i2c: ocores: Add irq support for sparc Add sparc support by using platform_get_irq instead of platform_get_resource. There are no platform resources of type IORESOURCE_IRQ for sparc, but platform_get_irq works for sparc. In the non-sparc case platform_get_irq internally uses platform_get_resource. Signed-off-by: Andreas Larsson Acked-by: Peter Korsgaard Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1fad4aeb7902..dafd26beecbb 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -267,7 +267,8 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) { struct ocores_i2c *i2c; struct ocores_i2c_platform_data *pdata; - struct resource *res, *res2; + struct resource *res; + int irq; int ret; int i; @@ -275,9 +276,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!res) return -ENODEV; - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) @@ -304,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) ocores_init(i2c); init_waitqueue_head(&i2c->wait); - ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, pdev->name, i2c); if (ret) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); -- cgit v1.2.3-59-g8ed1b From a000b8c1e30115800d3de86b4b058cadd9cba59d Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 15 Nov 2012 16:50:59 +0100 Subject: i2c: ocores: Add support for the GRLIB port of the controller and use function pointers for getreg and setreg functions The registers in the GRLIB port of the controller are 32-bit and in big endian byte order. The PRELOW and PREHIGH registers are merged into one register. The subsequent registers have their offset decreased accordingly. Hence the register access needs to be handled in a non-standard manner using custom getreg and setreg functions. Add setreg and getreg functions for different register widths and let oc_setreg and oc_getreg use function pointers to call the appropriate functions. A type is added as the data of the of match table entries. A new entry with a different compatible string is added to the table. The type of that entry triggers usage of the custom grlib functions by setting the setreg and getreg function pointers. Signed-off-by: Andreas Larsson Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 2 +- drivers/i2c/busses/i2c-ocores.c | 138 ++++++++++++++++++--- 2 files changed, 121 insertions(+), 19 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index c15781f4dc8c..1637c298a1b3 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -1,7 +1,7 @@ Device tree configuration for i2c-ocores Required properties: -- compatible : "opencores,i2c-ocores" +- compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst" - reg : bus address start and address range size of device - interrupts : interrupt number - clock-frequency : frequency of bus clock in Hz diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index dafd26beecbb..0ea84199b507 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -4,6 +4,9 @@ * * Peter Korsgaard * + * Support for the GRLIB port of the controller by + * Andreas Larsson + * * 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. @@ -38,6 +41,8 @@ struct ocores_i2c { int nmsgs; int state; /* see STATE_ */ int clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); }; /* registers */ @@ -71,24 +76,81 @@ struct ocores_i2c { #define STATE_READ 3 #define STATE_ERROR 4 -static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) { - if (i2c->reg_io_width == 4) - iowrite32(value, i2c->base + (reg << i2c->reg_shift)); - else if (i2c->reg_io_width == 2) - iowrite16(value, i2c->base + (reg << i2c->reg_shift)); + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +/* Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers has their offset decreased accordingly. */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); else - iowrite8(value, i2c->base + (reg << i2c->reg_shift)); + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + i2c->setreg(i2c, reg, value); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - if (i2c->reg_io_width == 4) - return ioread32(i2c->base + (reg << i2c->reg_shift)); - else if (i2c->reg_io_width == 2) - return ioread16(i2c->base + (reg << i2c->reg_shift)); - else - return ioread8(i2c->base + (reg << i2c->reg_shift)); + return i2c->getreg(i2c, reg); } static void ocores_process(struct ocores_i2c *i2c) @@ -227,11 +289,25 @@ static struct i2c_adapter ocores_adapter = { .algo = &ocores_algorithm, }; +static struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + #ifdef CONFIG_OF static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; u32 val; if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { @@ -257,6 +333,14 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, of_property_read_u32(pdev->dev.of_node, "reg-io-width", &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (int)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + return 0; } #else @@ -302,6 +386,30 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (i2c->reg_io_width == 0) i2c->reg_io_width = 1; /* Set to default value */ + if (!i2c->setreg || !i2c->getreg) { + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = oc_setreg_16; + i2c->getreg = oc_getreg_16; + break; + + case 4: + i2c->setreg = oc_setreg_32; + i2c->getreg = oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + return -EINVAL; + } + } + ocores_init(i2c); init_waitqueue_head(&i2c->wait); @@ -379,12 +487,6 @@ static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); #define OCORES_I2C_PM NULL #endif -static struct of_device_id ocores_i2c_match[] = { - { .compatible = "opencores,i2c-ocores", }, - {}, -}; -MODULE_DEVICE_TABLE(of, ocores_i2c_match); - static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, .remove = __devexit_p(ocores_i2c_remove), -- cgit v1.2.3-59-g8ed1b From 0857ba3c24c308f42a242fe8a1894772750230ce Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 18 Nov 2012 18:36:19 +0200 Subject: i2c: i2c-cbus-gpio: introduce driver Add i2c driver to enable access to devices behind CBUS on Nokia Internet Tablets. The patch also adds CBUS I2C configuration for N8x0 which is one of the users of this driver. Acked-by: Felipe Balbi Acked-by: Tony Lindgren Signed-off-by: Aaro Koskinen Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-cbus-gpio.txt | 27 ++ arch/arm/mach-omap2/board-n8x0.c | 42 +++ drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-cbus-gpio.c | 300 +++++++++++++++++++++ include/linux/platform_data/i2c-cbus-gpio.h | 27 ++ 6 files changed, 407 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt create mode 100644 drivers/i2c/busses/i2c-cbus-gpio.c create mode 100644 include/linux/platform_data/i2c-cbus-gpio.h diff --git a/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt new file mode 100644 index 000000000000..8ce9cd2855b5 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt @@ -0,0 +1,27 @@ +Device tree bindings for i2c-cbus-gpio driver + +Required properties: + - compatible = "i2c-cbus-gpio"; + - gpios: clk, dat, sel + - #address-cells = <1>; + - #size-cells = <0>; + +Optional properties: + - child nodes conforming to i2c bus binding + +Example: + +i2c@0 { + compatible = "i2c-cbus-gpio"; + gpios = <&gpio 66 0 /* clk */ + &gpio 65 0 /* dat */ + &gpio 64 0 /* sel */ + >; + #address-cells = <1>; + #size-cells = <0>; + + retu-mfd: retu@1 { + compatible = "retu-mfd"; + reg = <0x1>; + }; +}; diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index d95f727ca39a..bbfd74263c42 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -39,6 +41,45 @@ #define TUSB6010_GPIO_ENABLE 0 #define TUSB6010_DMACHAN 0x3f +#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE) +static struct i2c_cbus_platform_data n8x0_cbus_data = { + .clk_gpio = 66, + .dat_gpio = 65, + .sel_gpio = 64, +}; + +static struct platform_device n8x0_cbus_device = { + .name = "i2c-cbus-gpio", + .id = 3, + .dev = { + .platform_data = &n8x0_cbus_data, + }, +}; + +static struct i2c_board_info n8x0_i2c_board_info_3[] __initdata = { + { + I2C_BOARD_INFO("retu-mfd", 0x01), + }, +}; + +static void __init n8x0_cbus_init(void) +{ + const int retu_irq_gpio = 108; + + if (gpio_request_one(retu_irq_gpio, GPIOF_IN, "Retu IRQ")) + return; + irq_set_irq_type(gpio_to_irq(retu_irq_gpio), IRQ_TYPE_EDGE_RISING); + n8x0_i2c_board_info_3[0].irq = gpio_to_irq(retu_irq_gpio); + i2c_register_board_info(3, n8x0_i2c_board_info_3, + ARRAY_SIZE(n8x0_i2c_board_info_3)); + platform_device_register(&n8x0_cbus_device); +} +#else /* CONFIG_I2C_CBUS_GPIO */ +static void __init n8x0_cbus_init(void) +{ +} +#endif /* CONFIG_I2C_CBUS_GPIO */ + #if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) /* * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and @@ -677,6 +718,7 @@ static void __init n8x0_init_machine(void) gpmc_onenand_init(board_onenand_data); n8x0_mmc_init(); n8x0_usb_init(); + n8x0_cbus_init(); } MACHINE_START(NOKIA_N800, "Nokia N800") diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e9df4612b7eb..e949edf644d4 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -337,6 +337,16 @@ config I2C_BLACKFIN_TWI_CLK_KHZ help The unit of the TWI clock is kHz. +config I2C_CBUS_GPIO + tristate "CBUS I2C driver" + depends on GENERIC_GPIO + help + Support for CBUS access using I2C API. Mostly relevant for Nokia + Internet Tablets (770, N800 and N810). + + This driver can also be built as a module. If so, the module + will be called i2c-cbus-gpio. + config I2C_CPM tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)" depends on (CPM1 || CPM2) && OF_I2C diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 395b516ffa08..f9e3e0b5c827 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o +obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c new file mode 100644 index 000000000000..98386d659318 --- /dev/null +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -0,0 +1,300 @@ +/* + * CBUS I2C driver for Nokia Internet Tablets. + * + * Copyright (C) 2004-2010 Nokia Corporation + * + * Based on code written by Juha Yrjölä, David Weinehall, Mikko Ylinen and + * Felipe Balbi. Converted to I2C driver by Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Bit counts are derived from Nokia implementation. These should be checked + * if other CBUS implementations appear. + */ +#define CBUS_ADDR_BITS 3 +#define CBUS_REG_BITS 5 + +struct cbus_host { + spinlock_t lock; /* host lock */ + struct device *dev; + int clk_gpio; + int dat_gpio; + int sel_gpio; +}; + +/** + * cbus_send_bit - sends one bit over the bus + * @host: the host we're using + * @bit: one bit of information to send + */ +static void cbus_send_bit(struct cbus_host *host, unsigned bit) +{ + gpio_set_value(host->dat_gpio, bit ? 1 : 0); + gpio_set_value(host->clk_gpio, 1); + gpio_set_value(host->clk_gpio, 0); +} + +/** + * cbus_send_data - sends @len amount of data over the bus + * @host: the host we're using + * @data: the data to send + * @len: size of the transfer + */ +static void cbus_send_data(struct cbus_host *host, unsigned data, unsigned len) +{ + int i; + + for (i = len; i > 0; i--) + cbus_send_bit(host, data & (1 << (i - 1))); +} + +/** + * cbus_receive_bit - receives one bit from the bus + * @host: the host we're using + */ +static int cbus_receive_bit(struct cbus_host *host) +{ + int ret; + + gpio_set_value(host->clk_gpio, 1); + ret = gpio_get_value(host->dat_gpio); + gpio_set_value(host->clk_gpio, 0); + return ret; +} + +/** + * cbus_receive_word - receives 16-bit word from the bus + * @host: the host we're using + */ +static int cbus_receive_word(struct cbus_host *host) +{ + int ret = 0; + int i; + + for (i = 16; i > 0; i--) { + int bit = cbus_receive_bit(host); + + if (bit < 0) + return bit; + + if (bit) + ret |= 1 << (i - 1); + } + return ret; +} + +/** + * cbus_transfer - transfers data over the bus + * @host: the host we're using + * @rw: read/write flag + * @dev: device address + * @reg: register address + * @data: if @rw == I2C_SBUS_WRITE data to send otherwise 0 + */ +static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev, + unsigned reg, unsigned data) +{ + unsigned long flags; + int ret; + + /* We don't want interrupts disturbing our transfer */ + spin_lock_irqsave(&host->lock, flags); + + /* Reset state and start of transfer, SEL stays down during transfer */ + gpio_set_value(host->sel_gpio, 0); + + /* Set the DAT pin to output */ + gpio_direction_output(host->dat_gpio, 1); + + /* Send the device address */ + cbus_send_data(host, dev, CBUS_ADDR_BITS); + + /* Send the rw flag */ + cbus_send_bit(host, rw == I2C_SMBUS_READ); + + /* Send the register address */ + cbus_send_data(host, reg, CBUS_REG_BITS); + + if (rw == I2C_SMBUS_WRITE) { + cbus_send_data(host, data, 16); + ret = 0; + } else { + ret = gpio_direction_input(host->dat_gpio); + if (ret) { + dev_dbg(host->dev, "failed setting direction\n"); + goto out; + } + gpio_set_value(host->clk_gpio, 1); + + ret = cbus_receive_word(host); + if (ret < 0) { + dev_dbg(host->dev, "failed receiving data\n"); + goto out; + } + } + + /* Indicate end of transfer, SEL goes up until next transfer */ + gpio_set_value(host->sel_gpio, 1); + gpio_set_value(host->clk_gpio, 1); + gpio_set_value(host->clk_gpio, 0); + +out: + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} + +static int cbus_i2c_smbus_xfer(struct i2c_adapter *adapter, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data *data) +{ + struct cbus_host *chost = i2c_get_adapdata(adapter); + int ret; + + if (size != I2C_SMBUS_WORD_DATA) + return -EINVAL; + + ret = cbus_transfer(chost, read_write == I2C_SMBUS_READ, addr, + command, data->word); + if (ret < 0) + return ret; + + if (read_write == I2C_SMBUS_READ) + data->word = ret; + + return 0; +} + +static u32 cbus_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; +} + +static const struct i2c_algorithm cbus_i2c_algo = { + .smbus_xfer = cbus_i2c_smbus_xfer, + .functionality = cbus_i2c_func, +}; + +static int cbus_i2c_remove(struct platform_device *pdev) +{ + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + + return i2c_del_adapter(adapter); +} + +static int cbus_i2c_probe(struct platform_device *pdev) +{ + struct i2c_adapter *adapter; + struct cbus_host *chost; + int ret; + + adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter), + GFP_KERNEL); + if (!adapter) + return -ENOMEM; + + chost = devm_kzalloc(&pdev->dev, sizeof(*chost), GFP_KERNEL); + if (!chost) + return -ENOMEM; + + if (pdev->dev.of_node) { + struct device_node *dnode = pdev->dev.of_node; + if (of_gpio_count(dnode) != 3) + return -ENODEV; + chost->clk_gpio = of_get_gpio(dnode, 0); + chost->dat_gpio = of_get_gpio(dnode, 1); + chost->sel_gpio = of_get_gpio(dnode, 2); + } else if (pdev->dev.platform_data) { + struct i2c_cbus_platform_data *pdata = pdev->dev.platform_data; + chost->clk_gpio = pdata->clk_gpio; + chost->dat_gpio = pdata->dat_gpio; + chost->sel_gpio = pdata->sel_gpio; + } else { + return -ENODEV; + } + + adapter->owner = THIS_MODULE; + adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = &pdev->dev; + adapter->nr = pdev->id; + adapter->timeout = HZ; + adapter->algo = &cbus_i2c_algo; + strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name)); + + spin_lock_init(&chost->lock); + chost->dev = &pdev->dev; + + ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio, + GPIOF_OUT_INIT_LOW, "CBUS clk"); + if (ret) + return ret; + + ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN, + "CBUS data"); + if (ret) + return ret; + + ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio, + GPIOF_OUT_INIT_HIGH, "CBUS sel"); + if (ret) + return ret; + + i2c_set_adapdata(adapter, chost); + platform_set_drvdata(pdev, adapter); + + return i2c_add_numbered_adapter(adapter); +} + +#if defined(CONFIG_OF) +static const struct of_device_id i2c_cbus_dt_ids[] = { + { .compatible = "i2c-cbus-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids); +#endif + +static struct platform_driver cbus_i2c_driver = { + .probe = cbus_i2c_probe, + .remove = cbus_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-cbus-gpio", + }, +}; +module_platform_driver(cbus_i2c_driver); + +MODULE_ALIAS("platform:i2c-cbus-gpio"); +MODULE_DESCRIPTION("CBUS I2C driver"); +MODULE_AUTHOR("Juha Yrjölä"); +MODULE_AUTHOR("David Weinehall"); +MODULE_AUTHOR("Mikko Ylinen"); +MODULE_AUTHOR("Felipe Balbi"); +MODULE_AUTHOR("Aaro Koskinen "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/i2c-cbus-gpio.h b/include/linux/platform_data/i2c-cbus-gpio.h new file mode 100644 index 000000000000..6faa992a9502 --- /dev/null +++ b/include/linux/platform_data/i2c-cbus-gpio.h @@ -0,0 +1,27 @@ +/* + * i2c-cbus-gpio.h - CBUS I2C platform_data definition + * + * Copyright (C) 2004-2009 Nokia Corporation + * + * Written by Felipe Balbi and Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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. + */ + +#ifndef __INCLUDE_LINUX_I2C_CBUS_GPIO_H +#define __INCLUDE_LINUX_I2C_CBUS_GPIO_H + +struct i2c_cbus_platform_data { + int dat_gpio; + int clk_gpio; + int sel_gpio; +}; + +#endif /* __INCLUDE_LINUX_I2C_CBUS_GPIO_H */ -- cgit v1.2.3-59-g8ed1b From 3b2f3ceb3c7f4a8c2d11aa7652842e5ce1b0dcc3 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Mon, 19 Nov 2012 15:48:46 +0530 Subject: i2c: s3c2410: Fix code to free gpios Store the requested gpios so that they can be freed on error/removal. Signed-off-by: Abhilash Kesavan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 081e261ac847..16592e5ab08a 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -856,6 +856,7 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); goto free_gpio; } + i2c->gpios[idx] = gpio; ret = gpio_request(gpio, "i2c-bus"); if (ret) { -- cgit v1.2.3-59-g8ed1b From 658122fe5e3a72940631ceda3efcb841054d91dc Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Mon, 19 Nov 2012 15:47:17 +0530 Subject: i2c: s3c2410: Add fix for i2c suspend/resume The I2C driver makes a gpio_request during initialization. This request happens again on resume and fails due to the earlier successful request. Re-factor the code to only initialize the gpios during probe. Errors on resume without this: [ 16.020000] s3c-i2c s3c2440-i2c.0: gpio [42] request failed [ 16.020000] s3c-i2c s3c2440-i2c.1: gpio [44] request failed [ 16.020000] s3c-i2c s3c2440-i2c.2: gpio [6] request failed Signed-off-by: Abhilash Kesavan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 16592e5ab08a..d784c76ae3e8 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -908,13 +908,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) pdata = i2c->pdata; - /* inititalise the gpio */ - - if (pdata->cfg_gpio) - pdata->cfg_gpio(to_platform_device(i2c->dev)); - else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) - return -EINVAL; - /* write slave address */ writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD); @@ -1055,6 +1048,15 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev); + /* inititalise the i2c gpio lines */ + + if (i2c->pdata->cfg_gpio) { + i2c->pdata->cfg_gpio(to_platform_device(i2c->dev)); + } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) { + ret = -EINVAL; + goto err_clk; + } + /* initialise the i2c controller */ ret = s3c24xx_i2c_init(i2c); -- cgit v1.2.3-59-g8ed1b From c5d5474425c4e7e291a98e739ea65f8acd0d8d5c Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Mon, 19 Nov 2012 13:17:48 +0100 Subject: i2c: ocores: Move grlib set/get functions into #ifdef CONFIG_OF block This moves the grlib set and get functions into the #ifdef CONFIG_OF block to avoid warnings of unimplemented functions when compiling with -Wunused-function when CONFIG_OF is not defined. Signed-off-by: Andreas Larsson Acked-by: Peter Korsgaard Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 68 ++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 0ea84199b507..df69598ed28e 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -109,40 +109,6 @@ static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) return ioread32(i2c->base + (reg << i2c->reg_shift)); } -/* Read and write functions for the GRLIB port of the controller. Registers are - * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one - * register. The subsequent registers has their offset decreased accordingly. */ -static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) -{ - u32 rd; - int rreg = reg; - if (reg != OCI2C_PRELOW) - rreg--; - rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); - if (reg == OCI2C_PREHIGH) - return (u8)(rd >> 8); - else - return (u8)rd; -} - -static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) -{ - u32 curr, wr; - int rreg = reg; - if (reg != OCI2C_PRELOW) - rreg--; - if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { - curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); - if (reg == OCI2C_PRELOW) - wr = (curr & 0xff00) | value; - else - wr = (((u32)value) << 8) | (curr & 0xff); - } else { - wr = value; - } - iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); -} - static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { i2c->setreg(i2c, reg, value); @@ -303,6 +269,40 @@ static struct of_device_id ocores_i2c_match[] = { MODULE_DEVICE_TABLE(of, ocores_i2c_match); #ifdef CONFIG_OF +/* Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers has their offset decreased accordingly. */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { -- cgit v1.2.3-59-g8ed1b From 31f313d9bebfc17e48c787c8c36b38662b4134a1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 21 Nov 2012 13:12:11 +0900 Subject: i2c: s3c2410: Remove recently introduced performance overheads The changes in "i2c-s3c2410: use exponential back off while polling for bus idle" remove the initial busy wait for I2C transfers to complete and replace it with usleep_range() calls which will schedule. Since for older SoCs I2C transfers would usually complete within an extremely small number of CPU cycles there is a win from not having to schedule. This happens because on the older SoCs the cores run at a smaller multiple of the speeds that the I2C bus is operating at; on more modern SoCs the busy wait is less likely to be effective. Fix the issue by restoring the busy wait, reducing the number of spins from 20 to 3 which covers the overwhelming majority of I2C transfers on the SoCs where the busy wait is effective. Signed-off-by: Mark Brown Acked-by: Olof Johansson Reviewed-by: Daniel Kurtz Reviewed-by: Doug Anderson Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index d784c76ae3e8..e93e7d672773 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -554,6 +554,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) unsigned long iicstat; ktime_t start, now; unsigned long delay; + int spins; /* ensure the stop has been through the bus */ @@ -566,12 +567,23 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) * end of a transaction. However, really slow i2c devices can stretch * the clock, delaying STOP generation. * - * As a compromise between idle detection latency for the normal, fast - * case, and system load in the slow device case, use an exponential - * back off in the polling loop, up to 1/10th of the total timeout, - * then continue to poll at a constant rate up to the timeout. + * On slower SoCs this typically happens within a very small number of + * instructions so busy wait briefly to avoid scheduling overhead. */ + spins = 3; iicstat = readl(i2c->regs + S3C2410_IICSTAT); + while ((iicstat & S3C2410_IICSTAT_START) && --spins) { + cpu_relax(); + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } + + /* + * If we do get an appreciable delay as a compromise between idle + * detection latency for the normal, fast case, and system load in the + * slow device case, use an exponential back off in the polling loop, + * up to 1/10th of the total timeout, then continue to poll at a + * constant rate up to the timeout. + */ delay = 1; while ((iicstat & S3C2410_IICSTAT_START) && ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) { -- cgit v1.2.3-59-g8ed1b From c35d3cfdbc8d4fb4358a5bc97a334dbdb86e3d69 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 18 Nov 2012 06:25:07 +0100 Subject: i2c: mxs: Handle i2c DMA failure properly Properly terminate the DMA transfer in case the DMA PIO transfer or setup fails for any reason. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 286ca1917820..0670da79ee5e 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -287,12 +287,14 @@ read_init_dma_fail: select_init_dma_fail: dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); select_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; /* Write failpath. */ write_init_dma_fail: dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); write_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 8f414059c66f57f610b71adf66fe20d8811bff8f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 18 Nov 2012 06:25:08 +0100 Subject: i2c: mxs: Do not disable the I2C SMBus quick mode There is no reason to disable the I2C SMBus quick mode on this IP block. Enable it. This essentially fixes the problem with the "i2c-detect" command for probing the bus. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 0670da79ee5e..6ed53da9e1f4 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -359,7 +359,7 @@ static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], static u32 mxs_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) -- cgit v1.2.3-59-g8ed1b From cd32e6ccdda15be1bf5b1b0a52631b06bb243d9e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 23 Nov 2012 17:03:16 +0100 Subject: i2c: at91: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following warning: drivers/i2c/busses/i2c-at91.c: In function ‘at91_twi_get_driver_data’: drivers/i2c/busses/i2c-at91.c:411:3: warning: return discards ‘const’ qualifier from pointer target type [enabled by default] Signed-off-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index c02bf208084f..511bd756f280 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -413,7 +413,7 @@ static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node); if (!match) return NULL; - return match->data; + return (struct at91_twi_pdata *)match->data; } return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data; } -- cgit v1.2.3-59-g8ed1b From 5f433819b3ee4d8603f834e1438462c4ad58b185 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 23 Nov 2012 10:09:03 +0100 Subject: i2c: at91: change struct members indentation Replace tabs for struct members indentation by space to minimise line changes when adding new members which would require extra tabs to keep alignment. Signed-off-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 511bd756f280..4f7577f23142 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -66,24 +66,24 @@ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ struct at91_twi_pdata { - unsigned clk_max_div; - unsigned clk_offset; - bool has_unre_flag; + unsigned clk_max_div; + unsigned clk_offset; + bool has_unre_flag; }; struct at91_twi_dev { - struct device *dev; - void __iomem *base; - struct completion cmd_complete; - struct clk *clk; - u8 *buf; - size_t buf_len; - struct i2c_msg *msg; - int irq; - unsigned transfer_status; - struct i2c_adapter adapter; - unsigned twi_cwgr_reg; - struct at91_twi_pdata *pdata; + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct clk *clk; + u8 *buf; + size_t buf_len; + struct i2c_msg *msg; + int irq; + unsigned transfer_status; + struct i2c_adapter adapter; + unsigned twi_cwgr_reg; + struct at91_twi_pdata *pdata; }; static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) -- cgit v1.2.3-59-g8ed1b From 60937b2cdbf948ddb84cbf5d728012519ff4b321 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 23 Nov 2012 10:09:04 +0100 Subject: i2c: at91: add dma support Add dma support for Atmel TWI which is available on sam9x5 and later. When using dma for reception, you have to read only n-2 bytes. The last two bytes are read manually. Don't doing this should cause to send the STOP command too late and then to get extra data in the receive register. Signed-off-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 306 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 298 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 4f7577f23142..b4575ee4bdf3 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -29,9 +31,11 @@ #include #include #include +#include #define TWI_CLK_HZ 100000 /* max 400 Kbits/s */ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ +#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */ /* AT91 TWI register definitions */ #define AT91_TWI_CR 0x0000 /* Control Register */ @@ -69,6 +73,18 @@ struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; bool has_unre_flag; + bool has_dma_support; + struct at_dma_slave dma_slave; +}; + +struct at91_twi_dma { + struct dma_chan *chan_rx; + struct dma_chan *chan_tx; + struct scatterlist sg; + struct dma_async_tx_descriptor *data_desc; + enum dma_data_direction direction; + bool buf_mapped; + bool xfer_in_progress; }; struct at91_twi_dev { @@ -80,10 +96,13 @@ struct at91_twi_dev { size_t buf_len; struct i2c_msg *msg; int irq; + unsigned imr; unsigned transfer_status; struct i2c_adapter adapter; unsigned twi_cwgr_reg; struct at91_twi_pdata *pdata; + bool use_dma; + struct at91_twi_dma dma; }; static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) @@ -102,6 +121,17 @@ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); } +static void at91_twi_irq_save(struct at91_twi_dev *dev) +{ + dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7; + at91_disable_twi_interrupts(dev); +} + +static void at91_twi_irq_restore(struct at91_twi_dev *dev) +{ + at91_twi_write(dev, AT91_TWI_IER, dev->imr); +} + static void at91_init_twi_bus(struct at91_twi_dev *dev) { at91_disable_twi_interrupts(dev); @@ -138,6 +168,28 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); } +static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) +{ + struct at91_twi_dma *dma = &dev->dma; + + at91_twi_irq_save(dev); + + if (dma->xfer_in_progress) { + if (dma->direction == DMA_FROM_DEVICE) + dmaengine_terminate_all(dma->chan_rx); + else + dmaengine_terminate_all(dma->chan_tx); + dma->xfer_in_progress = false; + } + if (dma->buf_mapped) { + dma_unmap_single(dev->dev, sg_dma_address(&dma->sg), + dev->buf_len, dma->direction); + dma->buf_mapped = false; + } + + at91_twi_irq_restore(dev); +} + static void at91_twi_write_next_byte(struct at91_twi_dev *dev) { if (dev->buf_len <= 0) @@ -154,6 +206,60 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev) ++dev->buf; } +static void at91_twi_write_data_dma_callback(void *data) +{ + struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dev->buf_len, DMA_MEM_TO_DEV); + + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); +} + +static void at91_twi_write_data_dma(struct at91_twi_dev *dev) +{ + dma_addr_t dma_addr; + struct dma_async_tx_descriptor *txdesc; + struct at91_twi_dma *dma = &dev->dma; + struct dma_chan *chan_tx = dma->chan_tx; + + if (dev->buf_len <= 0) + return; + + dma->direction = DMA_TO_DEVICE; + + at91_twi_irq_save(dev); + dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev->dev, dma_addr)) { + dev_err(dev->dev, "dma map failed\n"); + return; + } + dma->buf_mapped = true; + at91_twi_irq_restore(dev); + sg_dma_len(&dma->sg) = dev->buf_len; + sg_dma_address(&dma->sg) = dma_addr; + + txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) { + dev_err(dev->dev, "dma prep slave sg failed\n"); + goto error; + } + + txdesc->callback = at91_twi_write_data_dma_callback; + txdesc->callback_param = dev; + + dma->xfer_in_progress = true; + dmaengine_submit(txdesc); + dma_async_issue_pending(chan_tx); + + return; + +error: + at91_twi_dma_cleanup(dev); +} + static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { if (dev->buf_len <= 0) @@ -179,6 +285,61 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) ++dev->buf; } +static void at91_twi_read_data_dma_callback(void *data) +{ + struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dev->buf_len, DMA_DEV_TO_MEM); + + /* The last two bytes have to be read without using dma */ + dev->buf += dev->buf_len - 2; + dev->buf_len = 2; + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY); +} + +static void at91_twi_read_data_dma(struct at91_twi_dev *dev) +{ + dma_addr_t dma_addr; + struct dma_async_tx_descriptor *rxdesc; + struct at91_twi_dma *dma = &dev->dma; + struct dma_chan *chan_rx = dma->chan_rx; + + dma->direction = DMA_FROM_DEVICE; + + /* Keep in mind that we won't use dma to read the last two bytes */ + at91_twi_irq_save(dev); + dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev->dev, dma_addr)) { + dev_err(dev->dev, "dma map failed\n"); + return; + } + dma->buf_mapped = true; + at91_twi_irq_restore(dev); + dma->sg.dma_address = dma_addr; + sg_dma_len(&dma->sg) = dev->buf_len - 2; + + rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) { + dev_err(dev->dev, "dma prep slave sg failed\n"); + goto error; + } + + rxdesc->callback = at91_twi_read_data_dma_callback; + rxdesc->callback_param = dev; + + dma->xfer_in_progress = true; + dmaengine_submit(rxdesc); + dma_async_issue_pending(dma->chan_rx); + + return; + +error: + at91_twi_dma_cleanup(dev); +} + static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) { struct at91_twi_dev *dev = dev_id; @@ -229,12 +390,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) start_flags |= AT91_TWI_STOP; at91_twi_write(dev, AT91_TWI_CR, start_flags); - at91_twi_write(dev, AT91_TWI_IER, + /* + * When using dma, the last byte has to be read manually in + * order to not send the stop command too late and then + * to receive extra data. In practice, there are some issues + * if you use the dma to read n-1 bytes because of latency. + * Reading n-2 bytes with dma and the two last ones manually + * seems to be the best solution. + */ + if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_read_data_dma(dev); + /* + * It is important to enable TXCOMP irq here because + * doing it only when transferring the last two bytes + * will mask NACK errors since TXCOMP is set when a + * NACK occurs. + */ + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP); + } else + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP | AT91_TWI_RXRDY); } else { - at91_twi_write_next_byte(dev); - at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write_data_dma(dev); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else { + at91_twi_write_next_byte(dev); + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + } } ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, @@ -242,23 +427,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) if (ret == 0) { dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto error; } if (dev->transfer_status & AT91_TWI_NACK) { dev_dbg(dev->dev, "received nack\n"); - return -EREMOTEIO; + ret = -EREMOTEIO; + goto error; } if (dev->transfer_status & AT91_TWI_OVRE) { dev_err(dev->dev, "overrun while reading\n"); - return -EIO; + ret = -EIO; + goto error; } if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) { dev_err(dev->dev, "underrun while writing\n"); - return -EIO; + ret = -EIO; + goto error; } dev_dbg(dev->dev, "transfer complete\n"); return 0; + +error: + at91_twi_dma_cleanup(dev); + return ret; } static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) @@ -329,36 +522,42 @@ static struct at91_twi_pdata at91rm9200_config = { .clk_max_div = 5, .clk_offset = 3, .has_unre_flag = true, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9261_config = { .clk_max_div = 5, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9260_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9g20_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9g10_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9x5_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = true, }; static const struct platform_device_id at91_twi_devtypes[] = { @@ -405,6 +604,90 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); #define atmel_twi_dt_ids NULL #endif +static bool __devinit filter(struct dma_chan *chan, void *slave) +{ + struct at_dma_slave *sl = slave; + + if (sl->dma_dev == chan->device->dev) { + chan->private = sl; + return true; + } else { + return false; + } +} + +static int __devinit at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) +{ + int ret = 0; + struct at_dma_slave *sdata; + struct dma_slave_config slave_config; + struct at91_twi_dma *dma = &dev->dma; + + sdata = &dev->pdata->dma_slave; + + memset(&slave_config, 0, sizeof(slave_config)); + slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_maxburst = 1; + slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_maxburst = 1; + slave_config.device_fc = false; + + if (sdata && sdata->dma_dev) { + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma->chan_tx = dma_request_channel(mask, filter, sdata); + if (!dma->chan_tx) { + dev_err(dev->dev, "no DMA channel available for tx\n"); + ret = -EBUSY; + goto error; + } + dma->chan_rx = dma_request_channel(mask, filter, sdata); + if (!dma->chan_rx) { + dev_err(dev->dev, "no DMA channel available for rx\n"); + ret = -EBUSY; + goto error; + } + } else { + ret = -EINVAL; + goto error; + } + + slave_config.direction = DMA_MEM_TO_DEV; + if (dmaengine_slave_config(dma->chan_tx, &slave_config)) { + dev_err(dev->dev, "failed to configure tx channel\n"); + ret = -EINVAL; + goto error; + } + + slave_config.direction = DMA_DEV_TO_MEM; + if (dmaengine_slave_config(dma->chan_rx, &slave_config)) { + dev_err(dev->dev, "failed to configure rx channel\n"); + ret = -EINVAL; + goto error; + } + + sg_init_table(&dma->sg, 1); + dma->buf_mapped = false; + dma->xfer_in_progress = false; + + dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n", + dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); + + return ret; + +error: + dev_info(dev->dev, "can't use DMA\n"); + if (dma->chan_rx) + dma_release_channel(dma->chan_rx); + if (dma->chan_tx) + dma_release_channel(dma->chan_tx); + return ret; +} + static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( struct platform_device *pdev) { @@ -423,6 +706,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) struct at91_twi_dev *dev; struct resource *mem; int rc; + u32 phy_addr; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -433,6 +717,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -ENODEV; + phy_addr = mem->start; dev->pdata = at91_twi_get_driver_data(pdev); if (!dev->pdata) @@ -462,6 +747,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) } clk_prepare_enable(dev->clk); + if (dev->pdata->has_dma_support) { + if (at91_twi_configure_dma(dev, phy_addr) == 0) + dev->use_dma = true; + } + at91_calc_twi_clock(dev, TWI_CLK_HZ); at91_init_twi_bus(dev); -- cgit v1.2.3-59-g8ed1b From 972deb4f49b5b6703d9c6117ba0aeda2180d4447 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 26 Nov 2012 15:25:11 +0530 Subject: i2c: omap: Remove the OMAP_I2C_FLAG_RESET_REGS_POSTIDLE flag The OMAP_I2C_FLAG_RESET_REGS_POSTIDLE is not used anymore in the i2c driver. Remove the flag. Signed-off-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang --- arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 3 +-- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 9 +++------ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 3 +-- drivers/i2c/busses/i2c-omap.c | 3 +-- include/linux/i2c-omap.h | 1 - 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index 59d5c1cd316d..c9a186bc6d40 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -1103,8 +1103,7 @@ static struct omap_hwmod_class i2c_class = { }; static struct omap_i2c_dev_attr i2c_dev_attr = { - .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE, }; /* i2c1 */ diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 943222c40489..36270bb637e4 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -791,8 +791,7 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = { /* I2C1 */ static struct omap_i2c_dev_attr i2c1_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_hwmod omap3xxx_i2c1_hwmod = { @@ -817,8 +816,7 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = { /* I2C2 */ static struct omap_i2c_dev_attr i2c2_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_hwmod omap3xxx_i2c2_hwmod = { @@ -843,8 +841,7 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = { /* I2C3 */ static struct omap_i2c_dev_attr i2c3_dev_attr = { .fifo_depth = 64, /* bytes */ - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = { diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 652d0285bd6d..eb40dbc6688e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1526,8 +1526,7 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = { }; static struct omap_i2c_dev_attr i2c_dev_attr = { - .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE, }; /* i2c1 */ diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 248280136668..7a62acb7d262 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1038,8 +1038,7 @@ static const struct i2c_algorithm omap_i2c_algo = { #ifdef CONFIG_OF static struct omap_i2c_bus_platform_data omap3_pdata = { .rev = OMAP_I2C_IP_VERSION_1, - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_i2c_bus_platform_data omap4_pdata = { diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 1b25c04f82d9..babe0cf6d56b 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -20,7 +20,6 @@ #define OMAP_I2C_FLAG_NO_FIFO BIT(0) #define OMAP_I2C_FLAG_SIMPLE_CLOCK BIT(1) #define OMAP_I2C_FLAG_16BIT_DATA_REG BIT(2) -#define OMAP_I2C_FLAG_RESET_REGS_POSTIDLE BIT(3) #define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK BIT(5) #define OMAP_I2C_FLAG_FORCE_19200_INT_CLK BIT(6) /* how the CPU address bus must be translated for I2C unit access */ -- cgit v1.2.3-59-g8ed1b