From b37d2a3a75cb0e72e18c29336cb2095b63dabfc8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Jun 2012 07:47:19 -0300 Subject: [media] i2c: Export an unlocked flavor of i2c_transfer Some drivers (in particular for TV cards) need exclusive access to their I2C buses for specific operations. Export an unlocked flavor of i2c_transfer to give them full control. The unlocked flavor has the following limitations: * Obviously, caller must hold the i2c adapter lock. * No debug messages are logged. We don't want to log messages while holding a rt_mutex. * No check is done on the existence of adap->algo->master_xfer. It is thus the caller's responsibility to ensure that the function is OK to call. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/i2c/i2c-core.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index feb7dc359186..ccc6445979c4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1294,6 +1294,37 @@ module_exit(i2c_exit); * ---------------------------------------------------- */ +/** + * __i2c_transfer - unlocked flavor of i2c_transfer + * @adap: Handle to I2C bus + * @msgs: One or more messages to execute before STOP is issued to + * terminate the operation; each message begins with a START. + * @num: Number of messages to be executed. + * + * Returns negative errno, else the number of messages executed. + * + * Adapter lock must be held when calling this function. No debug logging + * takes place. adap->algo->master_xfer existence isn't checked. + */ +int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + unsigned long orig_jiffies; + int ret, try; + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (ret = 0, try = 0; try <= adap->retries; try++) { + ret = adap->algo->master_xfer(adap, msgs, num); + if (ret != -EAGAIN) + break; + if (time_after(jiffies, orig_jiffies + adap->timeout)) + break; + } + + return ret; +} +EXPORT_SYMBOL(__i2c_transfer); + /** * i2c_transfer - execute a single or combined I2C message * @adap: Handle to I2C bus @@ -1308,8 +1339,7 @@ module_exit(i2c_exit); */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - unsigned long orig_jiffies; - int ret, try; + int ret; /* REVISIT the fault reporting model here is weak: * @@ -1347,15 +1377,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) i2c_lock_adapter(adap); } - /* Retry automatically on arbitration loss */ - orig_jiffies = jiffies; - for (ret = 0, try = 0; try <= adap->retries; try++) { - ret = adap->algo->master_xfer(adap, msgs, num); - if (ret != -EAGAIN) - break; - if (time_after(jiffies, orig_jiffies + adap->timeout)) - break; - } + ret = __i2c_transfer(adap, msgs, num); i2c_unlock_adapter(adap); return ret; -- cgit v1.2.3 From 3dae3efb123f8b21df57f426c9c72d6ebcd83f8d Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:13 +0530 Subject: I2C: OMAP: make omap_i2c_unidle/idle functions depend on CONFIG_PM_RUNTIME The functions omap_i2c_unidle/idle are called from omap_i2c_runtime_resume and omap_i2c_runtime_suspend which is compiled for CONFIG_PM_RUNTIME. This patch removes the omap_i2c_unidle/idle functions and folds them into the runtime callbacks. This fixes the below warn when CONFIG_PM_RUNTIME is not defined CC arch/arm/mach-omap2/board-ti8168evm.o drivers/i2c/busses/i2c-omap.c:272: warning: 'omap_i2c_unidle' defined but not used drivers/i2c/busses/i2c-omap.c:293: warning: 'omap_i2c_idle' defined but not used CC net/ipv4/ip_forward.o Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 75 ++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 43 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 801df6000e9b..4f4188de3251 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -269,47 +269,6 @@ 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_unidle(struct omap_i2c_dev *dev) -{ - 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); -} - -static void omap_i2c_idle(struct omap_i2c_dev *dev) -{ - u16 iv; - - dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - if (dev->dtrev == OMAP_I2C_IP_VERSION_2) - omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); - else - 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 */ - } else { - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate); - - /* Flush posted write */ - omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } -} - static int omap_i2c_init(struct omap_i2c_dev *dev) { u16 psc = 0, scll = 0, sclh = 0, buf = 0; @@ -1163,8 +1122,22 @@ 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); + if (_dev->dtrev == OMAP_I2C_IP_VERSION_2) + omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); + else + 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 */ + } else { + omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate); - omap_i2c_idle(_dev); + /* Flush posted write */ + omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG); + } return 0; } @@ -1174,7 +1147,23 @@ 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); - omap_i2c_unidle(_dev); + 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); return 0; } -- cgit v1.2.3 From 247405160093cf88cb59242f877543dd28e93df1 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:14 +0530 Subject: I2C: OMAP: Fix the mismatch of pm_runtime enable and disable Currently the i2c driver calls the pm_runtime_enable and never the disable. This may cause a warning when pm_runtime_enable checks for the count match.Fix the same by calling pm_runtime_disable in the error and the remove path. Cc: Rajendra Nayak Acked-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 4f4188de3251..c851672eb6a8 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1090,6 +1090,7 @@ err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); iounmap(dev->base); + pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); kfree(dev); @@ -1110,6 +1111,7 @@ omap_i2c_remove(struct platform_device *pdev) free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + pm_runtime_disable(&pdev->dev); iounmap(dev->base); kfree(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From bd16c82f67a267b533e747c74c2fcd23578d4601 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:15 +0530 Subject: I2C: OMAP: Fix the interrupt clearing in OMAP4 On OMAP4 we were writing 1 to IRQENABLE_CLR which cleared only the arbitration lost interrupt. The patch intends to fix the same by writing 0 to the IE register clearing all interrupts. This is based on the work done by Vikram Pandita . The changes from the original patch ... - Does not use the IRQENABLE_CLR register to clear as it is not mentioned to be legacy register IRQENABLE_CLR helps in atomically setting/clearing specific interrupts, instead use the OMAP_I2C_IE_REG as we are clearing all interrupts. Cc: Vikram Pandita Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c851672eb6a8..bf07ffd83c1e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1127,10 +1127,8 @@ static int omap_i2c_runtime_suspend(struct device *dev) u16 iv; _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); - if (_dev->dtrev == OMAP_I2C_IP_VERSION_2) - omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); - else - omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); + + 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 */ -- cgit v1.2.3 From 62ff2c2b1a36de9dd98e9b8a575da6e6b2365740 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:16 +0530 Subject: I2C: OMAP: Prevent the register access after pm_runtime_put in probe Currently in probe pm_runtime_put(dev->dev); ... /* i2c device drivers may be active on return from add_adapter() */ adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); goto err_free_irq; } ... return 0; err_free_irq: free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); This may access the i2c registers without the clocks in the error cases. Fix the same by moving the pm_runtime_put after the error check. Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index bf07ffd83c1e..1777d799ee9e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1061,8 +1061,6 @@ omap_i2c_probe(struct platform_device *pdev) dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); - pm_runtime_put(dev->dev); - adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; @@ -1082,6 +1080,8 @@ omap_i2c_probe(struct platform_device *pdev) of_i2c_register_devices(adap); + pm_runtime_put(dev->dev); + return 0; err_free_irq: -- cgit v1.2.3 From 33d549851d2fcb6492429ebfebc344a8988b259d Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:17 +0530 Subject: I2C: OMAP: Don't check if wait_for_completion_timeout() returns less than zero By definition, wait_for_completion_timeout() returns an unsigned value and therefore, it is not necessary to check if the return value is less than zero as this is not possible. This is based on a patch from Jon Hunter Changes from his patch - Declare a long as the wait_for_completion_timeout returns long. Original patch is http://git.omapzoom.org/?p=kernel/omap.git;a=commitdiff;h=ea02cece7b0000bc736e60c4188a11aaa74bc6e6 Reviewed-by: Kevin Hilman Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1777d799ee9e..fec8d5c6f0e5 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -473,7 +473,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { struct omap_i2c_dev *dev = i2c_get_adapdata(adap); - int r; + unsigned long timeout; u16 w; dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", @@ -541,12 +541,10 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ - r = wait_for_completion_timeout(&dev->cmd_complete, - OMAP_I2C_TIMEOUT); + timeout = wait_for_completion_timeout(&dev->cmd_complete, + OMAP_I2C_TIMEOUT); dev->buf_len = 0; - if (r < 0) - return r; - if (r == 0) { + if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); return -ETIMEDOUT; -- cgit v1.2.3 From 0861f430893e0b6fe980a71cdc5fb444b952b8e1 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:18 +0530 Subject: I2C: OMAP: Fix the crash in i2c remove In omap_i2c_remove we are accessing the I2C_CON register without enabling the clocks. Fix the same by ensure device is accessible by calling pm_runtime_get_sync before accessing the registers and calling pm_runtime_put after accessing. This fixes the following crash. [ 154.723022] ------------[ cut here ]------------ [ 154.725677] WARNING: at arch/arm/mach-omap2/omap_l3_noc.c:112 l3_interrupt_handler+0x1b4/0x1c4() [ 154.725677] L3 custom error: MASTER:MPU TARGET:L4 PER2 [ 154.742614] Modules linked in: i2c_omap(-) [ 154.746948] Backtrace: [ 154.746948] [] (dump_backtrace+0x0/0x110) from [] (dump_stack+0x18/0x1c) [ 154.752716] r6:00000070 r5:c002c43c r4:df9b9e98 r3:df9b8000 [ 154.764465] [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x5c/0x6c) [ 154.768341] [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_fmt+0x38/0x40) [ 154.776153] r8:00000180 r7:c0361594 r6:c0379b48 r5:00080003 r4:e0838b00 [ 154.790771] r3:00000009 [ 154.791778] [] (warn_slowpath_fmt+0x0/0x40) from [] (l3_interrupt_handler+0x1b4/0x1c4) [ 154.803710] r3:c0361598 r2:c02ef74c [ 154.807403] [] (l3_interrupt_handler+0x0/0x1c4) from [] (handle_irq_event_percpu+0x58/0 [ 154.818237] r8:0000002a r7:00000000 r6:00000000 r5:df808054 r4:df8893c0 [ 154.825378] [] (handle_irq_event_percpu+0x0/0x188) from [] (handle_irq_event+0x44/0x64) [ 154.835662] [] (handle_irq_event+0x0/0x64) from [] (handle_fasteoi_irq+0xa4/0x10c) [ 154.845458] r6:0000002a r5:df808054 r4:df808000 r3:c034a150 [ 154.846466] [] (handle_fasteoi_irq+0x0/0x10c) from [] (generic_handle_irq+0x30/0x38) [ 154.854278] r5:c034aa48 r4:0000002a [ 154.862091] [] (generic_handle_irq+0x0/0x38) from [] (handle_IRQ+0x60/0xc0) [ 154.874450] r4:c034ea70 r3:000001f8 [ 154.878234] [] (handle_IRQ+0x0/0xc0) from [] (gic_handle_irq+0x20/0x5c) [ 154.887023] r7:ffffff40 r6:df9b9fb0 r5:c034e2b4 r4:0000001a [ 154.887054] [] (gic_handle_irq+0x0/0x5c) from [] (__irq_usr+0x40/0x60) [ 154.901153] Exception stack(0xdf9b9fb0 to 0xdf9b9ff8) [ 154.907104] 9fa0: beaf1f04 4006be00 0000000f 0000000c [ 154.915710] 9fc0: 4006c000 00000000 00008034 ffffff40 00000007 00000000 00000000 0007b8d7 [ 154.916778] 9fe0: 00000000 beaf1b68 0000d23c 4005baf0 80000010 ffffffff [ 154.931335] r6:ffffffff r5:80000010 r4:4005baf0 r3:beaf1f04 [ 154.937316] ---[ end trace 1b75b31a2719ed21 ]-- Cc: Rajendra Nayak Cc: Linux PM list Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index fec8d5c6f0e5..44e8cfa84dfe 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1108,7 +1108,9 @@ omap_i2c_remove(struct platform_device *pdev) free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); + pm_runtime_get_sync(&pdev->dev); omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); iounmap(dev->base); kfree(dev); -- cgit v1.2.3 From 3b0fb97c8dc476935670706873c27a474191ccce Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:19 +0530 Subject: I2C: OMAP: Handle error check for pm runtime If PM runtime get_sync fails return with the error so that no further reads/writes goes through the interface. This will avoid possible abort. Add a error message in case of failure with the cause of the failure. Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 44e8cfa84dfe..c39b72f4a278 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -585,7 +585,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int i; int r; - pm_runtime_get_sync(dev->dev); + r = pm_runtime_get_sync(dev->dev); + if (IS_ERR_VALUE(r)) + return r; r = omap_i2c_wait_for_bb(dev); if (r < 0) @@ -1011,7 +1013,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->regs = (u8 *)reg_map_ip_v1; pm_runtime_enable(dev->dev); - pm_runtime_get_sync(dev->dev); + r = pm_runtime_get_sync(dev->dev); + if (IS_ERR_VALUE(r)) + goto err_free_mem; dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; @@ -1103,12 +1107,16 @@ omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; + int ret; platform_set_drvdata(pdev, NULL); free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); - pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (IS_ERR_VALUE(ret)) + return ret; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 9aa8ec676b6ef151ab11868d16a928d92410d25e Mon Sep 17 00:00:00 2001 From: Tasslehoff Kjappfot Date: Tue, 29 May 2012 16:26:20 +0530 Subject: I2C: OMAP: prevent the overwrite of the errata flags i2c_probe set the dev->errata flag, but omap_i2c_init cleared the flag again. Prevent the overwrite of the errata flags.Move the errata handling to a unified place in probe to prevent such errors. Reviewed-by: Kevin Hilman Signed-off-by: Tasslehoff Kjappfot Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c39b72f4a278..6129cb870573 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -427,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - dev->errata = 0; - - if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) - dev->errata |= I2C_OMAP_ERRATA_I207; - /* Enable interrupts */ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | @@ -1019,6 +1014,11 @@ omap_i2c_probe(struct platform_device *pdev) dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; + dev->errata = 0; + + if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + dev->errata |= I2C_OMAP_ERRATA_I207; + if (dev->rev <= OMAP_I2C_REV_ON_3430) dev->errata |= I2C_OMAP3_1P153; -- cgit v1.2.3 From e7e62df09d9be4288c1b33aff6eef078f61c97aa Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:21 +0530 Subject: I2C: OMAP: Do not set the XUDF(Transmit underflow) if the underflow is not reached Currently in the 1.153 errata handling, while waiting for transmitter underflow, if NACK is got the XUDF(Transmit underflow) flag is also set. Fix this by setting the XUDF(Transmit underflow) flag after wait for the condition is over. Cc: Alexander Shishkin Acked-by: Moiz Sonasath Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6129cb870573..cd6feead9de2 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -730,7 +730,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - *err |= OMAP_I2C_STAT_XUDF; return -ETIMEDOUT; } @@ -743,6 +742,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) return 0; } + *err |= OMAP_I2C_STAT_XUDF; return 0; } -- cgit v1.2.3 From c8db38f0e15c1fd5fec765081eb41180c3acaf60 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 29 May 2012 16:26:22 +0530 Subject: I2C: OMAP: Rename the 1p153 to the erratum id i462 The section number in the recent errata document has changed. Rename the erratum 1p153 to the unique id i462 instead, so that it is easier to reference. Also change the function name and comments to reflect the same. Cc: Jon Hunter Reviewed-by: Kevin Hilman Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index cd6feead9de2..dc3bd40b9e47 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -173,7 +173,7 @@ enum { /* Errata definitions */ #define I2C_OMAP_ERRATA_I207 (1 << 0) -#define I2C_OMAP3_1P153 (1 << 1) +#define I2C_OMAP_ERRATA_I462 (1 << 1) struct omap_i2c_dev { struct device *dev; @@ -718,11 +718,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) #endif /* - * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing + * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) { unsigned long timeout = 10000; @@ -881,8 +881,8 @@ complete: break; } - if ((dev->errata & I2C_OMAP3_1P153) && - errata_omap3_1p153(dev, &stat, &err)) + if ((dev->errata & I2C_OMAP_ERRATA_I462) && + errata_omap3_i462(dev, &stat, &err)) goto complete; omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); @@ -1020,7 +1020,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->errata |= I2C_OMAP_ERRATA_I207; if (dev->rev <= OMAP_I2C_REV_ON_3430) - dev->errata |= I2C_OMAP3_1P153; + dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; -- cgit v1.2.3 From b4fde5e7ed1c275986f45fe411ef7a2df58f9652 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 29 May 2012 16:26:23 +0530 Subject: I2C: OMAP: Fix timeout problem during suspend. On a board with OMAP3 processor and TWL4030 Power management, we need to talk to the TWL4030 during late suspend but cannot because the I2C interrupt is disabled (as late suspend disables interrupt). e.g. I get messages like: [ 62.161102] musb-omap2430 musb-omap2430: LATE power domain suspend [ 63.167205] omap_i2c omap_i2c.1: controller timed out [ 63.183044] twl: i2c_read failed to transfer all messages [ 64.182861] omap_i2c omap_i2c.1: controller timed out [ 64.198455] twl: i2c_write failed to transfer all messages [ 65.198455] omap_i2c omap_i2c.1: controller timed out [ 65.203765] twl: i2c_write failed to transfer all messages The stack shows omap2430_runtime_suspend calling twl4030_set_suspend which tries to power-down the USB PHY (twl4030_phy_suspend -> twl4030_phy_power -> __twl4030_phy_power which as a nice WARN_ON that helps). Then we get the same in resume: [ 69.603912] musb-omap2430 musb-omap2430: EARLY power domain resume [ 70.610473] omap_i2c omap_i2c.1: controller timed out [ 70.626129] twl: i2c_write failed to transfer all messages etc. So don't disable interrupts for I2C. Acked-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: NeilBrown Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index dc3bd40b9e47..9895fa7e486e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1053,7 +1053,7 @@ omap_i2c_probe(struct platform_device *pdev) isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : omap_i2c_isr; - r = request_irq(dev->irq, isr, 0, pdev->name, dev); + r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); -- cgit v1.2.3 From ec7aaca2f64f509f45d463d784b41d0b3d2be083 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 13 Jun 2012 15:42:36 +0530 Subject: i2c: tegra: make sure register writes completes The Tegra PPSB (an peripheral bus) queues writes transactions. In order to guarantee that writes have completed before a certain time, a read transaction to a register on the same bus must be executed. This is necessary in situations such as when clearing an interrupt status or enable, so that when returning from an interrupt handler, the HW has already de-asserted its interrupt status output, which will avoid spurious interrupts. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 8b2e555a9563..785f7f7a344a 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -165,6 +165,10 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) { writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); + + /* Read back register to make sure that register writes completed */ + if (reg != I2C_TX_FIFO) + readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); } static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg) -- cgit v1.2.3 From a70181049fc7b619ddc10cc1b956e7ee04b5bddd Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 13 Jun 2012 15:42:37 +0530 Subject: i2c: tegra: add PROTOCOL_MANGLING as supported functionality. The Tegra i2c driver supports the I2C_M_IGNORE_NAK and hence returning I2C_FUNC_PROTOCOL_MANGLING as supported functionality. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 785f7f7a344a..68433aeaa2e8 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -563,7 +563,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], static u32 tegra_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; } static const struct i2c_algorithm tegra_i2c_algo = { -- cgit v1.2.3 From c8f5af2f507d7f97a11065b98ec9f6c22aad8af0 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 13 Jun 2012 15:42:38 +0530 Subject: i2c: tegra: support for I2C_M_NOSTART functionality Adding support for functionality I2C_M_NOSTART. When multiple message transfer request made through i2c and if any message is flagged with I2C_M_NOSTART then it will not send the start/repeat-start and address of that message i.e. sends data directly. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 68433aeaa2e8..c4593a24331c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -97,8 +97,21 @@ #define I2C_HEADER_10BIT_ADDR (1<<18) #define I2C_HEADER_IE_ENABLE (1<<17) #define I2C_HEADER_REPEAT_START (1<<16) +#define I2C_HEADER_CONTINUE_XFER (1<<15) #define I2C_HEADER_MASTER_ADDR_SHIFT 12 #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 +/* + * msg_end_type: The bus control which need to be send at end of transfer. + * @MSG_END_STOP: Send stop pulse at end of transfer. + * @MSG_END_REPEAT_START: Send repeat start at end of transfer. + * @MSG_END_CONTINUE: The following on message is coming and so do not send + * stop or repeat start. + */ +enum msg_end_type { + MSG_END_STOP, + MSG_END_REPEAT_START, + MSG_END_CONTINUE, +}; /** * struct tegra_i2c_dev - per device i2c context @@ -453,7 +466,7 @@ err: } static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, - struct i2c_msg *msg, int stop) + struct i2c_msg *msg, enum msg_end_type end_state) { u32 packet_header; u32 int_mask; @@ -480,7 +493,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); packet_header = I2C_HEADER_IE_ENABLE; - if (!stop) + if (end_state == MSG_END_CONTINUE) + packet_header |= I2C_HEADER_CONTINUE_XFER; + else if (end_state == MSG_END_REPEAT_START) packet_header |= I2C_HEADER_REPEAT_START; if (msg->flags & I2C_M_TEN) { packet_header |= msg->addr; @@ -552,8 +567,14 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], clk_enable(i2c_dev->clk); for (i = 0; i < num; i++) { - int stop = (i == (num - 1)) ? 1 : 0; - ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop); + enum msg_end_type end_type = MSG_END_STOP; + if (i < (num - 1)) { + if (msgs[i + 1].flags & I2C_M_NOSTART) + end_type = MSG_END_CONTINUE; + else + end_type = MSG_END_REPEAT_START; + } + ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type); if (ret) break; } @@ -564,7 +585,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], static u32 tegra_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING; + I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART; } static const struct i2c_algorithm tegra_i2c_algo = { -- cgit v1.2.3 From 9cbb6b2b92d0fdade0fe00cc00e3658b44c86676 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 13 Jun 2012 15:42:39 +0530 Subject: i2c: tegra: make all resource allocation through devm_* Use the devm_* for the memory region allocation, interrupt request, clock handler request. By doing this, it does not require to explicitly free it and hence saving some code. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 62 ++++++++++++------------------------------ 1 file changed, 17 insertions(+), 45 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index c4593a24331c..9f4e22cdf82c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -598,7 +598,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) struct tegra_i2c_dev *i2c_dev; struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; struct resource *res; - struct resource *iomem; struct clk *clk; struct clk *i2c_clk; const unsigned int *prop; @@ -611,50 +610,41 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no mem resource\n"); return -EINVAL; } - iomem = request_mem_region(res->start, resource_size(res), pdev->name); - if (!iomem) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; - } - base = ioremap(iomem->start, resource_size(iomem)); + base = devm_request_and_ioremap(&pdev->dev, res); if (!base) { - dev_err(&pdev->dev, "Cannot ioremap I2C region\n"); - return -ENOMEM; + dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n"); + return -EADDRNOTAVAIL; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(&pdev->dev, "no irq resource\n"); - ret = -EINVAL; - goto err_iounmap; + return -EINVAL; } irq = res->start; - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "missing controller clock"); - ret = PTR_ERR(clk); - goto err_release_region; + return PTR_ERR(clk); } - i2c_clk = clk_get(&pdev->dev, "i2c"); + i2c_clk = devm_clk_get(&pdev->dev, "i2c"); if (IS_ERR(i2c_clk)) { dev_err(&pdev->dev, "missing bus clock"); - ret = PTR_ERR(i2c_clk); - goto err_clk_put; + return PTR_ERR(i2c_clk); } - i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL); + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) { - ret = -ENOMEM; - goto err_i2c_clk_put; + dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev"); + return -ENOMEM; } i2c_dev->base = base; i2c_dev->clk = clk; i2c_dev->i2c_clk = i2c_clk; - i2c_dev->iomem = iomem; i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; @@ -683,13 +673,14 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) ret = tegra_i2c_init(i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to initialize i2c controller"); - goto err_free; + return ret; } - ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev); + ret = devm_request_irq(&pdev->dev, i2c_dev->irq, + tegra_i2c_isr, 0, pdev->name, i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); - goto err_free; + return ret; } clk_enable(i2c_dev->i2c_clk); @@ -707,38 +698,19 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { dev_err(&pdev->dev, "Failed to add I2C adapter\n"); - goto err_free_irq; + clk_disable(i2c_dev->i2c_clk); + return ret; } of_i2c_register_devices(&i2c_dev->adapter); return 0; -err_free_irq: - free_irq(i2c_dev->irq, i2c_dev); -err_free: - kfree(i2c_dev); -err_i2c_clk_put: - clk_put(i2c_clk); -err_clk_put: - clk_put(clk); -err_release_region: - release_mem_region(iomem->start, resource_size(iomem)); -err_iounmap: - iounmap(base); - return ret; } static int __devexit tegra_i2c_remove(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); i2c_del_adapter(&i2c_dev->adapter); - free_irq(i2c_dev->irq, i2c_dev); - clk_put(i2c_dev->i2c_clk); - clk_put(i2c_dev->clk); - release_mem_region(i2c_dev->iomem->start, - resource_size(i2c_dev->iomem)); - iounmap(i2c_dev->base); - kfree(i2c_dev); return 0; } -- cgit v1.2.3 From 9f8a3e7fd5bd08e3fd9847c04a5a445e2994f6b3 Mon Sep 17 00:00:00 2001 From: Richard Zhao Date: Mon, 4 Jun 2012 19:04:25 +0800 Subject: i2c: imx: convert to use managed functions - convert to use devm_request_and_ioremap, devm_kzalloc, devm_clk_get, devm_request_irq. - clean up unused variables. Signed-off-by: Richard Zhao Reviewed-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 71 +++++++++++--------------------------------- 1 file changed, 18 insertions(+), 53 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 8d6b504d65c4..a93e84650f99 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -118,10 +118,8 @@ static u16 __initdata i2c_clk_div[50][2] = { struct imx_i2c_struct { struct i2c_adapter adapter; - struct resource *res; struct clk *clk; void __iomem *base; - int irq; wait_queue_head_t queue; unsigned long i2csr; unsigned int disable_delay; @@ -473,7 +471,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev) struct imxi2c_platform_data *pdata = pdev->dev.platform_data; struct pinctrl *pinctrl; void __iomem *base; - resource_size_t res_size; int irq, bitrate; int ret; @@ -490,25 +487,15 @@ static int __init i2c_imx_probe(struct platform_device *pdev) return -ENOENT; } - res_size = resource_size(res); - - if (!request_mem_region(res->start, res_size, DRIVER_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); + base = devm_request_and_ioremap(&pdev->dev, res); + if (!base) return -EBUSY; - } - - base = ioremap(res->start, res_size); - if (!base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -EIO; - goto fail1; - } - i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL); + i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct), + GFP_KERNEL); if (!i2c_imx) { dev_err(&pdev->dev, "can't allocate interface\n"); - ret = -ENOMEM; - goto fail2; + return -ENOMEM; } /* Setup i2c_imx driver structure */ @@ -518,29 +505,27 @@ static int __init i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.dev.parent = &pdev->dev; i2c_imx->adapter.nr = pdev->id; i2c_imx->adapter.dev.of_node = pdev->dev.of_node; - i2c_imx->irq = irq; i2c_imx->base = base; - i2c_imx->res = res; pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) { - ret = PTR_ERR(pinctrl); - goto fail3; + dev_err(&pdev->dev, "can't get/select pinctrl\n"); + return PTR_ERR(pinctrl); } /* Get I2C clock */ - i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk"); + i2c_imx->clk = devm_clk_get(&pdev->dev, "i2c_clk"); if (IS_ERR(i2c_imx->clk)) { - ret = PTR_ERR(i2c_imx->clk); dev_err(&pdev->dev, "can't get I2C clock\n"); - goto fail3; + return PTR_ERR(i2c_imx->clk); } /* Request IRQ */ - ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx); + ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, + pdev->name, i2c_imx); if (ret) { - dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq); - goto fail4; + dev_err(&pdev->dev, "can't claim irq %d\n", irq); + return ret; } /* Init queue */ @@ -565,7 +550,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c_imx->adapter); if (ret < 0) { dev_err(&pdev->dev, "registration failed\n"); - goto fail5; + return ret; } of_i2c_register_devices(&i2c_imx->adapter); @@ -573,28 +558,16 @@ static int __init i2c_imx_probe(struct platform_device *pdev) /* Set up platform driver data */ platform_set_drvdata(pdev, i2c_imx); - dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq); + dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq); dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n", - i2c_imx->res->start, i2c_imx->res->end); - dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n", - res_size, i2c_imx->res->start); + res->start, res->end); + dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x\n", + resource_size(res), res->start); dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", i2c_imx->adapter.name); dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); return 0; /* Return OK */ - -fail5: - free_irq(i2c_imx->irq, i2c_imx); -fail4: - clk_put(i2c_imx->clk); -fail3: - kfree(i2c_imx); -fail2: - iounmap(base); -fail1: - release_mem_region(res->start, resource_size(res)); - return ret; /* Return error number */ } static int __exit i2c_imx_remove(struct platform_device *pdev) @@ -606,20 +579,12 @@ static int __exit i2c_imx_remove(struct platform_device *pdev) i2c_del_adapter(&i2c_imx->adapter); platform_set_drvdata(pdev, NULL); - /* free interrupt */ - free_irq(i2c_imx->irq, i2c_imx); - /* setup chip registers to defaults */ writeb(0, i2c_imx->base + IMX_I2C_IADR); writeb(0, i2c_imx->base + IMX_I2C_IFDR); writeb(0, i2c_imx->base + IMX_I2C_I2CR); writeb(0, i2c_imx->base + IMX_I2C_I2SR); - clk_put(i2c_imx->clk); - - iounmap(i2c_imx->base); - release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res)); - kfree(i2c_imx); return 0; } -- cgit v1.2.3 From af97bace2cca58ee7c94bf4d31e820f29688d7a5 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Mon, 11 Jun 2012 22:56:26 +0200 Subject: i2c-nomadik: move header to The header and driver are only used by arm/mach-u8500 (and potentially arm/mach-nomadik), but the STA2X11 I/O Hub exports on PCIe a number of devices, including i2c-nomadik. This patch allows compilation of the driver under x86. Signed-off-by: Alessandro Rubini Acked-by: Giancarlo Asnaghi Tested-by: Linus Walleij Signed-off-by: Wolfram Sang --- arch/arm/mach-ux500/board-mop500.c | 2 +- arch/arm/mach-ux500/devices-common.h | 2 +- arch/arm/plat-nomadik/include/plat/i2c.h | 39 ------------------------------- drivers/i2c/busses/i2c-nomadik.c | 3 +-- include/linux/platform_data/i2c-nomadik.h | 39 +++++++++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 43 deletions(-) delete mode 100644 arch/arm/plat-nomadik/include/plat/i2c.h create mode 100644 include/linux/platform_data/i2c-nomadik.h (limited to 'drivers/i2c') diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 1509a3cb5833..f9a964836d3a 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,6 @@ #include #include -#include #include #include diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h index 6e4706560266..23cf734b5384 100644 --- a/arch/arm/mach-ux500/devices-common.h +++ b/arch/arm/mach-ux500/devices-common.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include struct spi_master_cntlr; diff --git a/arch/arm/plat-nomadik/include/plat/i2c.h b/arch/arm/plat-nomadik/include/plat/i2c.h deleted file mode 100644 index 8ba70ffc31ec..000000000000 --- a/arch/arm/plat-nomadik/include/plat/i2c.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2009 ST-Ericsson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - */ -#ifndef __PLAT_I2C_H -#define __PLAT_I2C_H - -enum i2c_freq_mode { - I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */ - I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */ - I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */ - I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ -}; - -/** - * struct nmk_i2c_controller - client specific controller configuration - * @clk_freq: clock frequency for the operation mode - * @slsu: Slave data setup time in ns. - * The needed setup time for three modes of operation - * are 250ns, 100ns and 10ns respectively thus leading - * to the values of 14, 6, 2 for a 48 MHz i2c clk - * @tft: Tx FIFO Threshold in bytes - * @rft: Rx FIFO Threshold in bytes - * @timeout Slave response timeout(ms) - * @sm: speed mode - */ -struct nmk_i2c_controller { - unsigned long clk_freq; - unsigned short slsu; - unsigned char tft; - unsigned char rft; - int timeout; - enum i2c_freq_mode sm; -}; - -#endif /* __PLAT_I2C_H */ diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 5267ab93d550..752f1fda371f 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -23,8 +23,7 @@ #include #include #include - -#include +#include #define DRIVER_NAME "nmk-i2c" diff --git a/include/linux/platform_data/i2c-nomadik.h b/include/linux/platform_data/i2c-nomadik.h new file mode 100644 index 000000000000..c2303c3e4803 --- /dev/null +++ b/include/linux/platform_data/i2c-nomadik.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 ST-Ericsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#ifndef __PDATA_I2C_NOMADIK_H +#define __PDATA_I2C_NOMADIK_H + +enum i2c_freq_mode { + I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */ + I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */ + I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */ + I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ +}; + +/** + * struct nmk_i2c_controller - client specific controller configuration + * @clk_freq: clock frequency for the operation mode + * @slsu: Slave data setup time in ns. + * The needed setup time for three modes of operation + * are 250ns, 100ns and 10ns respectively thus leading + * to the values of 14, 6, 2 for a 48 MHz i2c clk + * @tft: Tx FIFO Threshold in bytes + * @rft: Rx FIFO Threshold in bytes + * @timeout Slave response timeout(ms) + * @sm: speed mode + */ +struct nmk_i2c_controller { + unsigned long clk_freq; + unsigned short slsu; + unsigned char tft; + unsigned char rft; + int timeout; + enum i2c_freq_mode sm; +}; + +#endif /* __PDATA_I2C_NOMADIK_H */ -- cgit v1.2.3 From 235602146ec9c1882edf1ccc68389c1176be8198 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Mon, 11 Jun 2012 22:56:38 +0200 Subject: i2c-nomadik: turn the platform driver to an amba driver The i2c-nomadik gateware is really a PrimeCell APB device. By hosting the driver under the amba bus we can access it more easily, for example using the generic pci-amba driver. The patch also fixes the mach-ux500 users, so they register an amba device instead than a platform device. Signed-off-by: Alessandro Rubini Acked-by: Giancarlo Asnaghi Tested-by: Linus Walleij Signed-off-by: Wolfram Sang --- arch/arm/mach-ux500/devices-common.h | 22 ++---- drivers/i2c/busses/i2c-nomadik.c | 142 ++++++++++++++++++----------------- 2 files changed, 78 insertions(+), 86 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h index 23cf734b5384..ecdd8386cffb 100644 --- a/arch/arm/mach-ux500/devices-common.h +++ b/arch/arm/mach-ux500/devices-common.h @@ -56,27 +56,15 @@ dbx500_add_uart(struct device *parent, const char *name, resource_size_t base, struct nmk_i2c_controller; -static inline struct platform_device * +static inline struct amba_device * dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq, struct nmk_i2c_controller *data) { - struct resource res[] = { - DEFINE_RES_MEM(base, SZ_4K), - DEFINE_RES_IRQ(irq), - }; + /* Conjure a name similar to what the platform device used to have */ + char name[16]; - struct platform_device_info pdevinfo = { - .parent = parent, - .name = "nmk-i2c", - .id = id, - .res = res, - .num_res = ARRAY_SIZE(res), - .data = data, - .size_data = sizeof(*data), - .dma_mask = DMA_BIT_MASK(32), - }; - - return platform_device_register_full(&pdevinfo); + snprintf(name, sizeof(name), "nmk-i2c.%d", id); + return amba_apb_device_add(parent, name, base, SZ_4K, irq, 0, data, 0); } static inline struct amba_device * diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 752f1fda371f..6db453fe68e6 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -14,7 +14,8 @@ */ #include #include -#include +#include +#include #include #include #include @@ -135,7 +136,7 @@ struct i2c_nmk_client { /** * struct nmk_i2c_dev - private data structure of the controller. - * @pdev: parent platform device. + * @adev: parent amba device. * @adap: corresponding I2C adapter. * @irq: interrupt line for the controller. * @virtbase: virtual io memory area. @@ -149,7 +150,7 @@ struct i2c_nmk_client { * @busy: Busy doing transfer. */ struct nmk_i2c_dev { - struct platform_device *pdev; + struct amba_device *adev; struct i2c_adapter adap; int irq; void __iomem *virtbase; @@ -216,7 +217,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) } } - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "flushing operation timed out giving up after %d attempts", LOOP_ATTEMPTS); @@ -363,7 +364,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * and high speed (up to 3.4 Mb/s) */ if (dev->cfg.sm > I2C_FREQ_MODE_FAST) { - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "do not support this mode defaulting to std. mode\n"); brcr2 = i2c_clk/(100000 * 2) & 0xffff; writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); @@ -422,7 +423,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) &dev->xfer_complete, dev->adap.timeout); if (timeout < 0) { - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "wait_for_completion_timeout " "returned %d waiting for event\n", timeout); status = timeout; @@ -430,7 +431,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) if (timeout == 0) { /* Controller timed out */ - dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n", + dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n", dev->cli.slave_adr); status = -ETIMEDOUT; } @@ -509,7 +510,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) &dev->xfer_complete, dev->adap.timeout); if (timeout < 0) { - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "wait_for_completion_timeout " "returned %d waiting for event\n", timeout); status = timeout; @@ -517,7 +518,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) if (timeout == 0) { /* Controller timed out */ - dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n", + dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n", dev->cli.slave_adr); status = -ETIMEDOUT; } @@ -556,7 +557,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) if (((i2c_sr >> 2) & 0x3) == 0x3) { /* get the abort cause */ cause = (i2c_sr >> 4) & 0x7; - dev_err(&dev->pdev->dev, "%s\n", + dev_err(&dev->adev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); @@ -629,7 +630,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, if (dev->regulator) regulator_enable(dev->regulator); - pm_runtime_get_sync(&dev->pdev->dev); + pm_runtime_get_sync(&dev->adev->dev); clk_enable(dev->clk); @@ -644,7 +645,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, for (i = 0; i < num_msgs; i++) { if (unlikely(msgs[i].flags & I2C_M_TEN)) { - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "10 bit addressing not supported\n"); status = -EINVAL; @@ -666,7 +667,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, out: clk_disable(dev->clk); - pm_runtime_put_sync(&dev->pdev->dev); + pm_runtime_put_sync(&dev->adev->dev); if (dev->regulator) regulator_disable(dev->regulator); @@ -789,7 +790,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) if (dev->cli.count) { dev->result = -EIO; - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "%lu bytes still remain to be xfered\n", dev->cli.count); (void) init_hw(dev); @@ -833,7 +834,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) dev->result = -EIO; (void) init_hw(dev); - dev_err(&dev->pdev->dev, "Tx Fifo Over run\n"); + dev_err(&dev->adev->dev, "Tx Fifo Over run\n"); complete(&dev->xfer_complete); break; @@ -846,10 +847,10 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_RFSE: case I2C_IT_WTSR: case I2C_IT_STD: - dev_err(&dev->pdev->dev, "unhandled Interrupt\n"); + dev_err(&dev->adev->dev, "unhandled Interrupt\n"); break; default: - dev_err(&dev->pdev->dev, "spurious Interrupt..\n"); + dev_err(&dev->adev->dev, "spurious Interrupt..\n"); break; } @@ -860,8 +861,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) #ifdef CONFIG_PM static int nmk_i2c_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev); + struct amba_device *adev = to_amba_device(dev); + struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); if (nmk_i2c->busy) return -EBUSY; @@ -898,79 +899,70 @@ static const struct i2c_algorithm nmk_i2c_algo = { .functionality = nmk_i2c_functionality }; -static int __devinit nmk_i2c_probe(struct platform_device *pdev) +static atomic_t adapter_id = ATOMIC_INIT(0); + +static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; - struct resource *res; struct nmk_i2c_controller *pdata = - pdev->dev.platform_data; + adev->dev.platform_data; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; + if (!pdata) { + dev_warn(&adev->dev, "no platform data\n"); + return -ENODEV; + } dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); if (!dev) { - dev_err(&pdev->dev, "cannot allocate memory\n"); + dev_err(&adev->dev, "cannot allocate memory\n"); ret = -ENOMEM; goto err_no_mem; } dev->busy = false; - dev->pdev = pdev; - platform_set_drvdata(pdev, dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENOENT; - goto err_no_resource; - } + dev->adev = adev; + amba_set_drvdata(adev, dev); - if (request_mem_region(res->start, resource_size(res), - DRIVER_NAME "I/O region") == NULL) { - ret = -EBUSY; - goto err_no_region; - } - - dev->virtbase = ioremap(res->start, resource_size(res)); + dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res)); if (!dev->virtbase) { ret = -ENOMEM; goto err_no_ioremap; } - dev->irq = platform_get_irq(pdev, 0); + dev->irq = adev->irq[0]; ret = request_irq(dev->irq, i2c_irq_handler, 0, DRIVER_NAME, dev); if (ret) { - dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq); + dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq); goto err_irq; } - dev->regulator = regulator_get(&pdev->dev, "v-i2c"); + dev->regulator = regulator_get(&adev->dev, "v-i2c"); if (IS_ERR(dev->regulator)) { - dev_warn(&pdev->dev, "could not get i2c regulator\n"); + dev_warn(&adev->dev, "could not get i2c regulator\n"); dev->regulator = NULL; } - pm_suspend_ignore_children(&pdev->dev, true); - pm_runtime_enable(&pdev->dev); + pm_suspend_ignore_children(&adev->dev, true); - dev->clk = clk_get(&pdev->dev, NULL); + dev->clk = clk_get(&adev->dev, NULL); if (IS_ERR(dev->clk)) { - dev_err(&pdev->dev, "could not get i2c clock\n"); + dev_err(&adev->dev, "could not get i2c clock\n"); ret = PTR_ERR(dev->clk); goto err_no_clk; } adap = &dev->adap; - adap->dev.parent = &pdev->dev; + adap->dev.parent = &adev->dev; adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->algo = &nmk_i2c_algo; adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) : msecs_to_jiffies(20000); + adap->nr = atomic_read(&adapter_id); snprintf(adap->name, sizeof(adap->name), - "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); - - /* fetch the controller id */ - adap->nr = pdev->id; + "Nomadik I2C%d at %pR", adap->nr, &adev->res); + atomic_inc(&adapter_id); /* fetch the controller configuration from machine */ dev->cfg.clk_freq = pdata->clk_freq; @@ -981,16 +973,18 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, dev); - dev_info(&pdev->dev, + dev_info(&adev->dev, "initialize %s on virtual base %p\n", adap->name, dev->virtbase); ret = i2c_add_numbered_adapter(adap); if (ret) { - dev_err(&pdev->dev, "failed to add adapter\n"); + dev_err(&adev->dev, "failed to add adapter\n"); goto err_add_adap; } + pm_runtime_put(&adev->dev); + return 0; err_add_adap: @@ -998,25 +992,21 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) err_no_clk: if (dev->regulator) regulator_put(dev->regulator); - pm_runtime_disable(&pdev->dev); free_irq(dev->irq, dev); err_irq: iounmap(dev->virtbase); err_no_ioremap: - release_mem_region(res->start, resource_size(res)); - err_no_region: - platform_set_drvdata(pdev, NULL); - err_no_resource: + amba_set_drvdata(adev, NULL); kfree(dev); err_no_mem: return ret; } -static int __devexit nmk_i2c_remove(struct platform_device *pdev) +static int nmk_i2c_remove(struct amba_device *adev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct nmk_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *res = &adev->res; + struct nmk_i2c_dev *dev = amba_get_drvdata(adev); i2c_del_adapter(&dev->adap); flush_i2c_fifo(dev); @@ -1031,31 +1021,46 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) clk_put(dev->clk); if (dev->regulator) regulator_put(dev->regulator); - pm_runtime_disable(&pdev->dev); - platform_set_drvdata(pdev, NULL); + pm_runtime_disable(&adev->dev); + amba_set_drvdata(adev, NULL); kfree(dev); return 0; } -static struct platform_driver nmk_i2c_driver = { - .driver = { +static struct amba_id nmk_i2c_ids[] = { + { + .id = 0x00180024, + .mask = 0x00ffffff, + }, + { + .id = 0x00380024, + .mask = 0x00ffffff, + }, + {}, +}; + +MODULE_DEVICE_TABLE(amba, nmk_i2c_ids); + +static struct amba_driver nmk_i2c_driver = { + .drv = { .owner = THIS_MODULE, .name = DRIVER_NAME, .pm = &nmk_i2c_pm, }, + .id_table = nmk_i2c_ids, .probe = nmk_i2c_probe, - .remove = __devexit_p(nmk_i2c_remove), + .remove = nmk_i2c_remove, }; static int __init nmk_i2c_init(void) { - return platform_driver_register(&nmk_i2c_driver); + return amba_driver_register(&nmk_i2c_driver); } static void __exit nmk_i2c_exit(void) { - platform_driver_unregister(&nmk_i2c_driver); + amba_driver_unregister(&nmk_i2c_driver); } subsys_initcall(nmk_i2c_init); @@ -1064,4 +1069,3 @@ module_exit(nmk_i2c_exit); MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR"); MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.3 From 419408edc90ee50d50323227d4dd73d6d22dc744 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Mon, 11 Jun 2012 22:56:49 +0200 Subject: i2c-nomadik: depend on ARM_AMBA, not PLAT_NOMADIK The gateware device has been used outside of the Nomadik world, using the pci-amba bridge driver, so loosen the dependencies. Signed-off-by: Alessandro Rubini Acked-by: Giancarlo Asnaghi Tested-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7244c8be6063..e9f9c5dc87ce 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -479,10 +479,11 @@ config I2C_MXS config I2C_NOMADIK tristate "ST-Ericsson Nomadik/Ux500 I2C Controller" - depends on PLAT_NOMADIK + depends on ARM_AMBA help If you say yes to this option, support will be included for the - I2C interface from ST-Ericsson's Nomadik and Ux500 architectures. + I2C interface from ST-Ericsson's Nomadik and Ux500 architectures, + as well as the STA2X11 PCIe I/O HUB. config I2C_NUC900 tristate "NUC900 I2C Driver" -- cgit v1.2.3 From 51a0c8d0b8a877f41e9be62fb1e946ec682611c1 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Mon, 25 Jun 2012 17:56:07 +0530 Subject: i2c-nomadik: Add 10-bit addressing support Signed-off-by: Virupax Sadashivpetimath Signed-off-by: Srinidhi KASAGAR Acked-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 46 +++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 6db453fe68e6..e6b93f3ca867 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -276,15 +276,32 @@ exit: /** * load_i2c_mcr_reg() - load the MCR register * @dev: private data of controller + * @flags: message flags */ -static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev) +static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags) { u32 mcr = 0; + unsigned short slave_adr_3msb_bits; - /* 7-bit address transaction */ - mcr |= GEN_MASK(1, I2C_MCR_AM, 12); mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1); + if (unlikely(flags & I2C_M_TEN)) { + /* 10-bit address transaction */ + mcr |= GEN_MASK(2, I2C_MCR_AM, 12); + /* + * Get the top 3 bits. + * EA10 represents extended address in MCR. This includes + * the extension (MSB bits) of the 7 bit address loaded + * in A7 + */ + slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7; + + mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8); + } else { + /* 7-bit address transaction */ + mcr |= GEN_MASK(1, I2C_MCR_AM, 12); + } + /* start byte procedure not applied */ mcr |= GEN_MASK(0, I2C_MCR_SB, 11); @@ -381,19 +398,20 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) /** * read_i2c() - Read from I2C client device * @dev: private data of I2C Driver + * @flags: message flags * * This function reads from i2c client device when controller is in * master mode. There is a completion timeout. If there is no transfer * before timeout error is returned. */ -static int read_i2c(struct nmk_i2c_dev *dev) +static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; u32 mcr; u32 irq_mask = 0; int timeout; - mcr = load_i2c_mcr_reg(dev); + mcr = load_i2c_mcr_reg(dev, flags); writel(mcr, dev->virtbase + I2C_MCR); /* load the current CR value */ @@ -459,17 +477,18 @@ static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) /** * write_i2c() - Write data to I2C client. * @dev: private data of I2C Driver + * @flags: message flags * * This function writes data to I2C client */ -static int write_i2c(struct nmk_i2c_dev *dev) +static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; u32 mcr; u32 irq_mask = 0; int timeout; - mcr = load_i2c_mcr_reg(dev); + mcr = load_i2c_mcr_reg(dev, flags); writel(mcr, dev->virtbase + I2C_MCR); @@ -538,11 +557,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) if (flags & I2C_M_RD) { /* read operation */ dev->cli.operation = I2C_READ; - status = read_i2c(dev); + status = read_i2c(dev, flags); } else { /* write operation */ dev->cli.operation = I2C_WRITE; - status = write_i2c(dev); + status = write_i2c(dev, flags); } if (status || (dev->result)) { @@ -644,13 +663,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, setup_i2c_controller(dev); for (i = 0; i < num_msgs; i++) { - if (unlikely(msgs[i].flags & I2C_M_TEN)) { - dev_err(&dev->adev->dev, - "10 bit addressing not supported\n"); - - status = -EINVAL; - goto out; - } dev->cli.slave_adr = msgs[i].addr; dev->cli.buffer = msgs[i].buf; dev->cli.count = msgs[i].len; @@ -891,7 +903,7 @@ static const struct dev_pm_ops nmk_i2c_pm = { static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } static const struct i2c_algorithm nmk_i2c_algo = { -- cgit v1.2.3 From a55b44ac3fe07d4e89486817732b596fce6ab9f6 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sun, 1 Jul 2012 23:34:30 +0200 Subject: i2c: mxs: mxs_i2c_finish_read: mute flase positive uninitialized var This patch mutes the false positive compiler warning: drivers/i2c/busses/i2c-mxs.c: In function 'mxs_i2c_xfer_msg': drivers/i2c/busses/i2c-mxs.c:206:8: warning: 'data' may be used uninitialized in this function [-Wuninitialized] drivers/i2c/busses/i2c-mxs.c:196:6: note: 'data' was declared here Signed-off-by: Marc Kleine-Budde Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 04eb441b6ce1..02ce1faeeeef 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -193,7 +193,7 @@ static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c) static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len) { - u32 data; + u32 uninitialized_var(data); int i; for (i = 0; i < len; i++) { -- cgit v1.2.3 From a3f24c0dbd0b9a7624d077b3c1841dde267aaa6c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 12 Jun 2012 19:33:30 +0200 Subject: i2c: stu300: use clk_prepare/unprepare Make sure we prepare/unprepare the clock for the ST U300 I2C driver as is required by the clk API especially if you use common clock. Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stu300.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 4d44af181f37..79b785150c15 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -924,7 +924,7 @@ stu300_probe(struct platform_device *pdev) dev->speed = scl_frequency; - clk_enable(dev->clk); + clk_prepare_enable(dev->clk); ret = stu300_init_hw(dev); clk_disable(dev->clk); @@ -960,6 +960,7 @@ stu300_probe(struct platform_device *pdev) err_add_adapter: err_init_hw: + clk_unprepare(dev->clk); free_irq(dev->irq, dev); err_no_irq: iounmap(dev->virtbase); @@ -1016,6 +1017,7 @@ stu300_remove(struct platform_device *pdev) free_irq(dev->irq, dev); iounmap(dev->virtbase); release_mem_region(dev->phybase, dev->physize); + clk_unprepare(dev->clk); clk_put(dev->clk); platform_set_drvdata(pdev, NULL); kfree(dev); -- cgit v1.2.3 From 1f09c672314f8180113429ff36cad09296c40a9f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 6 Jul 2012 15:31:32 -0300 Subject: i2c: i2c-imx: Adapt the clock name to the new clock framework With the new i.mx clock framework the i2c clock is registered as: clk_register_clkdev(clk[i2c1_ipg_gate], NULL, "imx-i2c.0") So we do not need to pass "i2c_clk" string and can use NULL instead. Signed-off-by: Fabio Estevam Acked-by: Sascha Hauer [wsa: rebased on top of the devm-conversion] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index a93e84650f99..dd2a0839b266 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -514,7 +514,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev) } /* Get I2C clock */ - i2c_imx->clk = devm_clk_get(&pdev->dev, "i2c_clk"); + i2c_imx->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_imx->clk)) { dev_err(&pdev->dev, "can't get I2C clock\n"); return PTR_ERR(i2c_imx->clk); -- cgit v1.2.3 From 8c88ab040115430fc146df7aa5a57538bf6d0e2d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 8 Jul 2012 13:11:43 +0200 Subject: i2c: imx: make bitrate an u32 type sparse found this assignment of u32 to an int. Fix it: drivers/i2c/busses/i2c-imx.c:540:56: warning: incorrect type in argument 3 (different signedness) and also fix the type in platform_data. All current users use values which fit into the old and new type, so it is a safe change. Signed-off-by: Wolfram Sang Reviewed-by: Richard Zhao Acked-by: Sascha Hauer --- arch/arm/plat-mxc/include/mach/i2c.h | 2 +- drivers/i2c/busses/i2c-imx.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/arm/plat-mxc/include/mach/i2c.h b/arch/arm/plat-mxc/include/mach/i2c.h index 375cdd0cf876..8289d915e615 100644 --- a/arch/arm/plat-mxc/include/mach/i2c.h +++ b/arch/arm/plat-mxc/include/mach/i2c.h @@ -15,7 +15,7 @@ * **/ struct imxi2c_platform_data { - int bitrate; + u32 bitrate; }; #endif /* __ASM_ARCH_I2C_H_ */ diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index dd2a0839b266..90460dd5e5ab 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -471,8 +471,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev) struct imxi2c_platform_data *pdata = pdev->dev.platform_data; struct pinctrl *pinctrl; void __iomem *base; - int irq, bitrate; - int ret; + int irq, ret; + u32 bitrate; dev_dbg(&pdev->dev, "<%s>\n", __func__); -- cgit v1.2.3 From 57c0dc3e69439a2ddf239226c318d676da773492 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 10 Jul 2012 17:10:21 +0530 Subject: i2c: tegra: remove unused member variable Remove unused member variable "iomem" of the i2c device structure. This variable becomes unused when converted all allocation to devm_* in following change: i2c: tegra: make all resource allocation through devm_* Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 9f4e22cdf82c..e7738588a1e6 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -119,7 +119,6 @@ enum msg_end_type { * @adapter: core i2c layer adapter information * @clk: clock reference for i2c controller * @i2c_clk: clock reference for i2c bus - * @iomem: memory resource for registers * @base: ioremapped registers cookie * @cont_id: i2c controller id, used for for packet header * @irq: irq number of transfer complete interrupt @@ -137,7 +136,6 @@ struct tegra_i2c_dev { struct i2c_adapter adapter; struct clk *clk; struct clk *i2c_clk; - struct resource *iomem; void __iomem *base; int cont_id; int irq; -- cgit v1.2.3 From 9dce4bcaaabce28f7b188e4fa4fda3ea74ae5a0d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 10 Jul 2012 16:50:41 +0530 Subject: i2c: tegra: use clk_disable_unprepare in place of clk_disable Use clk_disable_unprepare() inplace of clk_disable(). This was missed as part of moving clock enable/disable to prepare/unprepare for using the common clock framework. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index e7738588a1e6..60d777027ce8 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -696,7 +696,7 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { dev_err(&pdev->dev, "Failed to add I2C adapter\n"); - clk_disable(i2c_dev->i2c_clk); + clk_disable_unprepare(i2c_dev->i2c_clk); return ret; } -- cgit v1.2.3 From 02d8bf8dc6b09cb810599c64d47da3bdf4f85882 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 10 Jul 2012 16:50:42 +0530 Subject: i2c: tegra: use of_match_ptr() for match_table initialization In place of defining match_table for non-DT based as NULL, use of_match_ptr() for initialzing the of_match_table. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 60d777027ce8..f00649c78b05 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -754,8 +754,6 @@ static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { {}, }; MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); -#else -#define tegra_i2c_of_match NULL #endif static struct platform_driver tegra_i2c_driver = { @@ -768,7 +766,7 @@ static struct platform_driver tegra_i2c_driver = { .driver = { .name = "tegra-i2c", .owner = THIS_MODULE, - .of_match_table = tegra_i2c_of_match, + .of_match_table = of_match_ptr(tegra_i2c_of_match), }, }; -- cgit v1.2.3 From f277d27cc40f77719d45d9f5abf3ae4e9bdb172f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:22:47 +0200 Subject: i2c-at91: Use struct dev_pm_ops for power management Make the AT91 Two-Wire Interface driver define its PM callbacks through a struct dev_pm_ops object rather than by using legacy PM hooks in struct platform_driver. Signed-off-by: Rafael J. Wysocki Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 1679deef9c89..e24484beef07 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -279,30 +279,31 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev) /* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */ -static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg) +static int at91_i2c_suspend(struct device *dev) { clk_disable(twi_clk); return 0; } -static int at91_i2c_resume(struct platform_device *pdev) +static int at91_i2c_resume(struct device *dev) { return clk_enable(twi_clk); } +static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume); +#define AT91_I2C_PM (&at91_i2c_pm) + #else -#define at91_i2c_suspend NULL -#define at91_i2c_resume NULL +#define AT91_I2C_PM NULL #endif static struct platform_driver at91_i2c_driver = { .probe = at91_i2c_probe, .remove = __devexit_p(at91_i2c_remove), - .suspend = at91_i2c_suspend, - .resume = at91_i2c_resume, .driver = { .name = "at91_i2c", .owner = THIS_MODULE, + .pm = AT91_I2C_PM, }, }; -- cgit v1.2.3 From 85777ad264695b6287b958627196bd70f72ca8ae Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:23:31 +0200 Subject: i2c-bfin-twi: Use struct dev_pm_ops for power management Make the Blackfin On-Chip Two Wire Interface driver define its PM callbacks through a struct dev_pm_ops object rather than by using legacy PM hooks in struct platform_driver. Signed-off-by: Rafael J. Wysocki Acked-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index cdb59e5b23f7..515822429b19 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -611,9 +611,9 @@ static struct i2c_algorithm bfin_twi_algorithm = { .functionality = bfin_twi_functionality, }; -static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state) +static int i2c_bfin_twi_suspend(struct device *dev) { - struct bfin_twi_iface *iface = platform_get_drvdata(pdev); + struct bfin_twi_iface *iface = dev_get_drvdata(dev); iface->saved_clkdiv = read_CLKDIV(iface); iface->saved_control = read_CONTROL(iface); @@ -626,14 +626,14 @@ static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state return 0; } -static int i2c_bfin_twi_resume(struct platform_device *pdev) +static int i2c_bfin_twi_resume(struct device *dev) { - struct bfin_twi_iface *iface = platform_get_drvdata(pdev); + struct bfin_twi_iface *iface = dev_get_drvdata(dev); int rc = request_irq(iface->irq, bfin_twi_interrupt_entry, - 0, pdev->name, iface); + 0, to_platform_device(dev)->name, iface); if (rc) { - dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); + dev_err(dev, "Can't get IRQ %d !\n", iface->irq); return -ENODEV; } @@ -646,6 +646,9 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev) return 0; } +static SIMPLE_DEV_PM_OPS(i2c_bfin_twi_pm, + i2c_bfin_twi_suspend, i2c_bfin_twi_resume); + static int i2c_bfin_twi_probe(struct platform_device *pdev) { struct bfin_twi_iface *iface; @@ -770,11 +773,10 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev) static struct platform_driver i2c_bfin_twi_driver = { .probe = i2c_bfin_twi_probe, .remove = i2c_bfin_twi_remove, - .suspend = i2c_bfin_twi_suspend, - .resume = i2c_bfin_twi_resume, .driver = { .name = "i2c-bfin-twi", .owner = THIS_MODULE, + .pm = &i2c_bfin_twi_pm, }, }; -- cgit v1.2.3 From 84603c7c2e94bd1394f29fbfbd289432565ee2e8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:24:15 +0200 Subject: i2c-ocores: Use struct dev_pm_ops for power management Make the OpenCores I2C controller driver define its PM callbacks through a struct dev_pm_ops object rather than by using legacy PM hooks in struct platform_driver. Signed-off-by: Rafael J. Wysocki Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 75194c579b6d..d7d21d532557 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -367,9 +367,9 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev) } #ifdef CONFIG_PM -static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state) +static int ocores_i2c_suspend(struct device *dev) { - struct ocores_i2c *i2c = platform_get_drvdata(pdev); + struct ocores_i2c *i2c = dev_get_drvdata(dev); u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); /* make sure the device is disabled */ @@ -378,17 +378,19 @@ static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int ocores_i2c_resume(struct platform_device *pdev) +static int ocores_i2c_resume(struct device *dev) { - struct ocores_i2c *i2c = platform_get_drvdata(pdev); + struct ocores_i2c *i2c = dev_get_drvdata(dev); ocores_init(i2c); return 0; } + +static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); +#define OCORES_I2C_PM (&ocores_i2c_pm) #else -#define ocores_i2c_suspend NULL -#define ocores_i2c_resume NULL +#define OCORES_I2C_PM NULL #endif static struct of_device_id ocores_i2c_match[] = { @@ -400,12 +402,11 @@ MODULE_DEVICE_TABLE(of, ocores_i2c_match); static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, .remove = __devexit_p(ocores_i2c_remove), - .suspend = ocores_i2c_suspend, - .resume = ocores_i2c_resume, .driver = { .owner = THIS_MODULE, .name = "ocores-i2c", .of_match_table = ocores_i2c_match, + .pm = OCORES_I2C_PM, }, }; -- cgit v1.2.3 From 783414ba9a65fa15e44716dc478e9536d202e0ff Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:25:17 +0200 Subject: i2c-pnx: Use struct dev_pm_ops for power management Make the PNX I2C controller driver define its PM callbacks through a struct dev_pm_ops object rather than by using legacy PM hooks in struct platform_driver. Signed-off-by: Rafael J. Wysocki Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pnx.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 99389d2eae51..5d54416770b0 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -587,25 +587,27 @@ static struct i2c_algorithm pnx_algorithm = { }; #ifdef CONFIG_PM -static int i2c_pnx_controller_suspend(struct platform_device *pdev, - pm_message_t state) +static int i2c_pnx_controller_suspend(struct device *dev) { - struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); + struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); clk_disable(alg_data->clk); return 0; } -static int i2c_pnx_controller_resume(struct platform_device *pdev) +static int i2c_pnx_controller_resume(struct device *dev) { - struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); + struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); return clk_enable(alg_data->clk); } + +static SIMPLE_DEV_PM_OPS(i2c_pnx_pm, + i2c_pnx_controller_suspend, i2c_pnx_controller_resume); +#define PNX_I2C_PM (&i2c_pnx_pm) #else -#define i2c_pnx_controller_suspend NULL -#define i2c_pnx_controller_resume NULL +#define PNX_I2C_PM NULL #endif static int __devinit i2c_pnx_probe(struct platform_device *pdev) @@ -783,11 +785,10 @@ static struct platform_driver i2c_pnx_driver = { .name = "pnx-i2c", .owner = THIS_MODULE, .of_match_table = of_match_ptr(i2c_pnx_of_match), + .pm = PNX_I2C_PM, }, .probe = i2c_pnx_probe, .remove = __devexit_p(i2c_pnx_remove), - .suspend = i2c_pnx_controller_suspend, - .resume = i2c_pnx_controller_resume, }; static int __init i2c_adap_pnx_init(void) -- cgit v1.2.3 From b9f1b45bacb6485838e0504c312ecabc90c1e273 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:25:55 +0200 Subject: i2c-puv3: Use struct dev_pm_ops for power management Make the PKUnity-v3 SoC I2C controller driver define its suspend callback through a struct dev_pm_ops object rather than by using a legacy PM hook in struct platform_driver. The empty resume callback is not necessary, so remove it. Signed-off-by: Rafael J. Wysocki Acked-by: Guan Xuetao Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-puv3.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c index 93709fbe30eb..d8515be00b98 100644 --- a/drivers/i2c/busses/i2c-puv3.c +++ b/drivers/i2c/busses/i2c-puv3.c @@ -254,7 +254,7 @@ static int __devexit puv3_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state) +static int puv3_i2c_suspend(struct device *dev) { int poll_count; /* Disable the IIC */ @@ -267,23 +267,20 @@ static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state) return 0; } -static int puv3_i2c_resume(struct platform_device *dev) -{ - return 0 ; -} +static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL); +#define PUV3_I2C_PM (&puv3_i2c_pm) + #else -#define puv3_i2c_suspend NULL -#define puv3_i2c_resume NULL +#define PUV3_I2C_PM NULL #endif static struct platform_driver puv3_i2c_driver = { .probe = puv3_i2c_probe, .remove = __devexit_p(puv3_i2c_remove), - .suspend = puv3_i2c_suspend, - .resume = puv3_i2c_resume, .driver = { .name = "PKUnity-v3-I2C", .owner = THIS_MODULE, + .pm = PUV3_I2C_PM, } }; -- cgit v1.2.3 From 4aacc4b1b13cecef90d9ccbf9cf3fb4cc99807a0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:26:36 +0200 Subject: i2c-stu300: Use struct dev_pm_ops for power management Make the ST-Ericsson U300 I2C controller driver define its PM callbacks through a struct dev_pm_ops object rather than by using legacy PM hooks in struct platform_driver. Signed-off-by: Rafael J. Wysocki Reviewed-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stu300.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 79b785150c15..80dd1c074a08 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -979,31 +979,33 @@ stu300_probe(struct platform_device *pdev) } #ifdef CONFIG_PM -static int stu300_suspend(struct platform_device *pdev, pm_message_t state) +static int stu300_suspend(struct device *device) { - struct stu300_dev *dev = platform_get_drvdata(pdev); + struct stu300_dev *dev = dev_get_drvdata(device); /* Turn off everything */ stu300_wr8(0x00, dev->virtbase + I2C_CR); return 0; } -static int stu300_resume(struct platform_device *pdev) +static int stu300_resume(struct device *device) { int ret = 0; - struct stu300_dev *dev = platform_get_drvdata(pdev); + struct stu300_dev *dev = dev_get_drvdata(device); clk_enable(dev->clk); ret = stu300_init_hw(dev); clk_disable(dev->clk); if (ret != 0) - dev_err(&pdev->dev, "error re-initializing hardware.\n"); + dev_err(device, "error re-initializing hardware.\n"); return ret; } + +static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume); +#define STU300_I2C_PM (&stu300_pm) #else -#define stu300_suspend NULL -#define stu300_resume NULL +#define STU300_I2C_PM NULL #endif static int __exit @@ -1028,10 +1030,9 @@ static struct platform_driver stu300_i2c_driver = { .driver = { .name = NAME, .owner = THIS_MODULE, + .pm = STU300_I2C_PM, }, .remove = __exit_p(stu300_remove), - .suspend = stu300_suspend, - .resume = stu300_resume, }; -- cgit v1.2.3 From 6a7b3c3c465cef29d92dfc3fbbff0d958aa8be04 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Jul 2012 21:27:30 +0200 Subject: i2c-tegra: Use struct dev_pm_ops for power management Make the Tegra I2C controller driver define its PM callbacks through a struct dev_pm_ops object rather than by using legacy PM hooks in struct platform_driver. Signed-off-by: Rafael J. Wysocki Acked-by: Laxman Dewangan [wsa] adapt to of_match_ptr change Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index f00649c78b05..f85dee549e21 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -713,9 +713,9 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state) +static int tegra_i2c_suspend(struct device *dev) { - struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); i2c_lock_adapter(&i2c_dev->adapter); i2c_dev->is_suspended = true; @@ -724,9 +724,9 @@ static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int tegra_i2c_resume(struct platform_device *pdev) +static int tegra_i2c_resume(struct device *dev) { - struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; i2c_lock_adapter(&i2c_dev->adapter); @@ -744,6 +744,11 @@ static int tegra_i2c_resume(struct platform_device *pdev) return 0; } + +static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); +#define TEGRA_I2C_PM (&tegra_i2c_pm) +#else +#define TEGRA_I2C_PM NULL #endif #if defined(CONFIG_OF) @@ -759,14 +764,11 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = __devexit_p(tegra_i2c_remove), -#ifdef CONFIG_PM - .suspend = tegra_i2c_suspend, - .resume = tegra_i2c_resume, -#endif .driver = { .name = "tegra-i2c", .owner = THIS_MODULE, .of_match_table = of_match_ptr(tegra_i2c_of_match), + .pm = TEGRA_I2C_PM, }, }; -- cgit v1.2.3 From 7c86d44cda2e715bc95f525fd0eac4bd6a66998e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 10 Jul 2012 16:50:44 +0530 Subject: i2c: tegra: convert normal suspend/resume to *_noirq To provide the late suspend and early resume for i2c driver, convert the suspend/resume as suspend-> suspend_noirq resume -> resume_noirq Signed-off-by: Laxman Dewangan [wsa: fixed up to match previous pm_ops change] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index f85dee549e21..f179f88aa71a 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -713,7 +713,7 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int tegra_i2c_suspend(struct device *dev) +static int tegra_i2c_suspend_noirq(struct device *dev) { struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -724,7 +724,7 @@ static int tegra_i2c_suspend(struct device *dev) return 0; } -static int tegra_i2c_resume(struct device *dev) +static int tegra_i2c_resume_noirq(struct device *dev) { struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; @@ -745,7 +745,10 @@ static int tegra_i2c_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); +static const struct dev_pm_ops tegra_i2c_pm = { + .suspend_noirq = tegra_i2c_suspend_noirq, + .resume_noirq = tegra_i2c_resume_noirq, +}; #define TEGRA_I2C_PM (&tegra_i2c_pm) #else #define TEGRA_I2C_PM NULL -- cgit v1.2.3 From d790aea70d714c1ba58823b4dc1b445f1e791072 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 28 Jun 2012 20:41:27 +0530 Subject: i2c: omap: Annotate the remove code The omap_i2c_remove function may not be needed after device exit so the memory could be freed. Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9895fa7e486e..b08607606014 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1102,8 +1102,7 @@ err_release_region: return r; } -static int -omap_i2c_remove(struct platform_device *pdev) +static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; @@ -1187,7 +1186,7 @@ static struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove = omap_i2c_remove, + .remove = __devexit_p(omap_i2c_remove), .driver = { .name = "omap_i2c", .owner = THIS_MODULE, -- cgit v1.2.3 From 5692d2a22ed9c1a1bc3030bd8188f335b1b0b58c Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 28 Jun 2012 20:41:28 +0530 Subject: i2c: omap: Use SET_RUNTIME_PM_OPS Use SET_RUNTIME_PM_OPS macro to set runtime functions. Acked-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b08607606014..b9915bb9343d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1126,6 +1126,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM #ifdef CONFIG_PM_RUNTIME static int omap_i2c_runtime_suspend(struct device *dev) { @@ -1174,15 +1175,16 @@ static int omap_i2c_runtime_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_RUNTIME */ static struct dev_pm_ops omap_i2c_pm_ops = { - .runtime_suspend = omap_i2c_runtime_suspend, - .runtime_resume = omap_i2c_runtime_resume, + SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) #else #define OMAP_I2C_PM_OPS NULL -#endif +#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, -- cgit v1.2.3 From 0e33bbb25436949cc100d40edfbe0f96dfa25882 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 28 Jun 2012 20:41:29 +0530 Subject: i2c: omap: Do not initialise the completion everytime Use INIT_COMPLETION instead of init_completion in transfer. 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(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b9915bb9343d..6d05f1878ca0 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -490,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - init_completion(&dev->cmd_complete); + INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -999,6 +999,7 @@ omap_i2c_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); + init_completion(&dev->cmd_complete); dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; -- cgit v1.2.3 From f518b482c89b3ff51804f09c14b1cedbef811b84 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 28 Jun 2012 20:41:31 +0530 Subject: i2c: omap: Correct I2C revision for OMAP3 The OMAP3530 is based upon the same silicon as the OMAP3430 and so the I2C revision is the same for 3430 and 3530. However, the OMAP3630 device has the same I2C revision as OMAP4. Correct the revision definition to reflect this. This patch is based on work done by Jon Hunter Changes from his patch - Update OMAP_I2C_REV_ON_3430 also to reflect that it is same as 3530 Reviewed-by: Felipe Balbi Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6d05f1878ca0..8c2d7cfb82da 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -49,8 +49,8 @@ /* I2C controller revisions present on specific hardware */ #define OMAP_I2C_REV_ON_2430 0x36 -#define OMAP_I2C_REV_ON_3430 0x3C -#define OMAP_I2C_REV_ON_3530_4430 0x40 +#define OMAP_I2C_REV_ON_3430_3530 0x3C +#define OMAP_I2C_REV_ON_3630_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -305,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_AUTOIDLE_MASK); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + } 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 << @@ -1020,7 +1020,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430) + if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { @@ -1038,7 +1038,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) + if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 0; /* Disable hardware fixes */ else dev->b_hw = 1; /* Enable hardware fixes */ -- cgit v1.2.3 From d61a9095155e832287552a9e565b8756ee293c46 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 8 Jul 2012 17:53:05 +0200 Subject: i2c-mv64xxxx: allow more than one driver instance The driver currently checks the platform device id and rejects platform device id different from 0. This prevents the registration of a second i2c controller on systems where a second one might be available (such as Kirkwood 88F6282). CC: Andrew Lunn Signed-off-by: Nicolas Schichan Signed-off-by: Florian Fainelli Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 4f44a33017b0..6e70eea0cd2f 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -528,7 +528,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; int rc; - if ((pd->id != 0) || !pdata) + if (!pdata) return -ENODEV; drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); -- cgit v1.2.3 From 925594e03550f1825647ea5408a32bb9803d90f1 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 13 Jun 2012 16:22:40 +0800 Subject: i2c: i2c-bfin-twi: Illegal i2c bus lock upon certain transfer scenarios. For transfer counts > 255 bytes i2c-bfin-twi sets the data transfer counter DCNT to 0xFF indicating unlimited transfers. It then uses a flag iface->manual_stop to manually issue the STOP condition, once the required amount of bytes are received. We found that on I2C receive operation issuing the STOP condition together with a FULL RCV FIFO (2bytes) will cause SDA and SCL be constantly driven low. Temporary workaround until further investigation: Discard the RCV FIFO before issuing the STOP condition. Signed-off-by: Michael Hennerich Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 515822429b19..c2e6b7849e8d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -131,6 +131,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, iface->transPtr++; iface->readNum--; } else if (iface->manual_stop) { + /* Temporary workaround to avoid possible bus stall - + * Flush FIFO before issuing the STOP condition + */ + read_RCV_DATA16(iface); write_MASTER_CTL(iface, read_MASTER_CTL(iface) | STOP); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && -- cgit v1.2.3 From a20a64d226be36808b24d2205b5d35e80c49e8be Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:41 +0800 Subject: i2c: i2c-bfin-twi: Improve the patch for bug "Illegal i2c bus lock upon certain transfer scenarios". For transfer counts > 255 bytes i2c-bfin-twi sets the data transfer counter DCNT to 0xFF indicating unlimited transfers. It then uses a flag iface->manual_stop to manually issue the STOP condition, once the required amount of bytes are received. We found that on I2C receive operation issuing the STOP condition together with a FULL RCV FIFO (2bytes) will cause SDA and SCL be constantly driven low. This patch stops receiving operation immediately in last rx interrupt. This patch also wakes up waiting process when transfer completes. Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 43 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 19 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index c2e6b7849e8d..4799c6886946 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -130,21 +130,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, } iface->transPtr++; iface->readNum--; - } else if (iface->manual_stop) { - /* Temporary workaround to avoid possible bus stall - - * Flush FIFO before issuing the STOP condition - */ - read_RCV_DATA16(iface); - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | STOP); - } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg + 1 < iface->msg_num) { - if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART | MDIR); - else + } + + if (iface->readNum == 0) { + if (iface->manual_stop) { + /* Temporary workaround to avoid possible bus stall - + * Flush FIFO before issuing the STOP condition + */ + read_RCV_DATA16(iface); write_MASTER_CTL(iface, - (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + read_MASTER_CTL(iface) | STOP); + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | RSTART | MDIR); + else + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + } } } if (twi_int_status & MERR) { @@ -245,12 +249,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, } } - if (iface->pmsg[iface->cur_msg].len <= 255) - write_MASTER_CTL(iface, + if (iface->pmsg[iface->cur_msg].len <= 255) { + write_MASTER_CTL(iface, (read_MASTER_CTL(iface) & (~(0xff << 6))) | - (iface->pmsg[iface->cur_msg].len << 6)); - else { + (iface->pmsg[iface->cur_msg].len << 6)); + iface->manual_stop = 0; + } else { write_MASTER_CTL(iface, (read_MASTER_CTL(iface) | (0xff << 6))); @@ -264,8 +269,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, write_INT_MASK(iface, 0); write_MASTER_CTL(iface, 0); } + complete(&iface->complete); } - complete(&iface->complete); } /* Interrupt handler */ -- cgit v1.2.3 From a25733d6f6968240042ac94dc93c7ae3c9e8d68b Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:42 +0800 Subject: i2c: i2c-bfin-twi: Break dead waiting loop if i2c device misbehaves. Some fault i2c device may hold the sda/scl line and cause i2c driver wait in the BUS busy loop. The I2C framework already retry the transfer loop before timeout. Return -EAGAIN instead of pull BUSBUSY in the other loop. Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 4799c6886946..5fb5f3ee13a2 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -307,8 +307,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, if (!(read_CONTROL(iface) & TWI_ENA)) return -ENXIO; - while (read_MASTER_STAT(iface) & BUSBUSY) - yield(); + if (read_MASTER_STAT(iface) & BUSBUSY) + return -EAGAIN; iface->pmsg = msgs; iface->msg_num = num; @@ -407,8 +407,8 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, if (!(read_CONTROL(iface) & TWI_ENA)) return -ENXIO; - while (read_MASTER_STAT(iface) & BUSBUSY) - yield(); + if (read_MASTER_STAT(iface) & BUSBUSY) + return -EAGAIN; iface->writeNum = 0; iface->readNum = 0; -- cgit v1.2.3 From 2ee74eb95cf36b1a69e483f9ba2191bd8022b2c1 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:43 +0800 Subject: i2c: i2c-bfin-twi: Tighten condition when failing I2C transfer if MEN bit is reset unexpectedly. In order to mark I2C transfer fail when MEN bit in I2C controller is reset unexpectedly in MCOMP interrupt, interrupt status bits XMTSERV or RCVSERV should be checked. Master Transfer Complete (MCOMP). [1] The initiated master transfer has completed. In the absence of a repeat start, the bus has been released. [0] The completion of a transfer has not been detected. Signed-off-by: Sonic Zhang [wsa: fixed spaces around operators and typo in commit message] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 5fb5f3ee13a2..71be486a224d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -201,7 +201,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, return; } if (twi_int_status & MCOMP) { - if ((read_MASTER_CTL(iface) & MEN) == 0 && + if (twi_int_status & (XMTSERV | RCVSERV) && + (read_MASTER_CTL(iface) & MEN) == 0 && (iface->cur_mode == TWI_I2C_MODE_REPEAT || iface->cur_mode == TWI_I2C_MODE_COMBINED)) { iface->result = -1; -- cgit v1.2.3 From 28a377c79af918fc40c70553216571314c5f42a4 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:44 +0800 Subject: i2c:i2c-bfin-twi: TWI fails to restart next transfer in high system load. Current driver was developed based on BF537 0.2 HRM. In high system load, BUFRDERR error interrupt may be raised if XMTSERV interrupt of last TX byte is not served in time (set RSTART bit), which breaks restart tranfer as expected. "Buffer Read Error (BUFRDERR)" description in Blackfin HRM only applys to BF537 rev. < 0.3. In later rev. and later announced Blackfin chips, such as BF527 and BF548, a new TWI master feature "Clock Stretching" is added into the TWI controller, BUFRDERR interrupt is not triggered after TX FIFO is empty. This patch sets RSTART bit at the beginning of the first transfer. The SCL and SDA is hold till XMTSERV interrupt of last TX byte is served. Restart transfer is not broken in high system load. Signed-off-by: Sonic Zhang [wsa: fixed spaces around operators] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 71be486a224d..2288e1bcf016 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -99,7 +99,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, */ else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MDIR | RSTART); + read_MASTER_CTL(iface) | MDIR); else if (iface->manual_stop) write_MASTER_CTL(iface, read_MASTER_CTL(iface) | STOP); @@ -107,10 +107,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, iface->cur_msg + 1 < iface->msg_num) { if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART | MDIR); + read_MASTER_CTL(iface) | MDIR); else write_MASTER_CTL(iface, - (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + read_MASTER_CTL(iface) & ~MDIR); } } if (twi_int_status & RCVSERV) { @@ -144,10 +144,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, iface->cur_msg + 1 < iface->msg_num) { if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART | MDIR); + read_MASTER_CTL(iface) | MDIR); else write_MASTER_CTL(iface, - (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + read_MASTER_CTL(iface) & ~MDIR); } } } @@ -230,7 +230,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg+1 < iface->msg_num) { + iface->cur_msg + 1 < iface->msg_num) { iface->cur_msg++; iface->transPtr = iface->pmsg[iface->cur_msg].buf; iface->writeNum = iface->readNum = @@ -262,9 +262,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, (0xff << 6))); iface->manual_stop = 1; } - /* remove restart bit and enable master receive */ - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) & ~RSTART); + /* remove restart bit before last message */ + if (iface->cur_msg + 1 == iface->msg_num) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) & ~RSTART); } else { iface->result = 1; write_INT_MASK(iface, 0); @@ -321,7 +322,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, return -EINVAL; } - iface->cur_mode = TWI_I2C_MODE_REPEAT; + if (iface->msg_num > 1) + iface->cur_mode = TWI_I2C_MODE_REPEAT; iface->manual_stop = 0; iface->transPtr = pmsg->buf; iface->writeNum = iface->readNum = pmsg->len; @@ -366,6 +368,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, /* Master enable */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | + (iface->msg_num > 1 ? RSTART : 0) | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); SSYNC(); @@ -530,7 +533,7 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, else write_MASTER_CTL(iface, 0x1 << 6); /* Master enable */ - write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | + write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | RSTART | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); break; default: -- cgit v1.2.3 From c9d87edbcc8c8a8517e5d5e870fca376864e8198 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:45 +0800 Subject: i2c:i2c-bfin-twi: include twi head file TWI bit mask macros are moved to twi head file. Depend on commit 61c16b5c7414b6d0511dc384e0ea994e250e6339 Signed-off-by: Sonic Zhang Signed-off-by: Bob Liu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 2288e1bcf016..39b8d77bf35c 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -25,6 +25,7 @@ #include #include #include +#include /* SMBus mode*/ #define TWI_I2C_MODE_STANDARD 1 -- cgit v1.2.3 From f88aafe513df2b2daad0883d70daee7a51e89c82 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:46 +0800 Subject: i2c: i2c-bfin-twi: Move TWI peripheral pin request array to platform data. Depend on commit cf93feb3a0dee97c7896016a352a3226139fbcf4 Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 39b8d77bf35c..f4fbbd211ddd 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -78,11 +78,6 @@ DEFINE_TWI_REG(XMT_DATA16, 0x84) DEFINE_TWI_REG(RCV_DATA8, 0x88) DEFINE_TWI_REG(RCV_DATA16, 0x8C) -static const u16 pin_req[2][3] = { - {P_TWI0_SCL, P_TWI0_SDA, 0}, - {P_TWI1_SCL, P_TWI1_SDA, 0}, -}; - static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, unsigned short twi_int_status) { @@ -712,7 +707,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) p_adap->timeout = 5 * HZ; p_adap->retries = 3; - rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi"); + rc = peripheral_request_list((unsigned short *)pdev->dev.platform_data, + "i2c-bfin-twi"); if (rc) { dev_err(&pdev->dev, "Can't setup pin mux!\n"); goto out_error_pin_mux; @@ -759,7 +755,7 @@ out_error_add_adapter: free_irq(iface->irq, iface); out_error_req_irq: out_error_no_irq: - peripheral_free_list(pin_req[pdev->id]); + peripheral_free_list((unsigned short *)pdev->dev.platform_data); out_error_pin_mux: iounmap(iface->regs_base); out_error_ioremap: @@ -777,7 +773,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev) i2c_del_adapter(&(iface->adap)); free_irq(iface->irq, iface); - peripheral_free_list(pin_req[pdev->id]); + peripheral_free_list((unsigned short *)pdev->dev.platform_data); iounmap(iface->regs_base); kfree(iface); -- cgit v1.2.3 From 90c16bbf57412d69fb29ca61a3942c8f433aa381 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 13 Jun 2012 16:22:47 +0800 Subject: i2c: i2c-bfin-twi: Move blackfin TWI register access Macro to head file. Depend on 1e92bf6d80b5a0a137455c96bf6cdd9c1a5b531e Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 45 --------------------------------------- 1 file changed, 45 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index f4fbbd211ddd..0cf780fd6ef1 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -33,51 +33,6 @@ #define TWI_I2C_MODE_COMBINED 3 #define TWI_I2C_MODE_REPEAT 4 -struct bfin_twi_iface { - int irq; - spinlock_t lock; - char read_write; - u8 command; - u8 *transPtr; - int readNum; - int writeNum; - int cur_mode; - int manual_stop; - int result; - struct i2c_adapter adap; - struct completion complete; - struct i2c_msg *pmsg; - int msg_num; - int cur_msg; - u16 saved_clkdiv; - u16 saved_control; - void __iomem *regs_base; -}; - - -#define DEFINE_TWI_REG(reg, off) \ -static inline u16 read_##reg(struct bfin_twi_iface *iface) \ - { return bfin_read16(iface->regs_base + (off)); } \ -static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \ - { bfin_write16(iface->regs_base + (off), v); } - -DEFINE_TWI_REG(CLKDIV, 0x00) -DEFINE_TWI_REG(CONTROL, 0x04) -DEFINE_TWI_REG(SLAVE_CTL, 0x08) -DEFINE_TWI_REG(SLAVE_STAT, 0x0C) -DEFINE_TWI_REG(SLAVE_ADDR, 0x10) -DEFINE_TWI_REG(MASTER_CTL, 0x14) -DEFINE_TWI_REG(MASTER_STAT, 0x18) -DEFINE_TWI_REG(MASTER_ADDR, 0x1C) -DEFINE_TWI_REG(INT_STAT, 0x20) -DEFINE_TWI_REG(INT_MASK, 0x24) -DEFINE_TWI_REG(FIFO_CTL, 0x28) -DEFINE_TWI_REG(FIFO_STAT, 0x2C) -DEFINE_TWI_REG(XMT_DATA8, 0x80) -DEFINE_TWI_REG(XMT_DATA16, 0x84) -DEFINE_TWI_REG(RCV_DATA8, 0x88) -DEFINE_TWI_REG(RCV_DATA16, 0x8C) - static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, unsigned short twi_int_status) { -- cgit v1.2.3 From cd4f2d4aa79ccbb2713f33f9c9f24ed21b5fc8fa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 9 Jul 2012 18:22:53 +0200 Subject: i2c: mxs: Set I2C timing registers for mxs-i2c This patch configures the I2C bus timing registers according to information passed via DT. Currently, 100kHz and 400kHz modes are supported. The TIMING2 register value is wrong in the documentation for i.MX28! This was found and fixed by: Shawn Guo Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mxs.txt | 3 ++ arch/arm/boot/dts/imx28.dtsi | 2 + drivers/i2c/busses/i2c-mxs.c | 66 +++++++++++++++++++++++ 3 files changed, 71 insertions(+) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt index 1bfc02de1b0c..30ac3a0557f7 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt @@ -4,6 +4,8 @@ Required properties: - compatible: Should be "fsl,-i2c" - reg: Should contain registers location and length - interrupts: Should contain ERROR and DMA interrupts +- clock-frequency: Desired I2C bus clock frequency in Hz. + Only 100000Hz and 400000Hz modes are supported. Examples: @@ -13,4 +15,5 @@ i2c0: i2c@80058000 { compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; }; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 4634cb861a59..9af1606b5d3c 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -381,6 +381,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; status = "disabled"; }; @@ -390,6 +391,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x8005a000 2000>; interrupts = <110 69>; + clock-frequency = <100000>; status = "disabled"; }; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 02ce1faeeeef..088c5c1ed17d 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -46,6 +46,10 @@ #define MXS_I2C_CTRL0_DIRECTION 0x00010000 #define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF) +#define MXS_I2C_TIMING0 (0x10) +#define MXS_I2C_TIMING1 (0x20) +#define MXS_I2C_TIMING2 (0x30) + #define MXS_I2C_CTRL1 (0x40) #define MXS_I2C_CTRL1_SET (0x44) #define MXS_I2C_CTRL1_CLR (0x48) @@ -97,6 +101,35 @@ #define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \ MXS_I2C_CTRL0_MASTER_MODE) +struct mxs_i2c_speed_config { + uint32_t timing0; + uint32_t timing1; + uint32_t timing2; +}; + +/* + * Timing values for the default 24MHz clock supplied into the i2c block. + * + * The bus can operate at 95kHz or at 400kHz with the following timing + * register configurations. The 100kHz mode isn't present because it's + * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode + * shall be close enough replacement. Therefore when the bus is configured + * for 100kHz operation, 95kHz timing settings are actually loaded. + * + * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4]. + */ +static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = { + .timing0 = 0x00780030, + .timing1 = 0x00800030, + .timing2 = 0x00300030, +}; + +static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = { + .timing0 = 0x000f0007, + .timing1 = 0x001f000f, + .timing2 = 0x00300030, +}; + /** * struct mxs_i2c_dev - per device, private MXS-I2C data * @@ -112,11 +145,17 @@ struct mxs_i2c_dev { struct completion cmd_complete; u32 cmd_err; struct i2c_adapter adapter; + const struct mxs_i2c_speed_config *speed; }; static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) { stmp_reset_block(i2c->regs); + + writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0); + writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1); + writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); + writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, i2c->regs + MXS_I2C_QUEUECTRL_SET); @@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) +{ + uint32_t speed; + struct device *dev = i2c->dev; + struct device_node *node = dev->of_node; + int ret; + + if (!node) + return -EINVAL; + + i2c->speed = &mxs_i2c_95kHz_config; + ret = of_property_read_u32(node, "clock-frequency", &speed); + if (ret) + dev_warn(dev, "No I2C speed selected, using 100kHz\n"); + else if (speed == 400000) + i2c->speed = &mxs_i2c_400kHz_config; + else if (speed != 100000) + dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n"); + + return 0; +} + static int __devinit mxs_i2c_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) return err; i2c->dev = dev; + + err = mxs_i2c_get_ofdata(i2c); + if (err) + return err; + platform_set_drvdata(pdev, i2c); /* Do reset to enforce correct startup after pinmuxing */ -- cgit v1.2.3 From b900ba4c1513a8c9a2fab8dca4cc6f50b17d6861 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Wed, 30 May 2012 11:43:05 +0200 Subject: i2c: s3c2410: Fix pointer type passed to of_match_node() This commit fixes warning introduced in 27452498a ("i2c-s3c2410: Rework device type handling"): drivers/i2c/busses/i2c-s3c2410.c: In function 's3c24xx_get_device_quirks': drivers/i2c/busses/i2c-s3c2410.c:125: warning: passing argument 1 of 'of_match_node' from incompatible pointer type include/linux/of.h:245: note: expected 'const struct of_device_id *' but argument is of type 'const struct of_device_id (*)[4]' Signed-off-by: Karol Lewandowski Signed-off-by: Kyungmin Park Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 01959154572d..e43614c4f217 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -122,7 +122,7 @@ static inline unsigned int s3c24xx_get_device_quirks(struct platform_device *pde { if (pdev->dev.of_node) { const struct of_device_id *match; - match = of_match_node(&s3c24xx_i2c_match, pdev->dev.of_node); + match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node); return (unsigned int)match->data; } -- cgit v1.2.3 From a86ae9ff2905ebff4689bcd4946d7a95d9f5f237 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 28 Jun 2012 14:08:26 +0100 Subject: i2c-s3c2410: Use plain pm_runtime_put() There's no point in using _sync() as we don't really care if the suspend has completed immediately. Signed-off-by: Mark Brown Reviewed-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index e43614c4f217..5ae3b0236bd3 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -609,7 +609,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, if (ret != -EAGAIN) { clk_disable(i2c->clk); - pm_runtime_put_sync(&adap->dev); + pm_runtime_put(&adap->dev); return ret; } @@ -619,7 +619,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, } clk_disable(i2c->clk); - pm_runtime_put_sync(&adap->dev); + pm_runtime_put(&adap->dev); return -EREMOTEIO; } -- cgit v1.2.3 From 097df403128c858c646448c5181435f7b8bdcbdc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 12 Jul 2012 15:56:53 +0200 Subject: i2c: mv64xxxx: remove EXPERIMENTAL tag As git history indicates, the driver predates the git era and is heavily used and worked on since. Not EXPERIMENTAL anymore. Signed-off-by: Wolfram Sang Cc: Rodolfo Giometti Cc: Florian Fainelli --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e9f9c5dc87ce..52a825a4a19f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -458,7 +458,7 @@ config I2C_MPC config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL + depends on (MV64X60 || PLAT_ORION) help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. -- cgit v1.2.3 From 9ae97a8996a6d6f66e2fbc221906e2406d6c261f Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Fri, 13 Jul 2012 19:14:22 +0530 Subject: i2c: i2c-ocores: DT bindings and minor fixes. Cleanups to i2c-cores, no change in logic, changes are: * Move i2c-ocores device tree documentation from source file to Documentation/devicetree/bindings/i2c/i2c-ocores.txt. * Add \n to dev_warn and dev_err messages where missing * Minor updates to the text and formatting fixes. Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 27 +++++++++++++ drivers/i2c/busses/i2c-ocores.c | 45 ++++------------------ 2 files changed, 34 insertions(+), 38 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ocores.txt (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt new file mode 100644 index 000000000000..bfec8941509c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -0,0 +1,27 @@ +Device tree configuration for i2c-ocores + +Required properties: +- compatible : "opencores,i2c-ocores" +- reg : bus address start and address range size of device +- interrupts : interrupt number +- regstep : size of device registers in bytes +- clock-frequency : frequency of bus clock in Hz +- #address-cells : should be <1> +- #size-cells : should be <0> + +Example: + + i2c0: ocores@a0000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "opencores,i2c-ocores"; + reg = <0xa0000000 0x8>; + interrupts = <10>; + regstep = <1>; + clock-frequency = <20000000>; + + dummy@60 { + compatible = "dummy"; + reg = <0x60>; + }; + }; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index d7d21d532557..f6e7ad9f60e9 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -10,40 +10,9 @@ */ /* - * Device tree configuration: - * - * Required properties: - * - compatible : "opencores,i2c-ocores" - * - reg : bus address start and address range size of device - * - interrupts : interrupt number - * - regstep : size of device registers in bytes - * - clock-frequency : frequency of bus clock in Hz - * - * Example: - * - * i2c0: ocores@a0000000 { - * compatible = "opencores,i2c-ocores"; - * reg = <0xa0000000 0x8>; - * interrupts = <10>; - * - * regstep = <1>; - * clock-frequency = <20000000>; - * - * -- Devices connected on this I2C bus get - * -- defined here; address- and size-cells - * -- apply to these child devices - * - * #address-cells = <1>; - * #size-cells = <0>; - * - * dummy@60 { - * compatible = "dummy"; - * reg = <60>; - * }; - * }; - * + * This driver can be used from the device tree, see + * Documentation/devicetree/bindings/i2c/ocore-i2c.txt */ - #include #include #include @@ -247,14 +216,14 @@ static struct i2c_adapter ocores_adapter = { }; #ifdef CONFIG_OF -static int ocores_i2c_of_probe(struct platform_device* pdev, - struct ocores_i2c* i2c) +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) { const __be32* val; val = of_get_property(pdev->dev.of_node, "regstep", NULL); if (!val) { - dev_err(&pdev->dev, "Missing required parameter 'regstep'"); + dev_err(&pdev->dev, "Missing required parameter 'regstep'\n"); return -ENODEV; } i2c->regstep = be32_to_cpup(val); @@ -262,7 +231,7 @@ static int ocores_i2c_of_probe(struct platform_device* pdev, val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); if (!val) { dev_err(&pdev->dev, - "Missing required parameter 'clock-frequency'"); + "Missing required parameter 'clock-frequency'\n"); return -ENODEV; } i2c->clock_khz = be32_to_cpup(val) / 1000; @@ -351,7 +320,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return 0; } -static int __devexit ocores_i2c_remove(struct platform_device* pdev) +static int __devexit ocores_i2c_remove(struct platform_device *pdev) { struct ocores_i2c *i2c = platform_get_drvdata(pdev); -- cgit v1.2.3 From 8bb986a816148d6e8fbaae23be0fee33d6a1ae3f Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Fri, 13 Jul 2012 19:14:23 +0530 Subject: i2c: i2c-ocores: Use reg-shift property Deprecate 'regstep' property and use the standard 'reg-shift' property for register offset shifts. 'regstep' will still be supported as an optional property, but will give a warning when used. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 8 +++-- drivers/i2c/busses/i2c-ocores.c | 36 +++++++++++++--------- include/linux/i2c-ocores.h | 2 +- 3 files changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index bfec8941509c..1c9334bfc39c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -4,11 +4,14 @@ Required properties: - compatible : "opencores,i2c-ocores" - reg : bus address start and address range size of device - interrupts : interrupt number -- regstep : size of device registers in bytes - clock-frequency : frequency of bus clock in Hz - #address-cells : should be <1> - #size-cells : should be <0> +Optional properties: +- reg-shift : device register offsets are shifted by this value +- regstep : deprecated, use reg-shift above + Example: i2c0: ocores@a0000000 { @@ -17,9 +20,10 @@ Example: compatible = "opencores,i2c-ocores"; reg = <0xa0000000 0x8>; interrupts = <10>; - regstep = <1>; clock-frequency = <20000000>; + reg-shift = <0>; /* 8 bit registers */ + dummy@60 { compatible = "dummy"; reg = <0x60>; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index f6e7ad9f60e9..9e0709d5fb36 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -25,10 +25,11 @@ #include #include #include +#include struct ocores_i2c { void __iomem *base; - int regstep; + u32 reg_shift; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -71,12 +72,12 @@ struct ocores_i2c { static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { - iowrite8(value, i2c->base + reg * i2c->regstep); + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - return ioread8(i2c->base + reg * i2c->regstep); + return ioread8(i2c->base + (reg << i2c->reg_shift)); } static void ocores_process(struct ocores_i2c *i2c) @@ -219,22 +220,29 @@ static struct i2c_adapter ocores_adapter = { static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { - const __be32* val; - - val = of_get_property(pdev->dev.of_node, "regstep", NULL); - if (!val) { - dev_err(&pdev->dev, "Missing required parameter 'regstep'\n"); - return -ENODEV; + struct device_node *np = pdev->dev.of_node; + u32 val; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } } - i2c->regstep = be32_to_cpup(val); - val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); - if (!val) { + if (of_property_read_u32(np, "clock-frequency", &val)) { dev_err(&pdev->dev, "Missing required parameter 'clock-frequency'\n"); return -ENODEV; } - i2c->clock_khz = be32_to_cpup(val) / 1000; + i2c->clock_khz = val / 1000; return 0; } @@ -277,7 +285,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { - i2c->regstep = pdata->regstep; + i2c->reg_shift = pdata->reg_shift; i2c->clock_khz = pdata->clock_khz; } else { ret = ocores_i2c_of_probe(pdev, i2c); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 4d5e57ff6614..5d95df2436f4 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -12,7 +12,7 @@ #define _LINUX_I2C_OCORES_H struct ocores_i2c_platform_data { - u32 regstep; /* distance between registers */ + u32 reg_shift; /* register offset shift value */ u32 clock_khz; /* input clock in kHz */ u8 num_devices; /* number of devices in the devices list */ struct i2c_board_info const *devices; /* devices connected to the bus */ -- cgit v1.2.3 From 7326e38ffe894d0cd2904704b7d8c53d4a55d752 Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Fri, 13 Jul 2012 19:14:25 +0530 Subject: i2c: i2c-ocores: support for 16bit and 32bit IO Some architectures supports only 16-bit or 32-bit read/write access to their IO space. Add a 'reg-io-width' platform and OF parameter which specifies the IO width to support these platforms. reg-io-width can be specified as 1, 2 or 4, and has a default value of 1 if it is unspecified. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 2 ++ drivers/i2c/busses/i2c-ocores.c | 21 +++++++++++++++++++-- include/linux/i2c-ocores.h | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index 1c9334bfc39c..c15781f4dc8c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -10,6 +10,7 @@ Required properties: Optional properties: - reg-shift : device register offsets are shifted by this value +- reg-io-width : io register width in bytes (1, 2 or 4) - regstep : deprecated, use reg-shift above Example: @@ -23,6 +24,7 @@ Example: clock-frequency = <20000000>; reg-shift = <0>; /* 8 bit registers */ + reg-io-width = <1>; /* 8 bit read/write */ dummy@60 { compatible = "dummy"; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 9e0709d5fb36..bffd5501ac2d 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -30,6 +30,7 @@ struct ocores_i2c { void __iomem *base; u32 reg_shift; + u32 reg_io_width; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -72,12 +73,22 @@ struct ocores_i2c { static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { - iowrite8(value, i2c->base + (reg << i2c->reg_shift)); + 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)); + else + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - return ioread8(i2c->base + (reg << i2c->reg_shift)); + 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)); } static void ocores_process(struct ocores_i2c *i2c) @@ -244,6 +255,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, } i2c->clock_khz = val / 1000; + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); return 0; } #else @@ -286,6 +299,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; i2c->clock_khz = pdata->clock_khz; } else { ret = ocores_i2c_of_probe(pdev, i2c); @@ -293,6 +307,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return ret; } + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + ocores_init(i2c); init_waitqueue_head(&i2c->wait); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 5d95df2436f4..1c06b5c7c308 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -13,6 +13,7 @@ struct ocores_i2c_platform_data { u32 reg_shift; /* register offset shift value */ + u32 reg_io_width; /* register io read/write width */ u32 clock_khz; /* input clock in kHz */ u8 num_devices; /* number of devices in the devices list */ struct i2c_board_info const *devices; /* devices connected to the bus */ -- cgit v1.2.3 From 6f535b94261b16343cfbc4576a941bd7901b96e1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 16 Jul 2012 13:30:12 +0200 Subject: i2c: stu300: use devm managed resources Allocate memory for device state using devm_kzalloc(), get the clock using devm_clk_get(), get the IRQ using devm_request_irq(), request and remap memory using devm_request_and_ioremap(). All to simplify accounting and letting the kernel do the garbage-collection. Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stu300.c | 83 +++++++++-------------------------------- 1 file changed, 18 insertions(+), 65 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 80dd1c074a08..580a0c04cb42 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2009 ST-Ericsson AB + * Copyright (C) 2007-2012 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 * ST DDC I2C master mode driver, used in e.g. U300 series platforms. * Author: Linus Walleij @@ -139,8 +139,6 @@ module_param(scl_frequency, uint, 0644); * struct stu300_dev - the stu300 driver state holder * @pdev: parent platform device * @adapter: corresponding I2C adapter - * @phybase: location of I/O area in memory - * @physize: size of I/O area in memory * @clk: hardware block clock * @irq: assigned interrupt line * @cmd_issue_lock: this locks the following cmd_ variables @@ -155,8 +153,6 @@ module_param(scl_frequency, uint, 0644); struct stu300_dev { struct platform_device *pdev; struct i2c_adapter adapter; - resource_size_t phybase; - resource_size_t physize; void __iomem *virtbase; struct clk *clk; int irq; @@ -873,64 +869,44 @@ stu300_probe(struct platform_device *pdev) int ret = 0; char clk_name[] = "I2C0"; - dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL); if (!dev) { dev_err(&pdev->dev, "could not allocate device struct\n"); - ret = -ENOMEM; - goto err_no_devmem; + return -ENOMEM; } bus_nr = pdev->id; clk_name[3] += (char)bus_nr; - dev->clk = clk_get(&pdev->dev, clk_name); + dev->clk = devm_clk_get(&pdev->dev, clk_name); if (IS_ERR(dev->clk)) { - ret = PTR_ERR(dev->clk); dev_err(&pdev->dev, "could not retrieve i2c bus clock\n"); - goto err_no_clk; + return PTR_ERR(dev->clk); } dev->pdev = pdev; - platform_set_drvdata(pdev, dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENOENT; - goto err_no_resource; - } + if (!res) + return -ENOENT; - dev->phybase = res->start; - dev->physize = resource_size(res); - - if (request_mem_region(dev->phybase, dev->physize, - NAME " I/O Area") == NULL) { - ret = -EBUSY; - goto err_no_ioregion; - } - - dev->virtbase = ioremap(dev->phybase, dev->physize); + dev->virtbase = devm_request_and_ioremap(&pdev->dev, res); dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual " "base %p\n", bus_nr, dev->virtbase); - if (!dev->virtbase) { - ret = -ENOMEM; - goto err_no_ioremap; - } + if (!dev->virtbase) + return -ENOMEM; dev->irq = platform_get_irq(pdev, 0); - if (request_irq(dev->irq, stu300_irh, 0, - NAME, dev)) { - ret = -EIO; - goto err_no_irq; - } + ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev); + if (ret < 0) + return ret; dev->speed = scl_frequency; clk_prepare_enable(dev->clk); ret = stu300_init_hw(dev); clk_disable(dev->clk); - if (ret != 0) { dev_err(&dev->pdev->dev, "error initializing hardware.\n"); - goto err_init_hw; + return -EIO; } /* IRQ event handling initialization */ @@ -952,30 +928,13 @@ stu300_probe(struct platform_device *pdev) /* i2c device drivers may be active on return from add_adapter() */ ret = i2c_add_numbered_adapter(adap); if (ret) { - dev_err(&dev->pdev->dev, "failure adding ST Micro DDC " + dev_err(&pdev->dev, "failure adding ST Micro DDC " "I2C adapter\n"); - goto err_add_adapter; + return ret; } - return 0; - err_add_adapter: - err_init_hw: - clk_unprepare(dev->clk); - free_irq(dev->irq, dev); - err_no_irq: - iounmap(dev->virtbase); - err_no_ioremap: - release_mem_region(dev->phybase, dev->physize); - err_no_ioregion: - platform_set_drvdata(pdev, NULL); - err_no_resource: - clk_put(dev->clk); - err_no_clk: - kfree(dev); - err_no_devmem: - dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n", - pdev->id); - return ret; + platform_set_drvdata(pdev, dev); + return 0; } #ifdef CONFIG_PM @@ -1016,13 +975,7 @@ stu300_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); /* Turn off everything */ stu300_wr8(0x00, dev->virtbase + I2C_CR); - free_irq(dev->irq, dev); - iounmap(dev->virtbase); - release_mem_region(dev->phybase, dev->physize); - clk_unprepare(dev->clk); - clk_put(dev->clk); platform_set_drvdata(pdev, NULL); - kfree(dev); return 0; } -- cgit v1.2.3 From d38a0149e8a11ca333c1a6c489a2ccac2b73f2cb Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 17 Jul 2012 13:34:18 -0400 Subject: i2c-pmcmsp: remove IRQF_SAMPLE_RANDOM which is now a no-op With the changes in the random tree, IRQF_SAMPLE_RANDOM is now a no-op; interrupt randomness is now collected unconditionally in a very low-overhead fashion; see commit 775f4b297b. The IRQF_SAMPLE_RANDOM flag was scheduled to be removed in 2009 on the feature-removal-schedule, so this patch is preparation for the final removal of this flag. Signed-off-by: "Theodore Ts'o" Cc: "Ben Dooks" Cc: "Wolfram Sang" --- drivers/i2c/busses/i2c-pmcmsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 07b7447ecbc9..3d71395ae1f7 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -306,8 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) pmcmsptwi_data.irq = platform_get_irq(pldev, 0); if (pmcmsptwi_data.irq) { rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, - pldev->name, &pmcmsptwi_data); + IRQF_SHARED, pldev->name, &pmcmsptwi_data); if (rc == 0) { /* * Enable 'DONE' interrupt only. -- cgit v1.2.3 From f353a218de6393fb43a5e81c3adbe1aac1a871ab Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:39 +0200 Subject: i2c: Convert i2c-octeon.c to use device tree. There are three parts to this: 1) Remove the definitions of OCTEON_IRQ_TWSI and OCTEON_IRQ_TWSI2. The interrupts are specified by the device tree and these hard coded irq numbers block the used of the irq lines by the irq_domain code. 2) Remove platform device setup code from octeon-platform.c, it is now unused. 3) Convert i2c-octeon.c to use device tree. Part of this includes using the devm_* functions instead of the raw counterparts, thus simplifying error handling. No functionality is changed. Signed-off-by: David Daney Acked-by: Rob Herring Acked-by: Wolfram Sang Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/3939/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/octeon-irq.c | 2 - arch/mips/cavium-octeon/octeon-platform.c | 84 ---------------------------- arch/mips/include/asm/octeon/octeon.h | 5 -- drivers/i2c/busses/i2c-octeon.c | 92 ++++++++++++++++--------------- 4 files changed, 49 insertions(+), 134 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 52610ce50dfc..2a661ad35cf7 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1192,13 +1192,11 @@ static void __init octeon_irq_init_ciu(void) for (i = 0; i < 4; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI, 0, 45, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq); for (i = 0; i < 4; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI2, 0, 59, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq); diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 2754bc225903..f62a40f424ca 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -168,90 +168,6 @@ out: } device_initcall(octeon_rng_device_init); -static struct i2c_board_info __initdata octeon_i2c_devices[] = { - { - I2C_BOARD_INFO("ds1337", 0x68), - }, -}; - -static int __init octeon_i2c_devices_init(void) -{ - return i2c_register_board_info(0, octeon_i2c_devices, - ARRAY_SIZE(octeon_i2c_devices)); -} -arch_initcall(octeon_i2c_devices_init); - -#define OCTEON_I2C_IO_BASE 0x1180000001000ull -#define OCTEON_I2C_IO_UNIT_OFFSET 0x200 - -static struct octeon_i2c_data octeon_i2c_data[2]; - -static int __init octeon_i2c_device_init(void) -{ - struct platform_device *pd; - int ret = 0; - int port, num_ports; - - struct resource i2c_resources[] = { - { - .flags = IORESOURCE_MEM, - }, { - .flags = IORESOURCE_IRQ, - } - }; - - if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) - num_ports = 2; - else - num_ports = 1; - - for (port = 0; port < num_ports; port++) { - octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate(); - /*FIXME: should be examined. At the moment is set for 100Khz */ - octeon_i2c_data[port].i2c_freq = 100000; - - pd = platform_device_alloc("i2c-octeon", port); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - pd->dev.platform_data = octeon_i2c_data + port; - - i2c_resources[0].start = - OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET); - i2c_resources[0].end = i2c_resources[0].start + 0x1f; - switch (port) { - case 0: - i2c_resources[1].start = OCTEON_IRQ_TWSI; - i2c_resources[1].end = OCTEON_IRQ_TWSI; - break; - case 1: - i2c_resources[1].start = OCTEON_IRQ_TWSI2; - i2c_resources[1].end = OCTEON_IRQ_TWSI2; - break; - default: - BUG(); - } - - ret = platform_device_add_resources(pd, - i2c_resources, - ARRAY_SIZE(i2c_resources)); - if (ret) - goto fail; - - ret = platform_device_add(pd); - if (ret) - goto fail; - } - return ret; -fail: - platform_device_put(pd); -out: - return ret; -} -device_initcall(octeon_i2c_device_init); - /* Octeon SMI/MDIO interface. */ static int __init octeon_mdiobus_device_init(void) { diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index f72f768cd3a4..1e2486e23573 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -215,11 +215,6 @@ struct octeon_cf_data { int dma_engine; /* -1 for no DMA */ }; -struct octeon_i2c_data { - unsigned int sys_freq; - unsigned int i2c_freq; -}; - extern void octeon_write_lcd(const char *s); extern void octeon_check_cpu_bist(void); extern int octeon_get_boot_debug_flag(void); diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index ee139a598814..f44c83549fe5 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -2,7 +2,7 @@ * (C) Copyright 2009-2010 * Nokia Siemens Networks, michael.lawnick.ext@nsn.com * - * Portions Copyright (C) 2010 Cavium Networks, Inc. + * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc. * * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. * @@ -11,17 +11,18 @@ * warranty of any kind, whether express or implied. */ +#include +#include #include #include +#include +#include #include #include #include - -#include #include -#include -#include -#include +#include +#include #include @@ -65,7 +66,7 @@ struct octeon_i2c { wait_queue_head_t queue; struct i2c_adapter adap; int irq; - int twsi_freq; + u32 twsi_freq; int sys_freq; resource_size_t twsi_phys; void __iomem *twsi_base; @@ -121,10 +122,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg) */ static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) { - u64 tmp; - __raw_writeq(data, i2c->twsi_base + TWSI_INT); - tmp = __raw_readq(i2c->twsi_base + TWSI_INT); + __raw_readq(i2c->twsi_base + TWSI_INT); } /** @@ -515,7 +514,6 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev) { int irq, result = 0; struct octeon_i2c *i2c; - struct octeon_i2c_data *i2c_data; struct resource *res_mem; /* All adaptors have an irq. */ @@ -523,86 +521,90 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev) if (irq < 0) return irq; - i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) { dev_err(&pdev->dev, "kzalloc failed\n"); result = -ENOMEM; goto out; } i2c->dev = &pdev->dev; - i2c_data = pdev->dev.platform_data; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res_mem == NULL) { dev_err(i2c->dev, "found no memory resource\n"); result = -ENXIO; - goto fail_region; + goto out; } + i2c->twsi_phys = res_mem->start; + i2c->regsize = resource_size(res_mem); - if (i2c_data == NULL) { - dev_err(i2c->dev, "no I2C frequency data\n"); + /* + * "clock-rate" is a legacy binding, the official binding is + * "clock-frequency". Try the official one first and then + * fall back if it doesn't exist. + */ + if (of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &i2c->twsi_freq) && + of_property_read_u32(pdev->dev.of_node, + "clock-rate", &i2c->twsi_freq)) { + dev_err(i2c->dev, + "no I2C 'clock-rate' or 'clock-frequency' property\n"); result = -ENXIO; - goto fail_region; + goto out; } - i2c->twsi_phys = res_mem->start; - i2c->regsize = resource_size(res_mem); - i2c->twsi_freq = i2c_data->i2c_freq; - i2c->sys_freq = i2c_data->sys_freq; + i2c->sys_freq = octeon_get_io_clock_rate(); - if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) { + if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize, + res_mem->name)) { dev_err(i2c->dev, "request_mem_region failed\n"); - goto fail_region; + goto out; } - i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize); + i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize); init_waitqueue_head(&i2c->queue); i2c->irq = irq; - result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c); + result = devm_request_irq(&pdev->dev, i2c->irq, + octeon_i2c_isr, 0, DRV_NAME, i2c); if (result < 0) { dev_err(i2c->dev, "failed to attach interrupt\n"); - goto fail_irq; + goto out; } result = octeon_i2c_initlowlevel(i2c); if (result) { dev_err(i2c->dev, "init low level failed\n"); - goto fail_add; + goto out; } result = octeon_i2c_setclock(i2c); if (result) { dev_err(i2c->dev, "clock init failed\n"); - goto fail_add; + goto out; } i2c->adap = octeon_i2c_ops; i2c->adap.dev.parent = &pdev->dev; - i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; + i2c->adap.dev.of_node = pdev->dev.of_node; i2c_set_adapdata(&i2c->adap, i2c); platform_set_drvdata(pdev, i2c); - result = i2c_add_numbered_adapter(&i2c->adap); + result = i2c_add_adapter(&i2c->adap); if (result < 0) { dev_err(i2c->dev, "failed to add adapter\n"); goto fail_add; } - dev_info(i2c->dev, "version %s\n", DRV_VERSION); - return result; + of_i2c_register_devices(&i2c->adap); + + return 0; fail_add: platform_set_drvdata(pdev, NULL); - free_irq(i2c->irq, i2c); -fail_irq: - iounmap(i2c->twsi_base); - release_mem_region(i2c->twsi_phys, i2c->regsize); -fail_region: - kfree(i2c); out: return result; }; @@ -613,19 +615,24 @@ static int __devexit octeon_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); platform_set_drvdata(pdev, NULL); - free_irq(i2c->irq, i2c); - iounmap(i2c->twsi_base); - release_mem_region(i2c->twsi_phys, i2c->regsize); - kfree(i2c); return 0; }; +static struct of_device_id octeon_i2c_match[] = { + { + .compatible = "cavium,octeon-3860-twsi", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_i2c_match); + static struct platform_driver octeon_i2c_driver = { .probe = octeon_i2c_probe, .remove = __devexit_p(octeon_i2c_remove), .driver = { .owner = THIS_MODULE, .name = DRV_NAME, + .of_match_table = octeon_i2c_match, }, }; @@ -635,4 +642,3 @@ MODULE_AUTHOR("Michael Lawnick "); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From b61d15758941166b9cac41b87751dea21978bebc Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 22 Jul 2012 12:51:35 +0200 Subject: I2C: MV64XYZ: Add Device Tree support Extends the driver to get properties from device tree. Rather than pass the N & M factors in DT, use the more standard clock-frequency property. Calculate N & M at run time. In order to do this, we need to know tclk. So the driver uses clk_get() etc in order to get the clock and clk_get_rate() to determine the tclk rate. Not all platforms however have CLK, so some #ifdefery is needed to ensure the driver still compiles when CLK is not available. Signed-off-by: Andrew Lunn [wsa: converted some ints to u32 to match signedness] Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/mrvl-i2c.txt | 19 ++- drivers/i2c/busses/i2c-mv64xxx.c | 133 ++++++++++++++++++++- 2 files changed, 146 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt index b891ee218354..0f7945019f6f 100644 --- a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt @@ -1,4 +1,4 @@ -* I2C +* Marvell MMP I2C controller Required properties : @@ -32,3 +32,20 @@ Examples: interrupts = <58>; }; +* Marvell MV64XXX I2C controller + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : Should be "marvell,mv64xxx-i2c" + - interrupts : The interrupt number + - clock-frequency : Desired I2C bus clock frequency in Hz. + +Examples: + + i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + interrupts = <29>; + clock-frequency = <100000>; + }; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6e70eea0cd2f..2e9d56719e99 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -18,6 +18,11 @@ #include #include #include +#include +#include +#include +#include +#include /* Register defines */ #define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 @@ -98,6 +103,9 @@ struct mv64xxx_i2c_data { int rc; u32 freq_m; u32 freq_n; +#if defined(CONFIG_HAVE_CLK) + struct clk *clk; +#endif wait_queue_head_t waitq; spinlock_t lock; struct i2c_msg *msg; @@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) drv_data->reg_base_p = 0; } +#ifdef CONFIG_OF +static int __devinit +mv64xxx_calc_freq(const int tclk, const int n, const int m) +{ + return tclk / (10 * (m + 1) * (2 << n)); +} + +static bool __devinit +mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, + u32 *best_m) +{ + int freq, delta, best_delta = INT_MAX; + int m, n; + + for (n = 0; n <= 7; n++) + for (m = 0; m <= 15; m++) { + freq = mv64xxx_calc_freq(tclk, n, m); + delta = req_freq - freq; + if (delta >= 0 && delta < best_delta) { + *best_m = m; + *best_n = n; + best_delta = delta; + } + if (best_delta == 0) + return true; + } + if (best_delta == INT_MAX) + return false; + return true; +} + +static int __devinit +mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + struct device_node *np) +{ + u32 bus_freq, tclk; + int rc = 0; + + /* CLK is mandatory when using DT to describe the i2c bus. We + * need to know tclk in order to calculate bus clock + * factors. + */ +#if !defined(CONFIG_HAVE_CLK) + /* Have OF but no CLK */ + return -ENODEV; +#else + if (IS_ERR(drv_data->clk)) { + rc = -ENODEV; + goto out; + } + tclk = clk_get_rate(drv_data->clk); + of_property_read_u32(np, "clock-frequency", &bus_freq); + if (!mv64xxx_find_baud_factors(bus_freq, tclk, + &drv_data->freq_n, &drv_data->freq_m)) { + rc = -EINVAL; + goto out; + } + drv_data->irq = irq_of_parse_and_map(np, 0); + + /* Its not yet defined how timeouts will be specified in device tree. + * So hard code the value to 1 second. + */ + drv_data->adapter.timeout = HZ; +out: + return rc; +#endif +} +#else /* CONFIG_OF */ +static int __devinit +mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + struct device_node *np) +{ + return -ENODEV; +} +#endif /* CONFIG_OF */ + static int __devinit mv64xxx_i2c_probe(struct platform_device *pd) { @@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; int rc; - if (!pdata) + if ((!pdata && !pd->dev.of_node)) return -ENODEV; drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); @@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd) init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); - drv_data->freq_m = pdata->freq_m; - drv_data->freq_n = pdata->freq_n; - drv_data->irq = platform_get_irq(pd, 0); +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + drv_data->clk = clk_get(&pd->dev, NULL); + if (!IS_ERR(drv_data->clk)) { + clk_prepare(drv_data->clk); + clk_enable(drv_data->clk); + } +#endif + if (pdata) { + drv_data->freq_m = pdata->freq_m; + drv_data->freq_n = pdata->freq_n; + drv_data->irq = platform_get_irq(pd, 0); + drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); + } else if (pd->dev.of_node) { + rc = mv64xxx_of_config(drv_data, pd->dev.of_node); + if (rc) + goto exit_unmap_regs; + } if (drv_data->irq < 0) { rc = -ENXIO; goto exit_unmap_regs; } + drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); drv_data->adapter.nr = pd->id; + drv_data->adapter.dev.of_node = pd->dev.of_node; platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); @@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) goto exit_free_irq; } + of_i2c_register_devices(&drv_data->adapter); + return 0; exit_free_irq: free_irq(drv_data->irq, drv_data); exit_unmap_regs: +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + if (!IS_ERR(drv_data->clk)) { + clk_disable(drv_data->clk); + clk_unprepare(drv_data->clk); + } +#endif mv64xxx_i2c_unmap_regs(drv_data); exit_kfree: kfree(drv_data); @@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev) rc = i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); mv64xxx_i2c_unmap_regs(drv_data); +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + if (!IS_ERR(drv_data->clk)) { + clk_disable(drv_data->clk); + clk_unprepare(drv_data->clk); + } +#endif kfree(drv_data); return rc; } +static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = { + { .compatible = "marvell,mv64xxx-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); + static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, .remove = __devexit_p(mv64xxx_i2c_remove), .driver = { .owner = THIS_MODULE, .name = MV64XXX_I2C_CTLR_NAME, + .of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table), }, }; -- cgit v1.2.3 From 83a638df36eee8b6b6aeda9d122359e55adad2a2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 24 Jul 2012 14:13:56 +0200 Subject: i2c: Update Guenter Roeck's e-mail address My old e-mail address won't be valid for much longer. Time to update it. Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-diolan-u2c.c | 2 +- drivers/i2c/muxes/i2c-mux-pca9541.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index 7eb19a5222f2..aedb94f34bf7 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -517,6 +517,6 @@ static struct usb_driver diolan_u2c_driver = { module_usb_driver(diolan_u2c_driver); -MODULE_AUTHOR("Guenter Roeck "); +MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION(DRIVER_NAME " driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 8aacde1516ac..f8f72f39e0b5 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -396,6 +396,6 @@ static struct i2c_driver pca9541_driver = { module_i2c_driver(pca9541_driver); -MODULE_AUTHOR("Guenter Roeck "); +MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 56f2178898ffca84dcdfb351f0127bf5732b1610 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 24 Jul 2012 14:13:56 +0200 Subject: i2c/busses: Use module_pci_driver Convert the drivers in drivers/i2c/busses/* to usemodule_pci_driver() macro which makes the code smaller and a bit simpler. Signed-off-by: Axel Lin Acked-by: Wolfram Sang Signed-off-by: Jean Delvare Cc: Rudolf Marek Cc: Olof Johansson Cc: "Mark M. Hoffman" Cc: Tomoya MORINAGA --- drivers/i2c/busses/i2c-ali1535.c | 13 +------------ drivers/i2c/busses/i2c-ali1563.c | 14 +------------- drivers/i2c/busses/i2c-ali15x3.c | 13 +------------ drivers/i2c/busses/i2c-amd756.c | 13 +------------ drivers/i2c/busses/i2c-amd8111.c | 13 +------------ drivers/i2c/busses/i2c-designware-pcidrv.c | 12 +----------- drivers/i2c/busses/i2c-eg20t.c | 12 +----------- drivers/i2c/busses/i2c-hydra.c | 17 +---------------- drivers/i2c/busses/i2c-intel-mid.c | 13 +------------ drivers/i2c/busses/i2c-nforce2.c | 14 +------------- drivers/i2c/busses/i2c-pasemi.c | 13 +------------ drivers/i2c/busses/i2c-piix4.c | 13 +------------ drivers/i2c/busses/i2c-pxa-pci.c | 12 +----------- drivers/i2c/busses/i2c-sis630.c | 15 +-------------- drivers/i2c/busses/i2c-sis96x.c | 15 +-------------- drivers/i2c/busses/i2c-via.c | 14 +------------- 16 files changed, 16 insertions(+), 200 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index e66d248fc126..125cd8e0ad25 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -531,15 +531,7 @@ static struct pci_driver ali1535_driver = { .remove = __devexit_p(ali1535_remove), }; -static int __init i2c_ali1535_init(void) -{ - return pci_register_driver(&ali1535_driver); -} - -static void __exit i2c_ali1535_exit(void) -{ - pci_unregister_driver(&ali1535_driver); -} +module_pci_driver(ali1535_driver); MODULE_AUTHOR("Frodo Looijaard , " "Philip Edelbrock , " @@ -547,6 +539,3 @@ MODULE_AUTHOR("Frodo Looijaard , " "and Dan Eaton "); MODULE_DESCRIPTION("ALI1535 SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_ali1535_init); -module_exit(i2c_ali1535_exit); diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 47ae0091e027..e02d9f86c6a0 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -431,18 +431,6 @@ static struct pci_driver ali1563_pci_driver = { .remove = __devexit_p(ali1563_remove), }; -static int __init ali1563_init(void) -{ - return pci_register_driver(&ali1563_pci_driver); -} - -module_init(ali1563_init); - -static void __exit ali1563_exit(void) -{ - pci_unregister_driver(&ali1563_pci_driver); -} - -module_exit(ali1563_exit); +module_pci_driver(ali1563_pci_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 087ea9caa74d..ce8d26d053a5 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -513,21 +513,10 @@ static struct pci_driver ali15x3_driver = { .remove = __devexit_p(ali15x3_remove), }; -static int __init i2c_ali15x3_init(void) -{ - return pci_register_driver(&ali15x3_driver); -} - -static void __exit i2c_ali15x3_exit(void) -{ - pci_unregister_driver(&ali15x3_driver); -} +module_pci_driver(ali15x3_driver); MODULE_AUTHOR ("Frodo Looijaard , " "Philip Edelbrock , " "and Mark D. Studebaker "); MODULE_DESCRIPTION("ALI15X3 SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_ali15x3_init); -module_exit(i2c_ali15x3_exit); diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index eb778bf15c18..304aa03b57b2 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -410,21 +410,10 @@ static struct pci_driver amd756_driver = { .remove = __devexit_p(amd756_remove), }; -static int __init amd756_init(void) -{ - return pci_register_driver(&amd756_driver); -} - -static void __exit amd756_exit(void) -{ - pci_unregister_driver(&amd756_driver); -} +module_pci_driver(amd756_driver); MODULE_AUTHOR("Merlin Hughes "); MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(amd756_smbus); - -module_init(amd756_init) -module_exit(amd756_exit) diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index e5ac53b99b04..0919ac1d99aa 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -491,15 +491,4 @@ static struct pci_driver amd8111_driver = { .remove = __devexit_p(amd8111_remove), }; -static int __init i2c_amd8111_init(void) -{ - return pci_register_driver(&amd8111_driver); -} - -static void __exit i2c_amd8111_exit(void) -{ - pci_unregister_driver(&amd8111_driver); -} - -module_init(i2c_amd8111_init); -module_exit(i2c_amd8111_exit); +module_pci_driver(amd8111_driver); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 00e8f213f56e..92a1e2c15baa 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -374,17 +374,7 @@ static struct pci_driver dw_i2c_driver = { }, }; -static int __init dw_i2c_init_driver(void) -{ - return pci_register_driver(&dw_i2c_driver); -} -module_init(dw_i2c_init_driver); - -static void __exit dw_i2c_exit_driver(void) -{ - pci_unregister_driver(&dw_i2c_driver); -} -module_exit(dw_i2c_exit_driver); +module_pci_driver(dw_i2c_driver); MODULE_AUTHOR("Baruch Siach "); MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 2f74ae872e1e..259f7697bf25 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -953,17 +953,7 @@ static struct pci_driver pch_pcidriver = { .resume = pch_i2c_resume }; -static int __init pch_pci_init(void) -{ - return pci_register_driver(&pch_pcidriver); -} -module_init(pch_pci_init); - -static void __exit pch_pci_exit(void) -{ - pci_unregister_driver(&pch_pcidriver); -} -module_exit(pch_pci_exit); +module_pci_driver(pch_pcidriver); MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index c527de17db4f..c9f95e1666a8 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -156,23 +156,8 @@ static struct pci_driver hydra_driver = { .remove = __devexit_p(hydra_remove), }; -static int __init i2c_hydra_init(void) -{ - return pci_register_driver(&hydra_driver); -} - - -static void __exit i2c_hydra_exit(void) -{ - pci_unregister_driver(&hydra_driver); -} - - +module_pci_driver(hydra_driver); MODULE_AUTHOR("Geert Uytterhoeven "); MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); MODULE_LICENSE("GPL"); - -module_init(i2c_hydra_init); -module_exit(i2c_hydra_exit); - diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index 365bad5b890b..7c28f10f95ca 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -1116,18 +1116,7 @@ static struct pci_driver intel_mid_i2c_driver = { .remove = __devexit_p(intel_mid_i2c_remove), }; -static int __init intel_mid_i2c_init(void) -{ - return pci_register_driver(&intel_mid_i2c_driver); -} - -static void __exit intel_mid_i2c_exit(void) -{ - pci_unregister_driver(&intel_mid_i2c_driver); -} - -module_init(intel_mid_i2c_init); -module_exit(intel_mid_i2c_exit); +module_pci_driver(intel_mid_i2c_driver); MODULE_AUTHOR("Ba Zheng "); MODULE_DESCRIPTION("I2C driver for Moorestown Platform"); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 43a96a123920..392303b4be07 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -453,16 +453,4 @@ static struct pci_driver nforce2_driver = { .remove = __devexit_p(nforce2_remove), }; -static int __init nforce2_init(void) -{ - return pci_register_driver(&nforce2_driver); -} - -static void __exit nforce2_exit(void) -{ - pci_unregister_driver(&nforce2_driver); -} - -module_init(nforce2_init); -module_exit(nforce2_exit); - +module_pci_driver(nforce2_driver); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index eaaea73209c5..12edefd4183a 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -415,19 +415,8 @@ static struct pci_driver pasemi_smb_driver = { .remove = __devexit_p(pasemi_smb_remove), }; -static int __init pasemi_smb_init(void) -{ - return pci_register_driver(&pasemi_smb_driver); -} - -static void __exit pasemi_smb_exit(void) -{ - pci_unregister_driver(&pasemi_smb_driver); -} +module_pci_driver(pasemi_smb_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR ("Olof Johansson "); MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); - -module_init(pasemi_smb_init); -module_exit(pasemi_smb_exit); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index c14d48dd601a..46833fa7a3e0 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -544,20 +544,9 @@ static struct pci_driver piix4_driver = { .remove = __devexit_p(piix4_remove), }; -static int __init i2c_piix4_init(void) -{ - return pci_register_driver(&piix4_driver); -} - -static void __exit i2c_piix4_exit(void) -{ - pci_unregister_driver(&piix4_driver); -} +module_pci_driver(piix4_driver); MODULE_AUTHOR("Frodo Looijaard and " "Philip Edelbrock "); MODULE_DESCRIPTION("PIIX4 SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_piix4_init); -module_exit(i2c_piix4_exit); diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index a05817980556..4dc9bef17d77 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -163,17 +163,7 @@ static struct pci_driver ce4100_i2c_driver = { .remove = __devexit_p(ce4100_i2c_remove), }; -static int __init ce4100_i2c_init(void) -{ - return pci_register_driver(&ce4100_i2c_driver); -} -module_init(ce4100_i2c_init); - -static void __exit ce4100_i2c_exit(void) -{ - pci_unregister_driver(&ce4100_i2c_driver); -} -module_exit(ce4100_i2c_exit); +module_pci_driver(ce4100_i2c_driver); MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 15cf78f65ce0..5d6723b7525e 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -513,21 +513,8 @@ static struct pci_driver sis630_driver = { .remove = __devexit_p(sis630_remove), }; -static int __init i2c_sis630_init(void) -{ - return pci_register_driver(&sis630_driver); -} - - -static void __exit i2c_sis630_exit(void) -{ - pci_unregister_driver(&sis630_driver); -} - +module_pci_driver(sis630_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Malysh "); MODULE_DESCRIPTION("SIS630 SMBus driver"); - -module_init(i2c_sis630_init); -module_exit(i2c_sis630_exit); diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index cc5d149413f7..7b72614a9bc0 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -324,21 +324,8 @@ static struct pci_driver sis96x_driver = { .remove = __devexit_p(sis96x_remove), }; -static int __init i2c_sis96x_init(void) -{ - return pci_register_driver(&sis96x_driver); -} - -static void __exit i2c_sis96x_exit(void) -{ - pci_unregister_driver(&sis96x_driver); -} +module_pci_driver(sis96x_driver); MODULE_AUTHOR("Mark M. Hoffman "); MODULE_DESCRIPTION("SiS96x SMBus driver"); MODULE_LICENSE("GPL"); - -/* Register initialization functions using helper macros */ -module_init(i2c_sis96x_init); -module_exit(i2c_sis96x_exit); - diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 713d31ade26b..7ffee71ca190 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -161,20 +161,8 @@ static struct pci_driver vt586b_driver = { .remove = __devexit_p(vt586b_remove), }; -static int __init i2c_vt586b_init(void) -{ - return pci_register_driver(&vt586b_driver); -} - -static void __exit i2c_vt586b_exit(void) -{ - pci_unregister_driver(&vt586b_driver); -} - +module_pci_driver(vt586b_driver); MODULE_AUTHOR("Kyösti Mälkki "); MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge"); MODULE_LICENSE("GPL"); - -module_init(i2c_vt586b_init); -module_exit(i2c_vt586b_exit); -- cgit v1.2.3 From 14a8086d27ad9761d505489d5a239f21cd67ef0f Mon Sep 17 00:00:00 2001 From: Andrew Armenia Date: Tue, 24 Jul 2012 14:13:56 +0200 Subject: i2c-piix4: Eliminate piix4_smba global variable Some chipsets have multiple sets of piix4-compatible SMBus registers. Eliminating the global variable will allow these chipsets to be fully supported. Return value from piix4_setup and piix4_sb800_setup now returns the smba value detected. This is stored in a struct i2c_piix4_adapdata. Thus the global variable is eliminated. Signed-off-by: Andrew Armenia Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-piix4.c | 50 ++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 46833fa7a3e0..822e868e2ab4 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -94,7 +94,6 @@ MODULE_PARM_DESC(force_addr, "Forcibly enable the PIIX4 at the given address. " "EXTREMELY DANGEROUS!"); -static unsigned short piix4_smba; static int srvrworks_csb5_delay; static struct pci_driver piix4_driver; static struct i2c_adapter piix4_adapter; @@ -127,10 +126,15 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = { { }, }; +struct i2c_piix4_adapdata { + unsigned short smba; +}; + static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id) { unsigned char temp; + unsigned short piix4_smba; if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5)) @@ -206,7 +210,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, dev_err(&PIIX4_dev->dev, "Host SMBus controller not enabled!\n"); release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; return -ENODEV; } } @@ -224,12 +227,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, "SMBus Host Controller at 0x%x, revision %d\n", piix4_smba, temp); - return 0; + return piix4_smba; } static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, const struct pci_device_id *id) { + unsigned short piix4_smba; unsigned short smba_idx = 0xcd6; u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c; @@ -273,7 +277,6 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region " "0x%x already in use!\n", piix4_smba + i2ccfg_offset); release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; return -EBUSY; } i2ccfg = inb_p(piix4_smba + i2ccfg_offset); @@ -288,10 +291,10 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, "SMBus Host Controller at 0x%x, revision %d\n", piix4_smba, i2ccfg >> 4); - return 0; + return piix4_smba; } -static int piix4_transaction(void) +static int piix4_transaction(unsigned short piix4_smba) { int temp; int result = 0; @@ -370,6 +373,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { + struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap); + unsigned short piix4_smba = adapdata->smba; int i, len; int status; @@ -426,7 +431,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - status = piix4_transaction(); + status = piix4_transaction(piix4_smba); if (status) return status; @@ -472,6 +477,8 @@ static struct i2c_adapter piix4_adapter = { .algo = &smbus_algorithm, }; +static struct i2c_piix4_adapdata piix4_adapter_data; + static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, @@ -510,33 +517,44 @@ static int __devinit piix4_probe(struct pci_dev *dev, else retval = piix4_setup(dev, id); - if (retval) + if (retval < 0) return retval; + piix4_adapter_data.smba = retval; + /* set up the sysfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev; snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), - "SMBus PIIX4 adapter at %04x", piix4_smba); + "SMBus PIIX4 adapter at %04x", piix4_adapter_data.smba); + + i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data); if ((retval = i2c_add_adapter(&piix4_adapter))) { dev_err(&dev->dev, "Couldn't register adapter!\n"); - release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; + release_region(piix4_adapter_data.smba, SMBIOSIZE); + piix4_adapter_data.smba = 0; } return retval; } -static void __devexit piix4_remove(struct pci_dev *dev) +static void __devexit piix4_adap_remove(struct i2c_adapter *adap) { - if (piix4_smba) { - i2c_del_adapter(&piix4_adapter); - release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; + struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap); + + if (adapdata->smba) { + i2c_del_adapter(adap); + release_region(adapdata->smba, SMBIOSIZE); + adapdata->smba = 0; } } +static void __devexit piix4_remove(struct pci_dev *dev) +{ + piix4_adap_remove(&piix4_adapter); +} + static struct pci_driver piix4_driver = { .name = "piix4_smbus", .id_table = piix4_ids, -- cgit v1.2.3 From e154bf6fbfc167426ee938111a5ffa36bd8541a1 Mon Sep 17 00:00:00 2001 From: Andrew Armenia Date: Tue, 24 Jul 2012 14:13:56 +0200 Subject: i2c-piix4: Separate registration and probing code Some chipsets have multiple sets of SMBus registers each controlling a separate SMBus. Supporting these chipsets properly will require registering multiple I2C adapters for one piix4. The code to initialize and register the i2c_adapter structure has been separated from piix4_probe and allows registration of a piix4 adapter given its base address. Note that the i2c_adapter and i2c_piix4_adapdata structures are now dynamically allocated. Signed-off-by: Andrew Armenia Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-piix4.c | 111 ++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 40 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 822e868e2ab4..42ed0af10efd 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -96,7 +96,6 @@ MODULE_PARM_DESC(force_addr, static int srvrworks_csb5_delay; static struct pci_driver piix4_driver; -static struct i2c_adapter piix4_adapter; static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = { { @@ -294,27 +293,29 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, return piix4_smba; } -static int piix4_transaction(unsigned short piix4_smba) +static int piix4_transaction(struct i2c_adapter *piix4_adapter) { + struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter); + unsigned short piix4_smba = adapdata->smba; int temp; int result = 0; int timeout = 0; - dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " + dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { - dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " + dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). " "Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { - dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); + dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp); return -EBUSY; } else { - dev_dbg(&piix4_adapter.dev, "Successful!\n"); + dev_dbg(&piix4_adapter->dev, "Successful!\n"); } } @@ -333,35 +334,35 @@ static int piix4_transaction(unsigned short piix4_smba) /* If the SMBus is still busy, we give up */ if (timeout == MAX_TIMEOUT) { - dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); + dev_err(&piix4_adapter->dev, "SMBus Timeout!\n"); result = -ETIMEDOUT; } if (temp & 0x10) { result = -EIO; - dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); + dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n"); } if (temp & 0x08) { result = -EIO; - dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " + dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be " "locked until next hard reset. (sorry!)\n"); /* Clock stops and slave is stuck in mid-transmission */ } if (temp & 0x04) { result = -ENXIO; - dev_dbg(&piix4_adapter.dev, "Error: no response!\n"); + dev_dbg(&piix4_adapter->dev, "Error: no response!\n"); } if (inb_p(SMBHSTSTS) != 0x00) outb_p(inb(SMBHSTSTS), SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { - dev_err(&piix4_adapter.dev, "Failed reset at end of " + dev_err(&piix4_adapter->dev, "Failed reset at end of " "transaction (%02x)\n", temp); } - dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " + dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); @@ -431,7 +432,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - status = piix4_transaction(piix4_smba); + status = piix4_transaction(adap); if (status) return status; @@ -471,14 +472,6 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = piix4_func, }; -static struct i2c_adapter piix4_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = &smbus_algorithm, -}; - -static struct i2c_piix4_adapdata piix4_adapter_data; - static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, @@ -503,6 +496,56 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { MODULE_DEVICE_TABLE (pci, piix4_ids); +static struct i2c_adapter *piix4_main_adapter; + +static int __devinit piix4_add_adapter(struct pci_dev *dev, + unsigned short smba, + struct i2c_adapter **padap) +{ + struct i2c_adapter *adap; + struct i2c_piix4_adapdata *adapdata; + int retval; + + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (adap == NULL) { + release_region(smba, SMBIOSIZE); + return -ENOMEM; + } + + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->algo = &smbus_algorithm; + + adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL); + if (adapdata == NULL) { + kfree(adap); + release_region(smba, SMBIOSIZE); + return -ENOMEM; + } + + adapdata->smba = smba; + + /* set up the sysfs linkage to our parent device */ + adap->dev.parent = &dev->dev; + + snprintf(adap->name, sizeof(adap->name), + "SMBus PIIX4 adapter at %04x", smba); + + i2c_set_adapdata(adap, adapdata); + + retval = i2c_add_adapter(adap); + if (retval) { + dev_err(&dev->dev, "Couldn't register adapter!\n"); + kfree(adapdata); + kfree(adap); + release_region(smba, SMBIOSIZE); + return retval; + } + + *padap = adap; + return 0; +} + static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { @@ -520,23 +563,7 @@ static int __devinit piix4_probe(struct pci_dev *dev, if (retval < 0) return retval; - piix4_adapter_data.smba = retval; - - /* set up the sysfs linkage to our parent device */ - piix4_adapter.dev.parent = &dev->dev; - - snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), - "SMBus PIIX4 adapter at %04x", piix4_adapter_data.smba); - - i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data); - - if ((retval = i2c_add_adapter(&piix4_adapter))) { - dev_err(&dev->dev, "Couldn't register adapter!\n"); - release_region(piix4_adapter_data.smba, SMBIOSIZE); - piix4_adapter_data.smba = 0; - } - - return retval; + return piix4_add_adapter(dev, retval, &piix4_main_adapter); } static void __devexit piix4_adap_remove(struct i2c_adapter *adap) @@ -546,13 +573,17 @@ static void __devexit piix4_adap_remove(struct i2c_adapter *adap) if (adapdata->smba) { i2c_del_adapter(adap); release_region(adapdata->smba, SMBIOSIZE); - adapdata->smba = 0; + kfree(adapdata); + kfree(adap); } } static void __devexit piix4_remove(struct pci_dev *dev) { - piix4_adap_remove(&piix4_adapter); + if (piix4_main_adapter) { + piix4_adap_remove(piix4_main_adapter); + piix4_main_adapter = NULL; + } } static struct pci_driver piix4_driver = { -- cgit v1.2.3 From 2a2f7404a1946be62290292ca5d6438c4b50567f Mon Sep 17 00:00:00 2001 From: Andrew Armenia Date: Tue, 24 Jul 2012 14:13:57 +0200 Subject: i2c-piix4: Support AMD auxiliary SMBus controller Some AMD chipsets, such as the SP5100, have an auxiliary SMBus controller with a second set of registers. This patch adds support for this auxiliary controller. Tested on ASUS KCMA-D8 motherboard. Signed-off-by: Andrew Armenia Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-piix4 | 9 +++++ drivers/i2c/busses/Kconfig | 6 +++- drivers/i2c/busses/i2c-piix4.c | 71 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index 475bb4ae0720..1e6634f54c50 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4 @@ -8,6 +8,11 @@ Supported adapters: Datasheet: Only available via NDA from ServerWorks * ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges Datasheet: Not publicly available + SB700 register reference available at: + http://support.amd.com/us/Embedded_TechDocs/43009_sb7xx_rrg_pub_1.00.pdf + * AMD SP5100 (SB700 derivative found on some server mainboards) + Datasheet: Publicly available at the AMD website + http://support.amd.com/us/Embedded_TechDocs/44413.pdf * AMD Hudson-2 Datasheet: Not publicly available * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge @@ -68,6 +73,10 @@ this driver on those mainboards. The ServerWorks Southbridges, the Intel 440MX, and the Victory66 are identical to the PIIX4 in I2C/SMBus support. +The AMD SB700 and SP5100 chipsets implement two PIIX4-compatible SMBus +controllers. If your BIOS initializes the secondary controller, it will +be detected by this driver as an "Auxiliary SMBus Host Controller". + If you own Force CPCI735 motherboard or other OSB4 based systems you may need to change the SMBus Interrupt Select register so the SMBus controller uses the SMI mode. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7244c8be6063..2e7530a4e7b8 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -133,7 +133,7 @@ config I2C_PIIX4 ATI IXP300 ATI IXP400 ATI SB600 - ATI SB700 + ATI SB700/SP5100 ATI SB800 AMD Hudson-2 Serverworks OSB4 @@ -143,6 +143,10 @@ config I2C_PIIX4 Serverworks HT-1100 SMSC Victory66 + Some AMD chipsets contain two PIIX4-compatible SMBus + controllers. This driver will attempt to use both controllers + on the SB700/SP5100, if they have been initialized by the BIOS. + This driver can also be built as a module. If so, the module will be called i2c-piix4. diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 42ed0af10efd..ef511df2c965 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -21,11 +21,12 @@ Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 - ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 + ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800 AMD Hudson-2 SMSC Victory66 - Note: we assume there can only be one device, with one SMBus interface. + Note: we assume there can only be one device, with one or more + SMBus interfaces. */ #include @@ -293,6 +294,46 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev, return piix4_smba; } +static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev, + const struct pci_device_id *id, + unsigned short base_reg_addr) +{ + /* Set up auxiliary SMBus controllers found on some + * AMD chipsets e.g. SP5100 (SB700 derivative) */ + + unsigned short piix4_smba; + + /* Read address of auxiliary SMBus controller */ + pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba); + if ((piix4_smba & 1) == 0) { + dev_dbg(&PIIX4_dev->dev, + "Auxiliary SMBus controller not enabled\n"); + return -ENODEV; + } + + piix4_smba &= 0xfff0; + if (piix4_smba == 0) { + dev_dbg(&PIIX4_dev->dev, + "Auxiliary SMBus base address uninitialized\n"); + return -ENODEV; + } + + if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) + return -ENODEV; + + if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { + dev_err(&PIIX4_dev->dev, "Auxiliary SMBus region 0x%x " + "already in use!\n", piix4_smba); + return -EBUSY; + } + + dev_info(&PIIX4_dev->dev, + "Auxiliary SMBus Host Controller at 0x%x\n", + piix4_smba); + + return piix4_smba; +} + static int piix4_transaction(struct i2c_adapter *piix4_adapter) { struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter); @@ -497,6 +538,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { MODULE_DEVICE_TABLE (pci, piix4_ids); static struct i2c_adapter *piix4_main_adapter; +static struct i2c_adapter *piix4_aux_adapter; static int __devinit piix4_add_adapter(struct pci_dev *dev, unsigned short smba, @@ -560,10 +602,28 @@ static int __devinit piix4_probe(struct pci_dev *dev, else retval = piix4_setup(dev, id); + /* If no main SMBus found, give up */ if (retval < 0) return retval; - return piix4_add_adapter(dev, retval, &piix4_main_adapter); + /* Try to register main SMBus adapter, give up if we can't */ + retval = piix4_add_adapter(dev, retval, &piix4_main_adapter); + if (retval < 0) + return retval; + + /* Check for auxiliary SMBus on some AMD chipsets */ + if (dev->vendor == PCI_VENDOR_ID_ATI && + dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && + dev->revision < 0x40) { + retval = piix4_setup_aux(dev, id, 0x58); + if (retval > 0) { + /* Try to add the aux adapter if it exists, + * piix4_add_adapter will clean up if this fails */ + piix4_add_adapter(dev, retval, &piix4_aux_adapter); + } + } + + return 0; } static void __devexit piix4_adap_remove(struct i2c_adapter *adap) @@ -584,6 +644,11 @@ static void __devexit piix4_remove(struct pci_dev *dev) piix4_adap_remove(piix4_main_adapter); piix4_main_adapter = NULL; } + + if (piix4_aux_adapter) { + piix4_adap_remove(piix4_aux_adapter); + piix4_aux_adapter = NULL; + } } static struct pci_driver piix4_driver = { -- cgit v1.2.3 From fda2f4af37ccc80d655a5b4538288d461539b574 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 24 Jul 2012 14:13:57 +0200 Subject: i2c-smbus: Use module_i2c_driver() Using module_i2c_driver() makes the code smaller and cleaner. Signed-off-by: Fabio Estevam Signed-off-by: Jean Delvare --- drivers/i2c/i2c-smbus.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 9836d08f7a77..df3e0bf31eb3 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -245,18 +245,7 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) } EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); -static int __init i2c_smbus_init(void) -{ - return i2c_add_driver(&smbalert_driver); -} - -static void __exit i2c_smbus_exit(void) -{ - i2c_del_driver(&smbalert_driver); -} - -module_init(i2c_smbus_init); -module_exit(i2c_smbus_exit); +module_i2c_driver(smbalert_driver); MODULE_AUTHOR("Jean Delvare "); MODULE_DESCRIPTION("SMBus protocol extensions support"); -- cgit v1.2.3 From efa3cb15ad8ba40bd08b05df87ef0ca6680ef762 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:57 +0200 Subject: i2c-i801: Refactor use of LAST_BYTE in i801_block_transaction_byte_by_byte As a slight optimization, pull some logic out of the polling loop during byte-by-byte transactions by just setting the I801_LAST_BYTE bit, as defined in the i801 (PCH) datasheet, when reading the last byte of a byte-by-byte I2C_SMBUS_READ. Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ae2945a5e007..51e11eb64abc 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -117,8 +117,7 @@ #define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ -#define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */ +#define I801_LAST_BYTE 0x20 #define I801_START 0x40 #define I801_PEC_EN 0x80 /* ICH3 and later */ @@ -338,6 +337,11 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, return 0; } +/* + * For "byte-by-byte" block transactions: + * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 + * I2C read uses cmd=I801_I2C_BLOCK_DATA + */ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, union i2c_smbus_data *data, char read_write, int command, @@ -360,19 +364,15 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, outb_p(data->block[1], SMBBLKDAT(priv)); } + if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) { - if (command == I2C_SMBUS_I2C_BLOCK_DATA) - smbcmd = I801_I2C_BLOCK_LAST; - else - smbcmd = I801_BLOCK_LAST; - } else { - if (command == I2C_SMBUS_I2C_BLOCK_DATA - && read_write == I2C_SMBUS_READ) - smbcmd = I801_I2C_BLOCK_DATA; - else - smbcmd = I801_BLOCK_DATA; - } + if (i == len && read_write == I2C_SMBUS_READ) + smbcmd |= I801_LAST_BYTE; outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv)); if (i == 1) -- cgit v1.2.3 From 0ba8b8bfd56533f0b9af7513c6ebbc10c79ae052 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:57 +0200 Subject: i2c-i801: Clear only status bits in HST_STS Writing back the whole status register could clear unwanted bits. In particular, it could clear the "INUSE_STS" bit, which is a 'hardware semaphore', that might be useful to use some day. To prepare for this, let's ban writing back the whole status to register HST_STS, of which this is the only instance. Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 51e11eb64abc..05f394938b82 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -300,7 +300,7 @@ static void i801_wait_hwpec(struct i801_priv *priv) if (timeout > MAX_RETRIES) dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n"); - outb_p(status, SMBHSTSTS(priv)); + outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv)); } static int i801_block_transaction_by_block(struct i801_priv *priv, -- cgit v1.2.3 From 70a1cc1952355404a5746c88757f5a444df52b04 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:58 +0200 Subject: i2c-i801: Check and return errors during byte-by-byte transfers If an error is detected in the polling loop, abort the transaction and return an error code. * DEV_ERR is set if the device does not respond with an acknowledge, and the SMBus controller times out (minimum 25ms). * BUS_ERR is set if a bus arbitration collision is detected. In other words, when the SMBus controller tries to generate a START condition, but detects that the SMBDATA is being held low, usually by another SMBus/I2C master. * FAILED is only set if a transaction is stopped by software (using the SMBHSTCNT KILL bit). Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 05f394938b82..40a50f780972 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -131,9 +131,11 @@ #define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_HOST_BUSY 0x01 -#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \ - SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ - SMBHSTSTS_INTR) +#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ + SMBHSTSTS_DEV_ERR) + +#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \ + STATUS_ERROR_FLAGS) /* Older devices have their ID defined in */ #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 @@ -384,7 +386,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, do { usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); - } while ((!(status & SMBHSTSTS_BYTE_DONE)) + } while (!(status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) && (timeout++ < MAX_RETRIES)); result = i801_check_post(priv, status, timeout > MAX_RETRIES); -- cgit v1.2.3 From edbeea63839cf0ea169c3e0737d49a96b2ca8388 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:58 +0200 Subject: i2c-i801: Rename some SMBHSTCNT bit constants Rename the SMBHSTCNT register bit access constants to match the style of other register bits. Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 40a50f780972..016fa22f1351 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -102,9 +102,6 @@ #define SMBAUXCTL_CRC 1 #define SMBAUXCTL_E32B 2 -/* kill bit for SMBHSTCNT */ -#define SMBHSTCNT_KILL 2 - /* Other settings */ #define MAX_RETRIES 400 #define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ @@ -117,9 +114,13 @@ #define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ -#define I801_LAST_BYTE 0x20 -#define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH3 and later */ + +/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN 0x01 +#define SMBHSTCNT_KILL 0x02 +#define SMBHSTCNT_LAST_BYTE 0x20 +#define SMBHSTCNT_START 0x40 +#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */ /* I801 Hosts Status register bits */ #define SMBHSTSTS_BYTE_DONE 0x80 @@ -271,7 +272,7 @@ static int i801_transaction(struct i801_priv *priv, int xact) /* the current contents of SMBHSTCNT can be overwritten, since PEC, * INTREN, SMBSCMD are passed in xact */ - outb_p(xact | I801_START, SMBHSTCNT(priv)); + outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); /* We will always wait for a fraction of a second! */ do { @@ -323,7 +324,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, } status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | - I801_PEC_EN * hwpec); + (hwpec ? SMBHSTCNT_PEC_EN : 0)); if (status) return status; @@ -374,11 +375,11 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, for (i = 1; i <= len; i++) { if (i == len && read_write == I2C_SMBUS_READ) - smbcmd |= I801_LAST_BYTE; + smbcmd |= SMBHSTCNT_LAST_BYTE; outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv)); if (i == 1) - outb_p(inb(SMBHSTCNT(priv)) | I801_START, + outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, SMBHSTCNT(priv)); /* We will always wait for a fraction of a second! */ -- cgit v1.2.3 From 37af871112e1dec1e39dfac782f0be5926be1c88 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:58 +0200 Subject: i2c-i801: Drop ENABLE_INT9 Later patches enable interrupts. This preliminary patch removes the older unsupported ENABLE_INT9 flag. Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 016fa22f1351..569a282e3347 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -104,7 +104,6 @@ /* Other settings */ #define MAX_RETRIES 400 -#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ /* I801 command constants */ #define I801_QUICK 0x00 @@ -271,7 +270,7 @@ static int i801_transaction(struct i801_priv *priv, int xact) return result; /* the current contents of SMBHSTCNT can be overwritten, since PEC, - * INTREN, SMBSCMD are passed in xact */ + * SMBSCMD are passed in xact */ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); /* We will always wait for a fraction of a second! */ @@ -323,7 +322,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, outb_p(data->block[i+1], SMBBLKDAT(priv)); } - status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | + status = i801_transaction(priv, I801_BLOCK_DATA | (hwpec ? SMBHSTCNT_PEC_EN : 0)); if (status) return status; @@ -376,7 +375,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, for (i = 1; i <= len; i++) { if (i == len && read_write == I2C_SMBUS_READ) smbcmd |= SMBHSTCNT_LAST_BYTE; - outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv)); + outb_p(smbcmd, SMBHSTCNT(priv)); if (i == 1) outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, @@ -567,7 +566,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ret = i801_block_transaction(priv, data, read_write, size, hwpec); else - ret = i801_transaction(priv, xact | ENABLE_INT9); + ret = i801_transaction(priv, xact); /* Some BIOSes don't like it when PEC is enabled at reboot or resume time, so we forcibly disable it after every transaction. Turn off -- cgit v1.2.3 From 6cad93c4bbd62ecfa2e1b3a95c1ac4f6f27764c7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 24 Jul 2012 14:13:58 +0200 Subject: i2c-i801: Consolidate polling (Based on earlier work by Daniel Kurtz.) Come up with a consistent, driver-wide strategy for event polling. For intermediate steps of byte-by-byte block transactions, check for BYTE_DONE or any error flag being set. At the end of every transaction (regardless of PEC being used), check for both BUSY being cleared and INTR or any error flag being set. This ensures proper action for all transaction types. Signed-off-by: Jean Delvare Cc: Daniel Kurtz --- drivers/i2c/busses/i2c-i801.c | 108 +++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 55 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 569a282e3347..a1ce4e68b49a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -206,13 +206,17 @@ static int i801_check_pre(struct i801_priv *priv) return 0; } -/* Convert the status register to an error code, and clear it. */ -static int i801_check_post(struct i801_priv *priv, int status, int timeout) +/* + * Convert the status register to an error code, and clear it. + * Note that status only contains the bits we want to clear, not the + * actual register value. + */ +static int i801_check_post(struct i801_priv *priv, int status) { int result = 0; /* If the SMBus is still busy, we give up */ - if (timeout) { + if (unlikely(status < 0)) { dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); /* try to stop the current command */ dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); @@ -245,64 +249,68 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout) dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); } - if (result) { - /* Clear error flags */ - outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv)); - status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; - if (status) { - dev_warn(&priv->pci_dev->dev, "Failed clearing status " - "flags at end of transaction (%02x)\n", - status); - } - } + /* Clear status flags except BYTE_DONE, to be cleared by caller */ + outb_p(status, SMBHSTSTS(priv)); return result; } -static int i801_transaction(struct i801_priv *priv, int xact) +/* Wait for BUSY being cleared and either INTR or an error flag being set */ +static int i801_wait_intr(struct i801_priv *priv) { - int status; - int result; int timeout = 0; - - result = i801_check_pre(priv); - if (result < 0) - return result; - - /* the current contents of SMBHSTCNT can be overwritten, since PEC, - * SMBSCMD are passed in xact */ - outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); + int status; /* We will always wait for a fraction of a second! */ do { usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); - } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES)); + } while (((status & SMBHSTSTS_HOST_BUSY) || + !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) && + (timeout++ < MAX_RETRIES)); - result = i801_check_post(priv, status, timeout > MAX_RETRIES); - if (result < 0) - return result; - - outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); - return 0; + if (timeout > MAX_RETRIES) { + dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n"); + return -ETIMEDOUT; + } + return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR); } -/* wait for INTR bit as advised by Intel */ -static void i801_wait_hwpec(struct i801_priv *priv) +/* Wait for either BYTE_DONE or an error flag being set */ +static int i801_wait_byte_done(struct i801_priv *priv) { int timeout = 0; int status; + /* We will always wait for a fraction of a second! */ do { usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); - } while ((!(status & SMBHSTSTS_INTR)) - && (timeout++ < MAX_RETRIES)); + } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) && + (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) { + dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n"); + return -ETIMEDOUT; + } + return status & STATUS_ERROR_FLAGS; +} + +static int i801_transaction(struct i801_priv *priv, int xact) +{ + int status; + int result; - if (timeout > MAX_RETRIES) - dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n"); + result = i801_check_pre(priv); + if (result < 0) + return result; - outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv)); + /* the current contents of SMBHSTCNT can be overwritten, since PEC, + * SMBSCMD are passed in xact */ + outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); + + status = i801_wait_intr(priv); + return i801_check_post(priv, status); } static int i801_block_transaction_by_block(struct i801_priv *priv, @@ -353,7 +361,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, int smbcmd; int status; int result; - int timeout; result = i801_check_pre(priv); if (result < 0) @@ -381,17 +388,9 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, SMBHSTCNT(priv)); - /* We will always wait for a fraction of a second! */ - timeout = 0; - do { - usleep_range(250, 500); - status = inb_p(SMBHSTSTS(priv)); - } while (!(status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) - && (timeout++ < MAX_RETRIES)); - - result = i801_check_post(priv, status, timeout > MAX_RETRIES); - if (result < 0) - return result; + status = i801_wait_byte_done(priv); + if (status) + goto exit; if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) { @@ -418,10 +417,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, outb_p(data->block[i+1], SMBBLKDAT(priv)); /* signals SMBBLKDAT ready */ - outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv)); + outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); } - return 0; + status = i801_wait_intr(priv); +exit: + return i801_check_post(priv, status); } static int i801_set_block_buffer_mode(struct i801_priv *priv) @@ -476,9 +477,6 @@ static int i801_block_transaction(struct i801_priv *priv, read_write, command, hwpec); - if (result == 0 && hwpec) - i801_wait_hwpec(priv); - if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_WRITE) { /* restore saved configuration register value */ -- cgit v1.2.3 From 636752bcb5177a301d0266270661581de8624828 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:58 +0200 Subject: i2c-i801: Enable IRQ for SMBus transactions Add a new 'feature' to i2c-i801 to enable using PCI interrupts. When the feature is enabled, then an isr is installed for the device's PCI IRQ. An I2C/SMBus transaction is always terminated by one of the following interrupt sources: FAILED, BUS_ERR, DEV_ERR, or on success: INTR. When the isr fires for one of these cases, it sets the ->status variable and wakes up the waitq. The waitq then saves off the status code, and clears ->status (in preparation for some future transaction). The SMBus controller generates an INTR irq at the end of each transaction where INTREN was set in the HST_CNT register. No locking is needed around accesses to priv->status since all writes to it are serialized: it is only ever set once in the isr at the end of a transaction, and cleared while no interrupts can occur. In addition, the I2C adapter lock guarantees that entire I2C transactions for a single adapter are always serialized. For this patch, the INTREN bit is set only for SMBus block, byte and word transactions, but not for I2C reads or writes. The use of the DS (BYTE_DONE) interrupt with byte-by-byte I2C transactions is implemented in a subsequent patch. The interrupt feature has only been enabled for COUGARPOINT hardware. In addition, it is disabled if SMBus is using the SMI# interrupt. Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-i801 | 13 +++-- drivers/i2c/busses/i2c-i801.c | 99 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 71f55bbcefc8..615142da4ef6 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -38,9 +38,10 @@ Module Parameters Disable selected features normally supported by the device. This makes it possible to work around possible driver or hardware bugs if the feature in question doesn't work as intended for whatever reason. Bit values: - 1 disable SMBus PEC - 2 disable the block buffer - 8 disable the I2C block read functionality + 0x01 disable SMBus PEC + 0x02 disable the block buffer + 0x08 disable the I2C block read functionality + 0x10 don't use interrupts Description @@ -86,6 +87,12 @@ SMBus 2.0 Support The 82801DB (ICH4) and later chips support several SMBus 2.0 features. +Interrupt Support +----------------- + +PCI interrupt support is supported on the 82801EB (ICH5) and later chips. + + Hidden ICH SMBus ---------------- diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index a1ce4e68b49a..bcce18dfcc39 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -60,10 +60,12 @@ Block process call transaction no I2C block read transaction yes (doesn't use the block buffer) Slave mode no + Interrupt processing yes See the file Documentation/i2c/busses/i2c-i801 for details. */ +#include #include #include #include @@ -76,6 +78,7 @@ #include #include #include +#include /* I801 SMBus address offsets */ #define SMBHSTSTS(p) (0 + (p)->smba) @@ -91,8 +94,12 @@ /* PCI Address Constants */ #define SMBBAR 4 +#define SMBPCISTS 0x006 #define SMBHSTCFG 0x040 +/* Host status bits for SMBPCISTS */ +#define SMBPCISTS_INTS 0x08 + /* Host configuration bits for SMBHSTCFG */ #define SMBHSTCFG_HST_EN 1 #define SMBHSTCFG_SMB_SMI_EN 2 @@ -155,6 +162,10 @@ struct i801_priv { unsigned char original_hstcfg; struct pci_dev *pci_dev; unsigned int features; + + /* isr processing */ + wait_queue_head_t waitq; + u8 status; }; static struct pci_driver i801_driver; @@ -163,6 +174,7 @@ static struct pci_driver i801_driver; #define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_PROC (1 << 2) #define FEATURE_I2C_BLOCK_READ (1 << 3) +#define FEATURE_IRQ (1 << 4) /* Not really a feature, but it's convenient to handle it as such */ #define FEATURE_IDF (1 << 15) @@ -171,6 +183,7 @@ static const char *i801_feature_names[] = { "Block buffer", "Block process call", "I2C block read", + "Interrupt", }; static unsigned int disable_features; @@ -215,7 +228,12 @@ static int i801_check_post(struct i801_priv *priv, int status) { int result = 0; - /* If the SMBus is still busy, we give up */ + /* + * If the SMBus is still busy, we give up + * Note: This timeout condition only happens when using polling + * transactions. For interrupt operation, NAK/timeout is indicated by + * DEV_ERR. + */ if (unlikely(status < 0)) { dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); /* try to stop the current command */ @@ -305,6 +323,14 @@ static int i801_transaction(struct i801_priv *priv, int xact) if (result < 0) return result; + if (priv->features & FEATURE_IRQ) { + outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, + SMBHSTCNT(priv)); + wait_event(priv->waitq, (status = priv->status)); + priv->status = 0; + return i801_check_post(priv, status); + } + /* the current contents of SMBHSTCNT can be overwritten, since PEC, * SMBSCMD are passed in xact */ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); @@ -347,6 +373,44 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, return 0; } +/* + * i801 signals transaction completion with one of these interrupts: + * INTR - Success + * DEV_ERR - Invalid command, NAK or communication timeout + * BUS_ERR - SMI# transaction collision + * FAILED - transaction was canceled due to a KILL request + * When any of these occur, update ->status and wake up the waitq. + * ->status must be cleared before kicking off the next transaction. + */ +static irqreturn_t i801_isr(int irq, void *dev_id) +{ + struct i801_priv *priv = dev_id; + u16 pcists; + u8 status; + + /* Confirm this is our interrupt */ + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); + if (!(pcists & SMBPCISTS_INTS)) + return IRQ_NONE; + + status = inb_p(SMBHSTSTS(priv)); + if (status != 0x42) + dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status); + + /* + * Clear irq sources and report transaction result. + * ->status must be cleared before the next transaction is started. + */ + status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; + if (status) { + outb_p(status, SMBHSTSTS(priv)); + priv->status |= status; + wake_up(&priv->waitq); + } + + return IRQ_HANDLED; +} + /* * For "byte-by-byte" block transactions: * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 @@ -799,6 +863,10 @@ static int __devinit i801_probe(struct pci_dev *dev, break; } + /* IRQ processing only tested on CougarPoint PCH */ + if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) + priv->features |= FEATURE_IRQ; + /* Disable features on user request */ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { if (priv->features & disable_features & (1 << i)) @@ -846,16 +914,31 @@ static int __devinit i801_probe(struct pci_dev *dev, } pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp); - if (temp & SMBHSTCFG_SMB_SMI_EN) + if (temp & SMBHSTCFG_SMB_SMI_EN) { dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); - else + /* Disable SMBus interrupt feature if SMBus using SMI# */ + priv->features &= ~FEATURE_IRQ; + } else { dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); + } /* Clear special mode bits */ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + if (priv->features & FEATURE_IRQ) { + init_waitqueue_head(&priv->waitq); + + err = request_irq(dev->irq, i801_isr, IRQF_SHARED, + i801_driver.name, priv); + if (err) { + dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", + dev->irq, err); + goto exit_release; + } + } + /* set up the sysfs linkage to our parent device */ priv->adapter.dev.parent = &dev->dev; @@ -867,14 +950,18 @@ static int __devinit i801_probe(struct pci_dev *dev, err = i2c_add_adapter(&priv->adapter); if (err) { dev_err(&dev->dev, "Failed to add SMBus adapter\n"); - goto exit_release; + goto exit_free_irq; } i801_probe_optional_slaves(priv); pci_set_drvdata(dev, priv); + return 0; +exit_free_irq: + if (priv->features & FEATURE_IRQ) + free_irq(dev->irq, priv); exit_release: pci_release_region(dev, SMBBAR); exit: @@ -888,7 +975,11 @@ static void __devexit i801_remove(struct pci_dev *dev) i2c_del_adapter(&priv->adapter); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); + + if (priv->features & FEATURE_IRQ) + free_irq(dev->irq, priv); pci_release_region(dev, SMBBAR); + pci_set_drvdata(dev, NULL); kfree(priv); /* -- cgit v1.2.3 From 29b608540b030d38a978c972cbe99d40efdb7267 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 24 Jul 2012 14:13:59 +0200 Subject: i2c-i801: Enable interrupts on ICH5/7/8/9/10 Enable interrupts on more devices. ICH5, ICH7(-M) and ICH10 have been tested to work OK. ICH8 and ICH9 are expected to work just fine as they are very close to ICH7 and ICH10. Ultimately we want to enable this feature on at least every device since the ICH5, but for now we limit the exposure. We'll enable it for other devices if we don't get negative feedback. As a bonus, let the user know when interrupts are used. Signed-off-by: Jean Delvare Cc: Daniel Kurtz --- drivers/i2c/busses/i2c-i801.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index bcce18dfcc39..003196fffd2c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -863,8 +863,14 @@ static int __devinit i801_probe(struct pci_dev *dev, break; } - /* IRQ processing only tested on CougarPoint PCH */ - if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) + /* IRQ processing tested on CougarPoint PCH, ICH5, ICH7-M and ICH10 */ + if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS || + dev->device == PCI_DEVICE_ID_INTEL_82801EB_3 || + dev->device == PCI_DEVICE_ID_INTEL_ICH7_17 || + dev->device == PCI_DEVICE_ID_INTEL_ICH8_5 || + dev->device == PCI_DEVICE_ID_INTEL_ICH9_6 || + dev->device == PCI_DEVICE_ID_INTEL_ICH10_4 || + dev->device == PCI_DEVICE_ID_INTEL_ICH10_5) priv->features |= FEATURE_IRQ; /* Disable features on user request */ @@ -918,8 +924,6 @@ static int __devinit i801_probe(struct pci_dev *dev, dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); /* Disable SMBus interrupt feature if SMBus using SMI# */ priv->features &= ~FEATURE_IRQ; - } else { - dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); } /* Clear special mode bits */ @@ -937,6 +941,7 @@ static int __devinit i801_probe(struct pci_dev *dev, dev->irq, err); goto exit_release; } + dev_info(&dev->dev, "SMBus using PCI Interrupt\n"); } /* set up the sysfs linkage to our parent device */ -- cgit v1.2.3 From d3ff6ce40031e8401eab60c3de7db9b1f3f4c08b Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 24 Jul 2012 14:13:59 +0200 Subject: i2c-i801: Enable IRQ for byte_by_byte transactions Byte-by-byte transactions are used primarily for accessing I2C devices with an SMBus controller. For these transactions, for each byte that is read or written, the SMBus controller generates a BYTE_DONE IRQ. The isr reads/writes the next byte, and clears the IRQ flag to start the next byte. On the penultimate IRQ, the isr also sets the LAST_BYTE flag. There is no locking around the cmd/len/count/data variables, since the I2C adapter lock ensures there is never multiple simultaneous transactions for the same device, and the driver thread never accesses these variables while interrupts might be occurring. The end result is faster I2C block read and write transactions. Note: This patch has only been tested and verified by doing I2C read and write block transfers on Cougar Point 6 Series PCH, as well as I2C read block transfers on ICH5. Signed-off-by: Daniel Kurtz Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 85 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 003196fffd2c..898dcf9c7ade 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -166,6 +166,13 @@ struct i801_priv { /* isr processing */ wait_queue_head_t waitq; u8 status; + + /* Command state used by isr for byte-by-byte block transactions */ + u8 cmd; + bool is_read; + int count; + int len; + u8 *data; }; static struct pci_driver i801_driver; @@ -373,14 +380,60 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, return 0; } +static void i801_isr_byte_done(struct i801_priv *priv) +{ + if (priv->is_read) { + /* For SMBus block reads, length is received with first byte */ + if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) && + (priv->count == 0)) { + priv->len = inb_p(SMBHSTDAT0(priv)); + if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) { + dev_err(&priv->pci_dev->dev, + "Illegal SMBus block read size %d\n", + priv->len); + /* FIXME: Recover */ + priv->len = I2C_SMBUS_BLOCK_MAX; + } else { + dev_dbg(&priv->pci_dev->dev, + "SMBus block read size is %d\n", + priv->len); + } + priv->data[-1] = priv->len; + } + + /* Read next byte */ + if (priv->count < priv->len) + priv->data[priv->count++] = inb(SMBBLKDAT(priv)); + else + dev_dbg(&priv->pci_dev->dev, + "Discarding extra byte on block read\n"); + + /* Set LAST_BYTE for last byte of read transaction */ + if (priv->count == priv->len - 1) + outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE, + SMBHSTCNT(priv)); + } else if (priv->count < priv->len - 1) { + /* Write next byte, except for IRQ after last byte */ + outb_p(priv->data[++priv->count], SMBBLKDAT(priv)); + } + + /* Clear BYTE_DONE to continue with next byte */ + outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); +} + /* - * i801 signals transaction completion with one of these interrupts: - * INTR - Success - * DEV_ERR - Invalid command, NAK or communication timeout - * BUS_ERR - SMI# transaction collision - * FAILED - transaction was canceled due to a KILL request - * When any of these occur, update ->status and wake up the waitq. - * ->status must be cleared before kicking off the next transaction. + * There are two kinds of interrupts: + * + * 1) i801 signals transaction completion with one of these interrupts: + * INTR - Success + * DEV_ERR - Invalid command, NAK or communication timeout + * BUS_ERR - SMI# transaction collision + * FAILED - transaction was canceled due to a KILL request + * When any of these occur, update ->status and wake up the waitq. + * ->status must be cleared before kicking off the next transaction. + * + * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt + * occurs for each byte of a byte-by-byte to prepare the next byte. */ static irqreturn_t i801_isr(int irq, void *dev_id) { @@ -397,6 +450,9 @@ static irqreturn_t i801_isr(int irq, void *dev_id) if (status != 0x42) dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status); + if (status & SMBHSTSTS_BYTE_DONE) + i801_isr_byte_done(priv); + /* * Clear irq sources and report transaction result. * ->status must be cleared before the next transaction is started. @@ -443,6 +499,21 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, else smbcmd = I801_BLOCK_DATA; + if (priv->features & FEATURE_IRQ) { + priv->is_read = (read_write == I2C_SMBUS_READ); + if (len == 1 && priv->is_read) + smbcmd |= SMBHSTCNT_LAST_BYTE; + priv->cmd = smbcmd | SMBHSTCNT_INTREN; + priv->len = len; + priv->count = 0; + priv->data = &data->block[1]; + + outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + wait_event(priv->waitq, (status = priv->status)); + priv->status = 0; + return i801_check_post(priv, status); + } + for (i = 1; i <= len; i++) { if (i == len && read_write == I2C_SMBUS_READ) smbcmd |= SMBHSTCNT_LAST_BYTE; -- cgit v1.2.3 From 68a7602f098c30cc27fbc336db575af63f1be07b Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Tue, 24 Jul 2012 14:13:59 +0200 Subject: i2c-tiny-usb: Add support for the Robofuzz OSIF USB/I2C converter Robofuzz OSIF is a generic USB/iIC interface that embeds an ATMega8A AVR-RISC microcontroler. The device is based upon Till Harbaum's i2c-tiny-usb and although it enhances the original design with further functionnalities it still maintain compatibility with it with respect to the USB/I2C interface. Signed-off-by: Emmanuel Deloget Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-tiny-usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index f07307ff360d..05106368d405 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -143,6 +143,7 @@ static const struct i2c_algorithm usb_algorithm = { static const struct usb_device_id i2c_tiny_usb_table[] = { { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */ + { USB_DEVICE(0x1964, 0x0001) }, /* Robofuzz OSIF */ { } /* Terminating entry */ }; -- cgit v1.2.3 From d47726c52122d64253ae56e0fafdb7d0b954e97c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 Jul 2012 14:13:59 +0200 Subject: i2c: Add SCCB support SCCB is a serial communication bus developed by Omnivision. Its 2-wire mode is very similar to SMBus byte data transactions, but requires the controller to ignore the ACK bit and to insert a stop condition after each message. Add a device SCCB flag and a message stop flag to be passed to controller drivers. [JD: Kill rogue definition in go7007 driver.] Signed-off-by: Laurent Pinchart Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 2 +- drivers/staging/media/go7007/wis-i2c.h | 5 ----- include/linux/i2c.h | 3 +++ 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a6ad32bc0a96..361978a8485a 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2122,7 +2122,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, int try; s32 res; - flags &= I2C_M_TEN | I2C_CLIENT_PEC; + flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; if (adapter->algo->smbus_xfer) { i2c_lock_adapter(adapter); diff --git a/drivers/staging/media/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h index 3c2b9be455df..6d09c06c8560 100644 --- a/drivers/staging/media/go7007/wis-i2c.h +++ b/drivers/staging/media/go7007/wis-i2c.h @@ -25,11 +25,6 @@ #define I2C_DRIVERID_WIS_TW2804 0xf0f6 #define I2C_DRIVERID_S2250 0xf0f7 -/* Flag to indicate that the client needs to be accessed with SCCB semantics */ -/* We re-use the I2C_M_TEN value so the flag passes through the masks in the - * core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */ -#define I2C_CLIENT_SCCB 0x10 - /* Definitions for new video decoder commands */ struct video_decoder_resolution { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ddfa04108baf..1d0fe4877b1f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -425,6 +425,8 @@ void i2c_unlock_adapter(struct i2c_adapter *); #define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ /* Must equal I2C_M_TEN below */ #define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */ +#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */ + /* Must match I2C_M_STOP|IGNORE_NAK */ /* i2c adapter classes (bitmask) */ #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ @@ -541,6 +543,7 @@ struct i2c_msg { __u16 flags; #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #define I2C_M_RD 0x0001 /* read data, from slave to master */ +#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ -- cgit v1.2.3 From 72fc2c7f78b0c365454e60ad33b0e74aea43e3ab Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 Jul 2012 14:13:59 +0200 Subject: i2c: Fall back to emulated SMBus if the operation isn't supported natively Adapter drivers might support only a subset of the SMBus operations natively. Those drivers currently have to manually emulate unsupported operations using I2C. Make the i2c_smbus_xfer() function fall back to i2c_smbus_xfer_emulated() when the adapter's .smbus_xfer() operation returns -EOPNOTSUPP, like it already does when the .smbus_xfer() operation isn't available at all. [JD: Minor optimization.] Signed-off-by: Laurent Pinchart Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 361978a8485a..26488aa893d5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2140,11 +2140,17 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, break; } i2c_unlock_adapter(adapter); - } else - res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, - command, protocol, data); - return res; + if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) + return res; + /* + * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't + * implement native support for the SMBus operation. + */ + } + + return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, + command, protocol, data); } EXPORT_SYMBOL(i2c_smbus_xfer); -- cgit v1.2.3 From fb604a3d58b79ef722942f664f11dee5e1f73ea4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 Jul 2012 14:13:59 +0200 Subject: i2c-omap: Add support for I2C_M_STOP message flag Generate a stop condition after each message marked with I2C_M_STOP. [JD: Add I2C_FUNC_PROTOCOL_MANGLING.] Signed-off-by: Laurent Pinchart Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-omap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 801df6000e9b..c2148332de0f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -545,6 +545,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (dev->speed > 400) w |= OMAP_I2C_CON_OPMODE_HS; + if (msg->flags & I2C_M_STOP) + stop = 1; if (msg->flags & I2C_M_TEN) w |= OMAP_I2C_CON_XA; if (!(msg->flags & I2C_M_RD)) @@ -658,7 +660,8 @@ out: static u32 omap_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 & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_PROTOCOL_MANGLING; } static inline void -- cgit v1.2.3 From 5db20c49e2d6581797c17057e068d89d6677aa24 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 24 Jul 2012 17:32:45 +0200 Subject: Revert "i2c: tegra: convert normal suspend/resume to *_noirq" This reverts commit 7c86d44cda2e715bc95f525fd0eac4bd6a66998e. Stephen says: IIRC, I proposed it before solely to solve some suspend/resume ordering issues, and Colin Cross NAKd it. These days, deferred probe should make this change unnecessary. Reported-by: Stephen Warren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index f179f88aa71a..f85dee549e21 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -713,7 +713,7 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int tegra_i2c_suspend_noirq(struct device *dev) +static int tegra_i2c_suspend(struct device *dev) { struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -724,7 +724,7 @@ static int tegra_i2c_suspend_noirq(struct device *dev) return 0; } -static int tegra_i2c_resume_noirq(struct device *dev) +static int tegra_i2c_resume(struct device *dev) { struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; @@ -745,10 +745,7 @@ static int tegra_i2c_resume_noirq(struct device *dev) return 0; } -static const struct dev_pm_ops tegra_i2c_pm = { - .suspend_noirq = tegra_i2c_suspend_noirq, - .resume_noirq = tegra_i2c_resume_noirq, -}; +static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); #define TEGRA_I2C_PM (&tegra_i2c_pm) #else #define TEGRA_I2C_PM NULL -- cgit v1.2.3 From dd995c9d82b6eedb2e704daf44e903da0b7f6ac1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 30 Jul 2012 14:39:30 -0700 Subject: i2c/i2c-pxa: remove conditional compilation of clk code With addition of dummy clk_*() calls for non CONFIG_HAVE_CLK cases in clk.h, there is no need to have clk code enclosed in #ifdef CONFIG_HAVE_CLK, #endif macros. pxa i2c also has these dummy macros defined locally. Remove them as they aren't required anymore. Signed-off-by: Viresh Kumar Acked-by: Wolfram Sang Cc: Russell King Cc: Mike Turquette Cc: Sergei Shtylyov Cc: viresh kumar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/i2c/busses/i2c-pxa.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index a997c7d3f95d..1034d93fb838 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -41,13 +41,6 @@ #include -#ifndef CONFIG_HAVE_CLK -#define clk_get(dev, id) NULL -#define clk_put(clk) do { } while (0) -#define clk_disable(clk) do { } while (0) -#define clk_enable(clk) do { } while (0) -#endif - struct pxa_reg_layout { u32 ibmr; u32 idbr; -- cgit v1.2.3 From b007a3ef958413736a9e2ba698ad6675a9d519ab Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Aug 2012 12:27:24 +0100 Subject: i2c: nomadik: Add default configuration into the Nomadik I2C driver At this moment in time there is only one known configuration for the Nomadik I2C driver. By not holding that configuration in the driver adds some unnecessary overhead in platform code. The configuration has already been removed from platform code, this patch checks for any over-riding configurations. If there aren't any, the default is used. [LinusW says: "Right now this is causing boot regressions so we need it badly..."] Acked-by: srinidhi kasagar Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 5e6f1eed4f83..61b00edacb08 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -350,10 +350,6 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) i2c_clk = clk_get_rate(dev->clk); - /* fallback to std. mode if machine has not provided it */ - if (dev->cfg.clk_freq == 0) - dev->cfg.clk_freq = 100000; - /* * The spec says, in case of std. mode the divider is * 2 whereas it is 3 for fast and fastplus mode of @@ -911,20 +907,32 @@ static const struct i2c_algorithm nmk_i2c_algo = { .functionality = nmk_i2c_functionality }; +static struct nmk_i2c_controller u8500_i2c = { + /* + * Slave data setup time; 250ns, 100ns, and 10ns, which + * is 14, 6 and 2 respectively for a 48Mhz i2c clock. + */ + .slsu = 0xe, + .tft = 1, /* Tx FIFO threshold */ + .rft = 8, /* Rx FIFO threshold */ + .clk_freq = 400000, /* fast mode operation */ + .timeout = 200, /* Slave response timeout(ms) */ + .sm = I2C_FREQ_MODE_FAST, +}; + static atomic_t adapter_id = ATOMIC_INIT(0); static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; - struct nmk_i2c_controller *pdata = - adev->dev.platform_data; + struct nmk_i2c_controller *pdata = adev->dev.platform_data; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; - if (!pdata) { - dev_warn(&adev->dev, "no platform data\n"); - return -ENODEV; - } + if (!pdata) + /* No i2c configuration found, using the default. */ + pdata = &u8500_i2c; + dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); if (!dev) { dev_err(&adev->dev, "cannot allocate memory\n"); -- cgit v1.2.3 From 33ec5e818b7b0d0d02864a9586050c6f9a6a8b98 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 26 Jun 2012 18:45:32 -0700 Subject: I2C: OMAP: xfer: fix runtime PM get/put balance on error In omap_i2c_xfer(), ensure pm_runtime_put() is called, even on failure. Without this, after a failed xfer, the runtime PM usecount will have been incremented, but not decremented causing the usecount to never reach zero after a failure. This keeps the device always runtime PM enabled which keeps the enclosing power domain active, and prevents full-chip retention/off from happening during idle. Signed-off-by: Kevin Hilman Reviewed-by: Shubhrajyoti D Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6849635b268a..5d19a49803c1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -584,7 +584,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) r = pm_runtime_get_sync(dev->dev); if (IS_ERR_VALUE(r)) - return r; + goto out; r = omap_i2c_wait_for_bb(dev); if (r < 0) -- cgit v1.2.3 From ab5625c30a0a3c8a8491b641c939575c84bc0dbb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 9 Aug 2012 08:47:20 -0700 Subject: i2c: diolan-u2c: Fix master_xfer return code The master_xfer function returns 0 on success. It should return the number of successful transactions. Signed-off-by: Guenter Roeck Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-diolan-u2c.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index aedb94f34bf7..dae3ddfe7619 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -405,6 +405,7 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, } } } + ret = num; abort: sret = diolan_i2c_stop(dev); if (sret < 0 && ret >= 0) -- cgit v1.2.3 From 371e67c9e1a82b5fd8110b9a25e36bbc3a99e8c7 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Sat, 18 Aug 2012 17:49:58 +0530 Subject: i2c: tegra: protect suspend/resume callbacks with CONFIG_PM_SLEEP The CONFIG_PM doesn't actually enable any of the PM callbacks, it only allows to enable CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. This means if CONFIG_PM is used to protect system sleep callbacks then it may end up unreferenced if only runtime PM is enabled. Hence protecting sleep callbacks with CONFIG_PM_SLEEP. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 66eb53fac202..9a08c57bc936 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -712,7 +712,7 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int tegra_i2c_suspend(struct device *dev) { struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); -- cgit v1.2.3