From af777ce42d3d51cdef353ce296d6f99dc503feef Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 May 2009 16:59:40 +0900 Subject: sh: clkfwk: module_clk -> peripheral_clk rename. For consistenct naming, and to allow us to fix up some confusion in the SH-Mobile clock framework, amongst other places. Signed-off-by: Paul Mundt --- drivers/i2c/busses/i2c-sh7760.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index baa28b73ae4..b9680f50f54 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -396,7 +396,7 @@ static int __devinit calc_CCR(unsigned long scl_hz) signed char cdf, cdfm; int scgd, scgdm, scgds; - mclk = clk_get(NULL, "module_clk"); + mclk = clk_get(NULL, "peripheral_clk"); if (IS_ERR(mclk)) { return PTR_ERR(mclk); } else { -- cgit v1.2.3-70-g09d2 From 9d2c0f67c8cf8d2f34aa126da7b98d265d54017f Mon Sep 17 00:00:00 2001 From: Sean MacLennan Date: Mon, 2 Feb 2009 07:01:59 +0000 Subject: i2c: Fix confusing i2c-ibm_iic message The i2c-ibm_iic driver printed messages in an odd order that seemed to list devices before the driver was probed. Here is an example: at24 0-0052: 512 byte 24c04 EEPROM (writable) ibm-iic ef600700.i2c: using standard (100 kHz) mode ad7414 0-004a: chip found This changes the order to print the i2c driver message before scanning for devices so that the logs show the driver, then the devices. Signed-off-by: Sean MacLennan Acked-by: Jean Delvare Signed-off-by: Josh Boyer --- drivers/i2c/busses/i2c-ibm_iic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 8b92a4666e0..e4476743f20 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -756,12 +756,12 @@ static int __devinit iic_probe(struct of_device *ofdev, goto error_cleanup; } - /* Now register all the child nodes */ - of_register_i2c_devices(adap, np); - dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); + /* Now register all the child nodes */ + of_register_i2c_devices(adap, np); + return 0; error_cleanup: -- cgit v1.2.3-70-g09d2 From f23d4911319fdebffd0529b31bb66d324ef287e6 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 13 Apr 2009 14:43:25 +0800 Subject: [ARM] pxa: add platform device ID table to pxa i2c driver Signed-off-by: Eric Miao --- arch/arm/mach-pxa/devices.c | 2 +- drivers/i2c/busses/i2c-pxa.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index d245e59c51b..899418e18a2 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -287,7 +287,7 @@ static struct resource pxa3xx_resources_i2c_power[] = { }; struct platform_device pxa3xx_device_i2c_power = { - .name = "pxa2xx-i2c", + .name = "pxa3xx-pwri2c", .id = 1, .resource = pxa3xx_resources_i2c_power, .num_resources = ARRAY_SIZE(pxa3xx_resources_i2c_power), diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index acc7143d965..e4ee8835b97 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -34,11 +34,25 @@ #include #include -#include #include #include #include +/* + * I2C register offsets will be shifted 0 or 1 bit left, depending on + * different SoCs + */ +#define REG_SHIFT_0 (0 << 0) +#define REG_SHIFT_1 (1 << 0) +#define REG_SHIFT(d) ((d) & 0x1) + +static const struct platform_device_id i2c_pxa_id_table[] = { + { "pxa2xx-i2c", REG_SHIFT_1 }, + { "pxa3xx-pwri2c", REG_SHIFT_0 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); + /* * I2C registers and bit definitions */ @@ -985,6 +999,7 @@ static int i2c_pxa_probe(struct platform_device *dev) struct pxa_i2c *i2c; struct resource *res; struct i2c_pxa_platform_data *plat = dev->dev.platform_data; + struct platform_device_id *id = platform_get_device_id(dev); int ret; int irq; @@ -1028,7 +1043,7 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = -EIO; goto eremap; } - i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1; + i2c->reg_shift = REG_SHIFT(id->driver_data); i2c->iobase = res->start; i2c->iosize = res_len(res); @@ -1150,6 +1165,7 @@ static struct platform_driver i2c_pxa_driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, }, + .id_table = i2c_pxa_id_table, }; static int __init i2c_adap_pxa_init(void) -- cgit v1.2.3-70-g09d2 From f0a83701399123b0e95cc4d949fcccf9941fd190 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 13 Apr 2009 15:03:11 +0800 Subject: [ARM] pxa: move mach/i2c.h to plat/i2c.h Signed-off-by: Paul Shen Signed-off-by: Eric Miao --- arch/arm/mach-pxa/cm-x300.c | 2 +- arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/csb726.c | 2 +- arch/arm/mach-pxa/devices.c | 2 +- arch/arm/mach-pxa/em-x270.c | 2 +- arch/arm/mach-pxa/ezx.c | 2 +- arch/arm/mach-pxa/imote2.c | 2 +- arch/arm/mach-pxa/include/mach/i2c.h | 82 ------------------------------------ arch/arm/mach-pxa/littleton.c | 2 +- arch/arm/mach-pxa/magician.c | 2 +- arch/arm/mach-pxa/mainstone.c | 2 +- arch/arm/mach-pxa/mioa701.c | 2 +- arch/arm/mach-pxa/pcm990-baseboard.c | 2 +- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/pxa27x.c | 2 +- arch/arm/mach-pxa/pxa3xx.c | 2 +- arch/arm/mach-pxa/saar.c | 2 +- arch/arm/mach-pxa/spitz.c | 2 +- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-pxa/trizeps4.c | 2 +- arch/arm/mach-pxa/viper.c | 2 +- arch/arm/mach-pxa/zylonite_pxa300.c | 2 +- arch/arm/plat-pxa/include/plat/i2c.h | 82 ++++++++++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-pxa.c | 2 +- 24 files changed, 104 insertions(+), 104 deletions(-) delete mode 100644 arch/arm/mach-pxa/include/mach/i2c.h create mode 100644 arch/arm/plat-pxa/include/plat/i2c.h (limited to 'drivers/i2c') diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index a9f48b1cb54..a97f87a90d0 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 930e364ccde..f04e5058328 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c index 2b289f83a61..f95b32d9899 100644 --- a/arch/arm/mach-pxa/csb726.c +++ b/arch/arm/mach-pxa/csb726.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 899418e18a2..d3c3b7b025a 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index bc0f73fbd4c..3503f523070 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index 7db966dc29c..4ce63b4e15c 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/imote2.c b/arch/arm/mach-pxa/imote2.c index 2121309b247..821e65a4097 100644 --- a/arch/arm/mach-pxa/imote2.c +++ b/arch/arm/mach-pxa/imote2.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/include/mach/i2c.h b/arch/arm/mach-pxa/include/mach/i2c.h deleted file mode 100644 index 1a9f65e6ec0..00000000000 --- a/arch/arm/mach-pxa/include/mach/i2c.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * i2c_pxa.h - * - * Copyright (C) 2002 Intrinsyc Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#ifndef _I2C_PXA_H_ -#define _I2C_PXA_H_ - -#if 0 -#define DEF_TIMEOUT 3 -#else -/* need a longer timeout if we're dealing with the fact we may well be - * looking at a multi-master environment -*/ -#define DEF_TIMEOUT 32 -#endif - -#define BUS_ERROR (-EREMOTEIO) -#define XFER_NAKED (-ECONNREFUSED) -#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ - -/* ICR initialize bit values -* -* 15. FM 0 (100 Khz operation) -* 14. UR 0 (No unit reset) -* 13. SADIE 0 (Disables the unit from interrupting on slave addresses -* matching its slave address) -* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration -* in master mode) -* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) -* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) -* 9. IRFIE 1 (Enable interrupts from full buffer received) -* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) -* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) -* 6. IUE 0 (Disable unit until we change settings) -* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) -* 4. MA 0 (Only send stop with the ICR stop bit) -* 3. TB 0 (We are not transmitting a byte initially) -* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) -* 1. STOP 0 (Do not send a STOP) -* 0. START 0 (Do not send a START) -* -*/ -#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) - -/* I2C status register init values - * - * 10. BED 1 (Clear bus error detected) - * 9. SAD 1 (Clear slave address detected) - * 7. IRF 1 (Clear IDBR Receive Full) - * 6. ITE 1 (Clear IDBR Transmit Empty) - * 5. ALD 1 (Clear Arbitration Loss Detected) - * 4. SSD 1 (Clear Slave Stop Detected) - */ -#define I2C_ISR_INIT 0x7FF /* status register init */ - -struct i2c_slave_client; - -struct i2c_pxa_platform_data { - unsigned int slave_addr; - struct i2c_slave_client *slave; - unsigned int class; - unsigned int use_pio :1; - unsigned int fast_mode :1; -}; - -extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info); - -#ifdef CONFIG_PXA27x -extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info); -#endif - -#ifdef CONFIG_PXA3xx -extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info); -#endif - -#endif diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index c872b9feb4d..ad5378b1af9 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index c899bbd94dc..5a9df973935 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index a6c8429e975..f4dabf0273c 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index ff8052ce0a0..804c25c4a06 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 6c12b5a3132..095521e9ee2 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 036bbde4d22..74f4ce600ca 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index a425ec71e65..c54ad8b3343 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index b02d4544dc9..462503a2e79 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c index ff823999143..8241a63ea58 100644 --- a/arch/arm/mach-pxa/saar.c +++ b/arch/arm/mach-pxa/saar.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "devices.h" diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 5a45fe340a1..229f48577d5 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index a0bd46ef5d3..168267a5dfb 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index f79c9cb70ae..825f540176d 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index dd031cc4184..d33c232b686 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c index c256c57642c..cefd1c0a854 100644 --- a/arch/arm/mach-pxa/zylonite_pxa300.c +++ b/arch/arm/mach-pxa/zylonite_pxa300.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "generic.h" diff --git a/arch/arm/plat-pxa/include/plat/i2c.h b/arch/arm/plat-pxa/include/plat/i2c.h new file mode 100644 index 00000000000..1a9f65e6ec0 --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/i2c.h @@ -0,0 +1,82 @@ +/* + * i2c_pxa.h + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef _I2C_PXA_H_ +#define _I2C_PXA_H_ + +#if 0 +#define DEF_TIMEOUT 3 +#else +/* need a longer timeout if we're dealing with the fact we may well be + * looking at a multi-master environment +*/ +#define DEF_TIMEOUT 32 +#endif + +#define BUS_ERROR (-EREMOTEIO) +#define XFER_NAKED (-ECONNREFUSED) +#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ + +/* ICR initialize bit values +* +* 15. FM 0 (100 Khz operation) +* 14. UR 0 (No unit reset) +* 13. SADIE 0 (Disables the unit from interrupting on slave addresses +* matching its slave address) +* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration +* in master mode) +* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) +* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) +* 9. IRFIE 1 (Enable interrupts from full buffer received) +* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) +* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) +* 6. IUE 0 (Disable unit until we change settings) +* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) +* 4. MA 0 (Only send stop with the ICR stop bit) +* 3. TB 0 (We are not transmitting a byte initially) +* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) +* 1. STOP 0 (Do not send a STOP) +* 0. START 0 (Do not send a START) +* +*/ +#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) + +/* I2C status register init values + * + * 10. BED 1 (Clear bus error detected) + * 9. SAD 1 (Clear slave address detected) + * 7. IRF 1 (Clear IDBR Receive Full) + * 6. ITE 1 (Clear IDBR Transmit Empty) + * 5. ALD 1 (Clear Arbitration Loss Detected) + * 4. SSD 1 (Clear Slave Stop Detected) + */ +#define I2C_ISR_INIT 0x7FF /* status register init */ + +struct i2c_slave_client; + +struct i2c_pxa_platform_data { + unsigned int slave_addr; + struct i2c_slave_client *slave; + unsigned int class; + unsigned int use_pio :1; + unsigned int fast_mode :1; +}; + +extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info); + +#ifdef CONFIG_PXA27x +extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info); +#endif + +#ifdef CONFIG_PXA3xx +extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info); +#endif + +#endif diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index e4ee8835b97..035a6c7e59d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -36,7 +36,7 @@ #include #include -#include +#include /* * I2C register offsets will be shifted 0 or 1 bit left, depending on -- cgit v1.2.3-70-g09d2 From 9528d1c7a541b481a0e80301dc8d545848104023 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 18 May 2009 08:14:41 -0400 Subject: i2c: Blackfin TWI: make sure we don't end up with a CLKDIV=0 Make sure we don't end up with an invalid CLKDIV=0 in case someone specifies 20kHz SCL or less (5 * 1024 / 20 = 0x100). Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu [ben-linux@fluff.org: shortened subject line] Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 2 +- drivers/i2c/busses/i2c-bfin-twi.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f1c6ca7e285..c8460fa9cfa 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -298,7 +298,7 @@ config I2C_BLACKFIN_TWI config I2C_BLACKFIN_TWI_CLK_KHZ int "Blackfin TWI I2C clock (kHz)" depends on I2C_BLACKFIN_TWI - range 10 400 + range 21 400 default 50 help The unit of the TWI clock is kHz. diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fc548b3d002..77cafb6ba92 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -614,6 +614,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) struct i2c_adapter *p_adap; struct resource *res; int rc; + unsigned int clkhilow; iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL); if (!iface) { @@ -675,10 +676,14 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) /* Set TWI internal clock as 10MHz */ write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + /* + * We will not end up with a CLKDIV=0 because no one will specify + * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100) + */ + clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ; + /* Set Twi interface clock as specified */ - write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) - << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) - & 0xFF)); + write_CLKDIV(iface, (clkhilow << 8) | clkhilow); /* Enable TWI */ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); -- cgit v1.2.3-70-g09d2 From 57a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 19 May 2009 07:21:58 -0400 Subject: i2c: Blackfin TWI: fix REPEAT START mode doesn't repeat Avoid rewrite TWI MASTER_CTL reg when issue next message In i2c repeat transfer mode, byte count of next message should be filled into part of the TWI MASTER_CTL reg when interrupt MCOMP of last message transfer is triggered. But, other bits in this reg should not be touched. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu [ben-linux@fluff.org: shorted subject] Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 15 +++++++-------- 1 file changed, 7 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 77cafb6ba92..4d73ad7b570 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -196,8 +196,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MEN | MDIR); SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && iface->cur_msg+1 < iface->msg_num) { @@ -222,18 +220,19 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) } if (iface->pmsg[iface->cur_msg].len <= 255) - write_MASTER_CTL(iface, - iface->pmsg[iface->cur_msg].len << 6); + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) & + (~(0xff << 6))) | + (iface->pmsg[iface->cur_msg].len << 6)); else { - write_MASTER_CTL(iface, 0xff << 6); + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | + (0xff << 6))); iface->manual_stop = 1; } /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - write_MASTER_CTL(iface, read_MASTER_CTL(iface) | - MEN | ((iface->read_write == I2C_SMBUS_READ) ? - MDIR : 0)); SSYNC(); } else { iface->result = 1; -- cgit v1.2.3-70-g09d2 From 94327d009e3aa20214e9dfa486a1fd14445fe736 Mon Sep 17 00:00:00 2001 From: Frank Shew Date: Tue, 19 May 2009 07:23:49 -0400 Subject: i2c: Blackfin TWI: fix transfer errors with repeat start We have a custom BF537 board with an I2C RTC (MAX DS3231) running uclinux 2007R1 for some time. Recently during migration to 2008R1.5-RC3 we losted access to the RTC. The RTC driver calls 'i2c_transfer()' which in turns calls 'bfin_twi_master_xfer()' in i2c-bfin-twi.c. Compared with 2007R1, it looks like the 2008R1.5 version of i2c-bin-twi.c has a new mode 'TWI_I2C-MODE_REPEAT' which corresponds to the Repeat Start Condition described in the HRM. However, according to the HRM, at XMIT or RECV interrupt and when the data count is 0, not only is the RESTART bit supposed to be set, but MDIR must also be set if the next operation is a receive sequence, and cleared if not. Currently there is no code that looks at the I2C_M_RD bit in the flag from the next cur_msg and set/clear the MDIR flag accordingly at the same time that the RSTART bit is set. Instead, MDIR is set or cleared (by OR'ing with 0?) after the RESTART bit has been cleared during handling of MCOMP interrupt. It appears that this is causing our failure with reading the RTC, as a quick patch to set/clear MDIR when RESTART is set seem to solve our problem. Signed-off-by: Frank Shew Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu [ben-linux@fluff.org: shorted subject] Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 4d73ad7b570..40136ea7a46 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -104,9 +104,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *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) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART); + 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); + } SSYNC(); /* Clear status */ write_INT_STAT(iface, XMTSERV); @@ -134,9 +139,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) read_MASTER_CTL(iface) | STOP); SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg+1 < iface->msg_num) { - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART); + 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); SSYNC(); } /* Clear interrupt source */ -- cgit v1.2.3-70-g09d2 From e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 May 2009 09:24:10 +0000 Subject: i2c: Blackfin TWI: implement I2C_FUNC_SMBUS_I2C_BLOCK functionality Some drivers need i2c_smbus_read_i2c_block_data() functionality, so add support for it to the Blackfin I2C bus driver. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger [ben-linux@fluff.org: shortened subject] Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 12 +++++++++++- 1 file changed, 11 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 40136ea7a46..26d8987e69b 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -449,6 +449,16 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, } iface->transPtr = data->block; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->block[1]; + break; default: return -1; } @@ -572,7 +582,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_I2C; + I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK; } static struct i2c_algorithm bfin_twi_algorithm = { -- cgit v1.2.3-70-g09d2 From baf46b4e378d7950dff7ba30cfd50ff585987cb4 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 27 May 2009 17:54:45 +0300 Subject: i2c: OMAP2/3: Fix scll/sclh calculations Fix scll/sclh calculations for HS and fast modes. Currently the driver uses equal (roughly) low/high times which will result in too short low time. OMAP3430 TRM gives the following equations: F/S: tLow = (scll + 7) * internal_clk tHigh = (sclh + 5) * internal_clk HS: tLow = (scll + 7) * fclk tHigh = (sclh + 5) * fclk Furthermore, the I2C specification sets the following minimum values for HS tLow/tHigh for capacitive bus loads 100 pF (maximum speed 3400) and 400 pF (maximum speed 1700): speed tLow tHigh 3400 160 ns 60 ns 1700 320 ns 120 ns and for F/S: speed tLow tHigh 400 1300 ns 600 ns 100 4700 ns 4000 ns By using duty cycles 33/66 (HS, F) and 50/50 (S) we stay above these minimum values. Signed-off-by: Aaro Koskinen Acked-by: Tony Lindgren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-omap.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ece0125a1ee..a879e4bf512 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -343,17 +343,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* If configured for High Speed */ if (dev->speed > 400) { + unsigned long scl; + /* For first phase of HS mode */ - fsscll = internal_clk / (400 * 2) - 6; - fssclh = internal_clk / (400 * 2) - 6; + scl = internal_clk / 400; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; /* For second phase of HS mode */ - hsscll = fclk_rate / (dev->speed * 2) - 6; - hssclh = fclk_rate / (dev->speed * 2) - 6; + scl = fclk_rate / dev->speed; + hsscll = scl - (scl / 3) - 7; + hssclh = (scl / 3) - 5; + } else if (dev->speed > 100) { + unsigned long scl; + + /* Fast mode */ + scl = internal_clk / dev->speed; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; } else { - /* To handle F/S modes */ - fsscll = internal_clk / (dev->speed * 2) - 6; - fssclh = internal_clk / (dev->speed * 2) - 6; + /* Standard mode */ + fsscll = internal_clk / (dev->speed * 2) - 7; + fssclh = internal_clk / (dev->speed * 2) - 5; } scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; -- cgit v1.2.3-70-g09d2 From 84bf2c868f3ca996e5bbd3beb2ef502f457140f3 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 27 May 2009 17:54:46 +0300 Subject: i2c: OMAP3: Better noise suppression for fast/standard modes Use longer noise filter period for fast and standard mode. Based on an earlier patch by Eero Nurkkala. Signed-off-by: Aaro Koskinen Acked-by: Tony Lindgren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-omap.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a879e4bf512..c73475dd0fb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) if (cpu_is_omap2430() || cpu_is_omap34xx()) { - /* HSI2C controller internal clk rate should be 19.2 Mhz */ - internal_clk = 19200; + /* + * HSI2C controller internal clk rate should be 19.2 Mhz for + * HS and for all modes on 2430. On 34xx we can use lower rate + * to get longer filter period for better noise suppression. + * The filter is iclk (fclk for HS) period. + */ + if (dev->speed > 400 || cpu_is_omap_2430()) + internal_clk = 19200; + else if (dev->speed > 100) + internal_clk = 9600; + else + internal_clk = 4000; fclk_rate = clk_get_rate(dev->fclk) / 1000; /* Compute prescaler divisor */ -- cgit v1.2.3-70-g09d2 From 7d85ccd816535f56880f7dfdb4de056794376b2c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Jun 2009 10:45:29 +0100 Subject: i2c-s3c2410: move to using platform idtable to match devices Change to using platform id table to match either of the two supported platform device names in the driver. This simplifies the driver init and exit code Note, log messages will now be prefixed with 's3c-i2c' instead of the driver name, so output will be of the form of: s3c-i2c s3c2440-i2c.0: slave address 0x10 Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-s3c2410.c | 48 ++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 1691ef0f1ee..079a312d36f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -51,6 +51,11 @@ enum s3c24xx_i2c_state { STATE_STOP }; +enum s3c24xx_i2c_type { + TYPE_S3C2410, + TYPE_S3C2440, +}; + struct s3c24xx_i2c { spinlock_t lock; wait_queue_head_t wait; @@ -88,8 +93,10 @@ struct s3c24xx_i2c { static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) { struct platform_device *pdev = to_platform_device(i2c->dev); + enum s3c24xx_i2c_type type; - return !strcmp(pdev->name, "s3c2440-i2c"); + type = platform_get_device_id(pdev)->driver_data; + return type == TYPE_S3C2440; } /* s3c24xx_i2c_master_complete @@ -969,52 +976,41 @@ static int s3c24xx_i2c_resume(struct platform_device *dev) /* device driver for platform bus bits */ -static struct platform_driver s3c2410_i2c_driver = { - .probe = s3c24xx_i2c_probe, - .remove = s3c24xx_i2c_remove, - .suspend_late = s3c24xx_i2c_suspend_late, - .resume = s3c24xx_i2c_resume, - .driver = { - .owner = THIS_MODULE, - .name = "s3c2410-i2c", - }, +static struct platform_device_id s3c24xx_driver_ids[] = { + { + .name = "s3c2410-i2c", + .driver_data = TYPE_S3C2410, + }, { + .name = "s3c2440-i2c", + .driver_data = TYPE_S3C2440, + }, { }, }; +MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -static struct platform_driver s3c2440_i2c_driver = { +static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove = s3c24xx_i2c_remove, .suspend_late = s3c24xx_i2c_suspend_late, .resume = s3c24xx_i2c_resume, + .id_table = s3c24xx_driver_ids, .driver = { .owner = THIS_MODULE, - .name = "s3c2440-i2c", + .name = "s3c-i2c", }, }; static int __init i2c_adap_s3c_init(void) { - int ret; - - ret = platform_driver_register(&s3c2410_i2c_driver); - if (ret == 0) { - ret = platform_driver_register(&s3c2440_i2c_driver); - if (ret) - platform_driver_unregister(&s3c2410_i2c_driver); - } - - return ret; + return platform_driver_register(&s3c24xx_i2c_driver); } subsys_initcall(i2c_adap_s3c_init); static void __exit i2c_adap_s3c_exit(void) { - platform_driver_unregister(&s3c2410_i2c_driver); - platform_driver_unregister(&s3c2440_i2c_driver); + platform_driver_unregister(&s3c24xx_i2c_driver); } module_exit(i2c_adap_s3c_exit); MODULE_DESCRIPTION("S3C24XX I2C Bus driver"); MODULE_AUTHOR("Ben Dooks, "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-i2c"); -MODULE_ALIAS("platform:s3c2440-i2c"); -- cgit v1.2.3-70-g09d2 From dd14be4c274fc484eccace03ae9726e516630331 Mon Sep 17 00:00:00 2001 From: Richard Röjfors Date: Fri, 5 Jun 2009 15:40:32 +0200 Subject: i2c-ocores: Can add I2C devices to the bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is sometimes a need for the ocores driver to add devices to the bus when installed. i2c_register_board_info can not always be used, because the I2C devices are not known at an early state, they could for instance be connected on a I2C bus on a PCI device which has the Open Cores IP. i2c_new_device can not be used in all cases either since the resulting bus nummer might be unknown. The solution is the pass a list of I2C devices in the platform data to the Open Cores driver. This is useful for MFD drivers. Signed-off-by: Richard Röjfors Signed-off-by: Ben Dooks --- Documentation/i2c/busses/i2c-ocores | 17 +++++++++++++++++ drivers/i2c/busses/i2c-ocores.c | 5 +++++ include/linux/i2c-ocores.h | 2 ++ 3 files changed, 24 insertions(+) (limited to 'drivers/i2c') diff --git a/Documentation/i2c/busses/i2c-ocores b/Documentation/i2c/busses/i2c-ocores index cfcebb10d14..c269aaa2f26 100644 --- a/Documentation/i2c/busses/i2c-ocores +++ b/Documentation/i2c/busses/i2c-ocores @@ -20,6 +20,8 @@ platform_device with the base address and interrupt number. The dev.platform_data of the device should also point to a struct ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the distance between registers and the input clock speed. +There is also a possibility to attach a list of i2c_board_info which +the i2c-ocores driver will add to the bus upon creation. E.G. something like: @@ -36,9 +38,24 @@ static struct resource ocores_resources[] = { }, }; +/* optional board info */ +struct i2c_board_info ocores_i2c_board_info[] = { + { + I2C_BOARD_INFO("tsc2003", 0x48), + .platform_data = &tsc2003_platform_data, + .irq = TSC_IRQ + }, + { + I2C_BOARD_INFO("adv7180", 0x42 >> 1), + .irq = ADV_IRQ + } +}; + static struct ocores_i2c_platform_data myi2c_data = { .regstep = 2, /* two bytes between registers */ .clock_khz = 50000, /* input clock of 50MHz */ + .devices = ocores_i2c_board_info, /* optional table of devices */ + .num_devices = ARRAY_SIZE(ocores_i2c_board_info), /* table size */ }; static struct platform_device myi2c = { diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index e5193bf7548..3542c6ba98f 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -216,6 +216,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) struct ocores_i2c_platform_data *pdata; struct resource *res, *res2; int ret; + int i; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -271,6 +272,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) goto add_adapter_failed; } + /* add in known devices to the bus */ + for (i = 0; i < pdata->num_devices; i++) + i2c_new_device(&i2c->adap, pdata->devices + i); + return 0; add_adapter_failed: diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 8ed591b0887..4d5e57ff661 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -14,6 +14,8 @@ struct ocores_i2c_platform_data { u32 regstep; /* distance between registers */ 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 */ }; #endif /* _LINUX_I2C_OCORES_H */ -- cgit v1.2.3-70-g09d2 From 1cf92b453a405f6e452737962933a19ec1582029 Mon Sep 17 00:00:00 2001 From: Jack Stone Date: Mon, 15 Jun 2009 18:01:46 +0200 Subject: i2c: Remove void casts Remove uneeded void casts. Signed-off-by: Jack Stone Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 85e2e919d1c..dfd7bc8094b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1509,7 +1509,7 @@ struct i2c_adapter* i2c_get_adapter(int id) struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; -- cgit v1.2.3-70-g09d2 From 66b650f04576a6737579ec404446450026ff2e0b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 15 Jun 2009 18:01:46 +0200 Subject: i2c: Retry automatically on arbitration loss Some small changes in i2c core to retry i2c xfers until either the maximum number of retries or the timeout is hit. Signed-off-by: Clifford Wolf Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dfd7bc8094b..635c488262c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1022,7 +1022,8 @@ module_exit(i2c_exit); */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - int ret; + unsigned long orig_jiffies; + int ret, try; /* REVISIT the fault reporting model here is weak: * @@ -1060,7 +1061,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) mutex_lock_nested(&adap->bus_lock, adap->level); } - ret = adap->algo->master_xfer(adap,msgs,num); + /* 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; + } mutex_unlock(&adap->bus_lock); return ret; @@ -1995,14 +2004,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { + unsigned long orig_jiffies; + int try; s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { mutex_lock(&adapter->bus_lock); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, - command, protocol, data); + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adapter->retries; try++) { + res = adapter->algo->smbus_xfer(adapter, addr, flags, + read_write, command, + protocol, data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adapter->timeout)) + break; + } mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, -- cgit v1.2.3-70-g09d2 From fa1b2ca4fa271f9300a764b9d505a027156f749b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:48 +0200 Subject: i2c: Do not probe for TV chips on Voodoo3 adapters There's no point in giving the I2C bus of Voodoo3 adapters a class value, there's no video chip driver checking for it anymore. If support is ever needed, the video device should be instantiated explicitly rather than probed. To the best of my knowledge the only video chip that can be found on these boards is a BT869 video encoder, for which no support exists currently. Signed-off-by: Jean Delvare Acked-by: Krzysztof Helt --- drivers/i2c/busses/i2c-voodoo3.c | 1 - drivers/video/tdfxfb.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 1a474acc0dd..7663d57833a 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, }; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 89f231dc443..ff43c888502 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); chan->adapter.owner = THIS_MODULE; - chan->adapter.class = I2C_CLASS_TV_ANALOG; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = dev; chan->algo.setsda = tdfxfb_i2c_setsda; -- cgit v1.2.3-70-g09d2 From c52cf01f5b35d77b2a918c319e22567de5c3c15f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:48 +0200 Subject: i2c: Do not give adapters a default parent We don't need to give adapters a parent if they don't have one. The driver core will put them in the virtual device directory and all will be fine. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 635c488262c..5ed622ee65c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) mutex_lock(&core_lock); - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. - */ - if (adap->dev.parent == NULL) { - adap->dev.parent = &platform_bus; - pr_debug("I2C adapter driver [%s] forgot to specify " - "physical device\n", adap->name); - } - /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; -- cgit v1.2.3-70-g09d2 From 4b364f230a5ef984818837ec7c2be0884eac191c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Jun 2009 18:01:49 +0200 Subject: i2c/chips: Move max6875 to drivers/misc/eeprom This driver only reads the user EEPROM of that chip, so we can move it to the eeprom-directory in order to further clean up (and later remove) drivers/i2c/chips. The Kconfig text was updated to match the current functionality, dropping the meanwhile obsoleted parts. Defconfigs have been adapted. Signed-off-by: Wolfram Sang Acked-by: Ben Gardner Signed-off-by: Jean Delvare --- arch/mips/configs/bigsur_defconfig | 2 +- arch/mips/configs/mtx1_defconfig | 2 +- arch/powerpc/configs/ppc6xx_defconfig | 2 +- drivers/i2c/chips/Kconfig | 15 --- drivers/i2c/chips/Makefile | 1 - drivers/i2c/chips/max6875.c | 246 ---------------------------------- drivers/misc/eeprom/Kconfig | 14 ++ drivers/misc/eeprom/Makefile | 1 + drivers/misc/eeprom/max6875.c | 246 ++++++++++++++++++++++++++++++++++ 9 files changed, 264 insertions(+), 265 deletions(-) delete mode 100644 drivers/i2c/chips/max6875.c create mode 100644 drivers/misc/eeprom/max6875.c (limited to 'drivers/i2c') diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 783da855a2e..d6d35b2e5fe 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -963,7 +963,7 @@ CONFIG_EEPROM_LEGACY=y CONFIG_SENSORS_PCF8574=y # CONFIG_PCF8575 is not set CONFIG_SENSORS_PCF8591=y -CONFIG_SENSORS_MAX6875=y +CONFIG_EEPROM_MAX6875=y # CONFIG_SENSORS_TSL2550 is not set CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 8426d3b9501..fadb351d249 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -1849,7 +1849,7 @@ CONFIG_EEPROM_LEGACY=m CONFIG_SENSORS_PCF8574=m CONFIG_SENSORS_PCA9539=m CONFIG_SENSORS_PCF8591=m -CONFIG_SENSORS_MAX6875=m +CONFIG_EEPROM_MAX6875=m # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 7d044dfd923..12dc7c40961 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -1808,7 +1808,7 @@ CONFIG_PCF8575=m CONFIG_SENSORS_PCA9539=m CONFIG_SENSORS_PCF8591=m # CONFIG_TPS65010 is not set -CONFIG_SENSORS_MAX6875=m +CONFIG_EEPROM_MAX6875=m CONFIG_SENSORS_TSL2550=m CONFIG_MCU_MPC8349EMITX=m # CONFIG_I2C_DEBUG_CORE is not set diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 8f8c81eb0ae..02d746c9c47 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -64,21 +64,6 @@ config SENSORS_PCA9539 This driver is deprecated and will be dropped soon. Use drivers/gpio/pca953x.c instead. -config SENSORS_MAX6875 - tristate "Maxim MAX6875 Power supply supervisor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Maxim MAX6875 - EEPROM-programmable, quad power-supply sequencer/supervisor. - - This provides an interface to program the EEPROM and reset the chip. - - This driver also supports the Maxim MAX6874 hex power-supply - sequencer/supervisor if found at a compatible address. - - This driver can also be built as a module. If so, the module - will be called max6875. - config SENSORS_TSL2550 tristate "Taos TSL2550 ambient light sensor" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 55a37603718..f4680d16ee3 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,7 +11,6 @@ # obj-$(CONFIG_DS1682) += ds1682.o -obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_PCF8575) += pcf8575.o diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c deleted file mode 100644 index 033d9d81ec8..00000000000 --- a/drivers/i2c/chips/max6875.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - max6875.c - driver for MAX6874/MAX6875 - - Copyright (C) 2005 Ben Gardner - - Based on i2c/chips/eeprom.c - - The MAX6875 has a bank of registers and two banks of EEPROM. - Address ranges are defined as follows: - * 0x0000 - 0x0046 = configuration registers - * 0x8000 - 0x8046 = configuration EEPROM - * 0x8100 - 0x82FF = user EEPROM - - This driver makes the user EEPROM available for read. - - The registers & config EEPROM should be accessed via i2c-dev. - - The MAX6875 ignores the lowest address bit, so each chip responds to - two addresses - 0x50/0x51 and 0x52/0x53. - - Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read - address, so this driver is destructive if loaded for the wrong EEPROM chip. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. -*/ - -#include -#include -#include -#include -#include -#include - -/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Insmod parameters */ -I2C_CLIENT_INSMOD_1(max6875); - -/* The MAX6875 can only read/write 16 bytes at a time */ -#define SLICE_SIZE 16 -#define SLICE_BITS 4 - -/* USER EEPROM is at addresses 0x8100 - 0x82FF */ -#define USER_EEPROM_BASE 0x8100 -#define USER_EEPROM_SIZE 0x0200 -#define USER_EEPROM_SLICES 32 - -/* MAX6875 commands */ -#define MAX6875_CMD_BLK_READ 0x84 - -/* Each client has this additional data */ -struct max6875_data { - struct i2c_client *fake_client; - struct mutex update_lock; - - u32 valid; - u8 data[USER_EEPROM_SIZE]; - unsigned long last_updated[USER_EEPROM_SLICES]; -}; - -static void max6875_update_slice(struct i2c_client *client, int slice) -{ - struct max6875_data *data = i2c_get_clientdata(client); - int i, j, addr; - u8 *buf; - - if (slice >= USER_EEPROM_SLICES) - return; - - mutex_lock(&data->update_lock); - - buf = &data->data[slice << SLICE_BITS]; - - if (!(data->valid & (1 << slice)) || - time_after(jiffies, data->last_updated[slice])) { - - dev_dbg(&client->dev, "Starting update of slice %u\n", slice); - - data->valid &= ~(1 << slice); - - addr = USER_EEPROM_BASE + (slice << SLICE_BITS); - - /* select the eeprom address */ - if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { - dev_err(&client->dev, "address set failed\n"); - goto exit_up; - } - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - if (i2c_smbus_read_i2c_block_data(client, - MAX6875_CMD_BLK_READ, - SLICE_SIZE, - buf) != SLICE_SIZE) { - goto exit_up; - } - } else { - for (i = 0; i < SLICE_SIZE; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - goto exit_up; - } - buf[i] = j; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -exit_up: - mutex_unlock(&data->update_lock); -} - -static ssize_t max6875_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = kobj_to_i2c_client(kobj); - struct max6875_data *data = i2c_get_clientdata(client); - int slice, max_slice; - - if (off > USER_EEPROM_SIZE) - return 0; - - if (off + count > USER_EEPROM_SIZE) - count = USER_EEPROM_SIZE - off; - - /* refresh slices which contain requested bytes */ - max_slice = (off + count - 1) >> SLICE_BITS; - for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) - max6875_update_slice(client, slice); - - memcpy(buf, &data->data[off], count); - - return count; -} - -static struct bin_attribute user_eeprom_attr = { - .attr = { - .name = "eeprom", - .mode = S_IRUGO, - }, - .size = USER_EEPROM_SIZE, - .read = max6875_read, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int max6875_detect(struct i2c_client *client, int kind, - struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA - | I2C_FUNC_SMBUS_READ_BYTE)) - return -ENODEV; - - /* Only check even addresses */ - if (client->addr & 1) - return -ENODEV; - - strlcpy(info->type, "max6875", I2C_NAME_SIZE); - - return 0; -} - -static int max6875_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct max6875_data *data; - int err; - - if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) - return -ENOMEM; - - /* A fake client is created on the odd address */ - data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); - if (!data->fake_client) { - err = -ENOMEM; - goto exit_kfree; - } - - /* Init real i2c_client */ - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - - err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); - if (err) - goto exit_remove_fake; - - return 0; - -exit_remove_fake: - i2c_unregister_device(data->fake_client); -exit_kfree: - kfree(data); - return err; -} - -static int max6875_remove(struct i2c_client *client) -{ - struct max6875_data *data = i2c_get_clientdata(client); - - i2c_unregister_device(data->fake_client); - - sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); - kfree(data); - - return 0; -} - -static const struct i2c_device_id max6875_id[] = { - { "max6875", 0 }, - { } -}; - -static struct i2c_driver max6875_driver = { - .driver = { - .name = "max6875", - }, - .probe = max6875_probe, - .remove = max6875_remove, - .id_table = max6875_id, - - .detect = max6875_detect, - .address_data = &addr_data, -}; - -static int __init max6875_init(void) -{ - return i2c_add_driver(&max6875_driver); -} - -static void __exit max6875_exit(void) -{ - i2c_del_driver(&max6875_driver); -} - - -MODULE_AUTHOR("Ben Gardner "); -MODULE_DESCRIPTION("MAX6875 driver"); -MODULE_LICENSE("GPL"); - -module_init(max6875_init); -module_exit(max6875_exit); diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 89fec052f3b..9118613af32 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -48,6 +48,20 @@ config EEPROM_LEGACY This driver can also be built as a module. If so, the module will be called eeprom. +config EEPROM_MAX6875 + tristate "Maxim MAX6874/5 power supply supervisor" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get read-only support for the user EEPROM of + the Maxim MAX6874/5 EEPROM-programmable, quad power-supply + sequencer/supervisor. + + All other features of this chip should be accessed via i2c-dev. + + This driver can also be built as a module. If so, the module + will be called max6875. + + config EEPROM_93CX6 tristate "EEPROM 93CX6 support" help diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 539dd8f8812..df3d68ffa9d 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_EEPROM_AT24) += at24.o obj-$(CONFIG_EEPROM_AT25) += at25.o obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o +obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c new file mode 100644 index 00000000000..3c0c58eed34 --- /dev/null +++ b/drivers/misc/eeprom/max6875.c @@ -0,0 +1,246 @@ +/* + max6875.c - driver for MAX6874/MAX6875 + + Copyright (C) 2005 Ben Gardner + + Based on eeprom.c + + The MAX6875 has a bank of registers and two banks of EEPROM. + Address ranges are defined as follows: + * 0x0000 - 0x0046 = configuration registers + * 0x8000 - 0x8046 = configuration EEPROM + * 0x8100 - 0x82FF = user EEPROM + + This driver makes the user EEPROM available for read. + + The registers & config EEPROM should be accessed via i2c-dev. + + The MAX6875 ignores the lowest address bit, so each chip responds to + two addresses - 0x50/0x51 and 0x52/0x53. + + Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read + address, so this driver is destructive if loaded for the wrong EEPROM chip. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. +*/ + +#include +#include +#include +#include +#include +#include + +/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(max6875); + +/* The MAX6875 can only read/write 16 bytes at a time */ +#define SLICE_SIZE 16 +#define SLICE_BITS 4 + +/* USER EEPROM is at addresses 0x8100 - 0x82FF */ +#define USER_EEPROM_BASE 0x8100 +#define USER_EEPROM_SIZE 0x0200 +#define USER_EEPROM_SLICES 32 + +/* MAX6875 commands */ +#define MAX6875_CMD_BLK_READ 0x84 + +/* Each client has this additional data */ +struct max6875_data { + struct i2c_client *fake_client; + struct mutex update_lock; + + u32 valid; + u8 data[USER_EEPROM_SIZE]; + unsigned long last_updated[USER_EEPROM_SLICES]; +}; + +static void max6875_update_slice(struct i2c_client *client, int slice) +{ + struct max6875_data *data = i2c_get_clientdata(client); + int i, j, addr; + u8 *buf; + + if (slice >= USER_EEPROM_SLICES) + return; + + mutex_lock(&data->update_lock); + + buf = &data->data[slice << SLICE_BITS]; + + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice])) { + + dev_dbg(&client->dev, "Starting update of slice %u\n", slice); + + data->valid &= ~(1 << slice); + + addr = USER_EEPROM_BASE + (slice << SLICE_BITS); + + /* select the eeprom address */ + if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { + dev_err(&client->dev, "address set failed\n"); + goto exit_up; + } + + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_smbus_read_i2c_block_data(client, + MAX6875_CMD_BLK_READ, + SLICE_SIZE, + buf) != SLICE_SIZE) { + goto exit_up; + } + } else { + for (i = 0; i < SLICE_SIZE; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) { + goto exit_up; + } + buf[i] = j; + } + } + data->last_updated[slice] = jiffies; + data->valid |= (1 << slice); + } +exit_up: + mutex_unlock(&data->update_lock); +} + +static ssize_t max6875_read(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct max6875_data *data = i2c_get_clientdata(client); + int slice, max_slice; + + if (off > USER_EEPROM_SIZE) + return 0; + + if (off + count > USER_EEPROM_SIZE) + count = USER_EEPROM_SIZE - off; + + /* refresh slices which contain requested bytes */ + max_slice = (off + count - 1) >> SLICE_BITS; + for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) + max6875_update_slice(client, slice); + + memcpy(buf, &data->data[off], count); + + return count; +} + +static struct bin_attribute user_eeprom_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + }, + .size = USER_EEPROM_SIZE, + .read = max6875_read, +}; + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int max6875_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return -ENODEV; + + /* Only check even addresses */ + if (client->addr & 1) + return -ENODEV; + + strlcpy(info->type, "max6875", I2C_NAME_SIZE); + + return 0; +} + +static int max6875_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max6875_data *data; + int err; + + if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) + return -ENOMEM; + + /* A fake client is created on the odd address */ + data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); + if (!data->fake_client) { + err = -ENOMEM; + goto exit_kfree; + } + + /* Init real i2c_client */ + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); + if (err) + goto exit_remove_fake; + + return 0; + +exit_remove_fake: + i2c_unregister_device(data->fake_client); +exit_kfree: + kfree(data); + return err; +} + +static int max6875_remove(struct i2c_client *client) +{ + struct max6875_data *data = i2c_get_clientdata(client); + + i2c_unregister_device(data->fake_client); + + sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); + kfree(data); + + return 0; +} + +static const struct i2c_device_id max6875_id[] = { + { "max6875", 0 }, + { } +}; + +static struct i2c_driver max6875_driver = { + .driver = { + .name = "max6875", + }, + .probe = max6875_probe, + .remove = max6875_remove, + .id_table = max6875_id, + + .detect = max6875_detect, + .address_data = &addr_data, +}; + +static int __init max6875_init(void) +{ + return i2c_add_driver(&max6875_driver); +} + +static void __exit max6875_exit(void) +{ + i2c_del_driver(&max6875_driver); +} + + +MODULE_AUTHOR("Ben Gardner "); +MODULE_DESCRIPTION("MAX6875 driver"); +MODULE_LICENSE("GPL"); + +module_init(max6875_init); +module_exit(max6875_exit); -- cgit v1.2.3-70-g09d2 From a231591f0427cfb91ae247be974a7fa0e6b37389 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 15 Jun 2009 18:01:49 +0200 Subject: i2c-viapro: Add new PCI device ID for VX855 The south bridge of the VIA VX855 chipset has a different PCI Device ID so i2c-viapro.c needs to be updated with this. Signed-off-by: Harald Welte Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-viapro | 4 ++++ drivers/i2c/busses/Kconfig | 6 +++--- drivers/i2c/busses/i2c-viapro.c | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 22efedf60c8..2e758b0e945 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -19,6 +19,9 @@ Supported adapters: * VIA Technologies, Inc. VX800/VX820 Datasheet: available on http://linux.via.com.tw + * VIA Technologies, Inc. VX855/VX875 + Datasheet: Availability unknown + Authors: Kyösti Mälkki , Mark D. Studebaker , @@ -53,6 +56,7 @@ Your lspci -n listing must show one of these : device 1106:3287 (VT8251) device 1106:8324 (CX700) device 1106:8353 (VX800/VX820) + device 1106:8409 (VX855/VX875) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c8460fa9cfa..0d04d3ebfc2 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -211,7 +211,7 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820" + tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" depends on PCI help If you say yes to this option, support will be included for the VIA @@ -225,8 +225,8 @@ config I2C_VIAPRO VT8237R/A/S VT8251 CX700 - VX800 - VX820 + VX800/VX820 + VX855/VX875 This driver can also be built as a module. If so, the module will be called i2c-viapro. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 02e6f724b05..54d810a4d00 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -37,6 +37,7 @@ VT8251 0x3287 yes CX700 0x8324 yes VX800/VX820 0x8353 yes + VX855/VX875 0x8409 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -404,6 +405,7 @@ found: switch (pdev->device) { case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_VX800: + case PCI_DEVICE_ID_VIA_VX855: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), + .driver_data = SMBBA3 }, { 0, } }; -- cgit v1.2.3-70-g09d2 From 6df263cf2ee1c6dd9709488ecd3c7b3447511ecf Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 14 Jun 2009 01:55:37 -0400 Subject: i2c-bfin-twi: pull in io.h for ioremap() Rather than relying on some of the headers implicitly pulling in io.h, pull it in explicitly our self for ioremap() and friends. Signed-off-by: Mike Frysinger Signed-off-by: Ben Dooks --- 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 26d8987e69b..9fb114c274a 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 18904c0ecdf2cf22347da2adc4b273e9570333d8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 13 Jun 2009 21:51:34 +0200 Subject: i2c: ST DDC I2C U300 bus driver v3 This adds support for the ST Microelectronics DDC I2C bus driver. This bus is used in the U300 architecture recently added to RMK:s ARM tree. Signed-off-by: Linus Walleij Reviewed-by: Ben Dooks Reviewed-by: Jean Delvare Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 12 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-stu300.c | 1029 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1042 insertions(+) create mode 100644 drivers/i2c/busses/i2c-stu300.c (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0d04d3ebfc2..0e0a3904083 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -513,6 +513,18 @@ config I2C_SIMTEC This driver can also be built as a module. If so, the module will be called i2c-simtec. +config I2C_STU300 + tristate "ST Microelectronics DDC I2C interface" + default y if MACH_U300 + help + If you say yes to this option, support will be included for the + I2C interface from ST Microelectronics simply called "DDC I2C" + supporting both I2C and DDC, used in e.g. the U300 series + mobile platforms. + + This driver can also be built as a module. If so, the module + will be called i2c-stu300. + config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" depends on ARCH_VERSATILE || ARCH_REALVIEW diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 776acb6403a..edeabf00310 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o +obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o # External I2C/SMBus adapter drivers diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c new file mode 100644 index 00000000000..182e711318b --- /dev/null +++ b/drivers/i2c/busses/i2c-stu300.c @@ -0,0 +1,1029 @@ +/* + * Copyright (C) 2007-2009 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 + * Author: Jonas Aaberg + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* the name of this kernel module */ +#define NAME "stu300" + +/* CR (Control Register) 8bit (R/W) */ +#define I2C_CR (0x00000000) +#define I2C_CR_RESET_VALUE (0x00) +#define I2C_CR_RESET_UMASK (0x00) +#define I2C_CR_DDC1_ENABLE (0x80) +#define I2C_CR_TRANS_ENABLE (0x40) +#define I2C_CR_PERIPHERAL_ENABLE (0x20) +#define I2C_CR_DDC2B_ENABLE (0x10) +#define I2C_CR_START_ENABLE (0x08) +#define I2C_CR_ACK_ENABLE (0x04) +#define I2C_CR_STOP_ENABLE (0x02) +#define I2C_CR_INTERRUPT_ENABLE (0x01) +/* SR1 (Status Register 1) 8bit (R/-) */ +#define I2C_SR1 (0x00000004) +#define I2C_SR1_RESET_VALUE (0x00) +#define I2C_SR1_RESET_UMASK (0x00) +#define I2C_SR1_EVF_IND (0x80) +#define I2C_SR1_ADD10_IND (0x40) +#define I2C_SR1_TRA_IND (0x20) +#define I2C_SR1_BUSY_IND (0x10) +#define I2C_SR1_BTF_IND (0x08) +#define I2C_SR1_ADSL_IND (0x04) +#define I2C_SR1_MSL_IND (0x02) +#define I2C_SR1_SB_IND (0x01) +/* SR2 (Status Register 2) 8bit (R/-) */ +#define I2C_SR2 (0x00000008) +#define I2C_SR2_RESET_VALUE (0x00) +#define I2C_SR2_RESET_UMASK (0x40) +#define I2C_SR2_MASK (0xBF) +#define I2C_SR2_SCLFAL_IND (0x80) +#define I2C_SR2_ENDAD_IND (0x20) +#define I2C_SR2_AF_IND (0x10) +#define I2C_SR2_STOPF_IND (0x08) +#define I2C_SR2_ARLO_IND (0x04) +#define I2C_SR2_BERR_IND (0x02) +#define I2C_SR2_DDC2BF_IND (0x01) +/* CCR (Clock Control Register) 8bit (R/W) */ +#define I2C_CCR (0x0000000C) +#define I2C_CCR_RESET_VALUE (0x00) +#define I2C_CCR_RESET_UMASK (0x00) +#define I2C_CCR_MASK (0xFF) +#define I2C_CCR_FMSM (0x80) +#define I2C_CCR_CC_MASK (0x7F) +/* OAR1 (Own Address Register 1) 8bit (R/W) */ +#define I2C_OAR1 (0x00000010) +#define I2C_OAR1_RESET_VALUE (0x00) +#define I2C_OAR1_RESET_UMASK (0x00) +#define I2C_OAR1_ADD_MASK (0xFF) +/* OAR2 (Own Address Register 2) 8bit (R/W) */ +#define I2C_OAR2 (0x00000014) +#define I2C_OAR2_RESET_VALUE (0x40) +#define I2C_OAR2_RESET_UMASK (0x19) +#define I2C_OAR2_MASK (0xE6) +#define I2C_OAR2_FR_25_10MHZ (0x00) +#define I2C_OAR2_FR_10_1667MHZ (0x20) +#define I2C_OAR2_FR_1667_2667MHZ (0x40) +#define I2C_OAR2_FR_2667_40MHZ (0x60) +#define I2C_OAR2_FR_40_5333MHZ (0x80) +#define I2C_OAR2_FR_5333_66MHZ (0xA0) +#define I2C_OAR2_FR_66_80MHZ (0xC0) +#define I2C_OAR2_FR_80_100MHZ (0xE0) +#define I2C_OAR2_FR_MASK (0xE0) +#define I2C_OAR2_ADD_MASK (0x06) +/* DR (Data Register) 8bit (R/W) */ +#define I2C_DR (0x00000018) +#define I2C_DR_RESET_VALUE (0x00) +#define I2C_DR_RESET_UMASK (0xFF) +#define I2C_DR_D_MASK (0xFF) +/* ECCR (Extended Clock Control Register) 8bit (R/W) */ +#define I2C_ECCR (0x0000001C) +#define I2C_ECCR_RESET_VALUE (0x00) +#define I2C_ECCR_RESET_UMASK (0xE0) +#define I2C_ECCR_MASK (0x1F) +#define I2C_ECCR_CC_MASK (0x1F) + +/* + * These events are more or less responses to commands + * sent into the hardware, presumably reflecting the state + * of an internal state machine. + */ +enum stu300_event { + STU300_EVENT_NONE = 0, + STU300_EVENT_1, + STU300_EVENT_2, + STU300_EVENT_3, + STU300_EVENT_4, + STU300_EVENT_5, + STU300_EVENT_6, + STU300_EVENT_7, + STU300_EVENT_8, + STU300_EVENT_9 +}; + +enum stu300_error { + STU300_ERROR_NONE = 0, + STU300_ERROR_ACKNOWLEDGE_FAILURE, + STU300_ERROR_BUS_ERROR, + STU300_ERROR_ARBITRATION_LOST +}; + +/* timeout waiting for the controller to respond */ +#define STU300_TIMEOUT (msecs_to_jiffies(1000)) + +/* + * The number of address send athemps tried before giving up. + * If the first one failes it seems like 5 to 8 attempts are required. + */ +#define NUM_ADDR_RESEND_ATTEMPTS 10 + +/* I2C clock speed, in Hz 0-400kHz*/ +static unsigned int scl_frequency = 100000; +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 + * @cmd_complete: acknowledge completion for an I2C command + * @cmd_event: expected event coming in as a response to a command + * @cmd_err: error code as response to a command + * @speed: current bus speed in Hz + * @msg_index: index of current message + * @msg_len: length of current message + */ +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; + spinlock_t cmd_issue_lock; + struct completion cmd_complete; + enum stu300_event cmd_event; + enum stu300_error cmd_err; + unsigned int speed; + int msg_index; + int msg_len; +}; + +/* Local forward function declarations */ +static int stu300_init_hw(struct stu300_dev *dev); + +/* + * The block needs writes in both MSW and LSW in order + * for all data lines to reach their destination. + */ +static inline void stu300_wr8(u32 value, void __iomem *address) +{ + writel((value << 16) | value, address); +} + +/* + * This merely masks off the duplicates which appear + * in bytes 1-3. You _MUST_ use 32-bit bus access on this + * device, else it will not work. + */ +static inline u32 stu300_r8(void __iomem *address) +{ + return readl(address) & 0x000000FFU; +} + +/* + * Tells whether a certain event or events occurred in + * response to a command. The events represent states in + * the internal state machine of the hardware. The events + * are not very well described in the hardware + * documentation and can only be treated as abstract state + * machine states. + * + * @ret 0 = event has not occurred, any other value means + * the event occurred. + */ +static int stu300_event_occurred(struct stu300_dev *dev, + enum stu300_event mr_event) { + u32 status1; + u32 status2; + + /* What event happened? */ + status1 = stu300_r8(dev->virtbase + I2C_SR1); + if (!(status1 & I2C_SR1_EVF_IND)) + /* No event at all */ + return 0; + status2 = stu300_r8(dev->virtbase + I2C_SR2); + + switch (mr_event) { + case STU300_EVENT_1: + if (status1 & I2C_SR1_ADSL_IND) + return 1; + break; + case STU300_EVENT_2: + case STU300_EVENT_3: + case STU300_EVENT_7: + case STU300_EVENT_8: + if (status1 & I2C_SR1_BTF_IND) { + if (status2 & I2C_SR2_AF_IND) + dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE; + else if (status2 & I2C_SR2_BERR_IND) + dev->cmd_err = STU300_ERROR_BUS_ERROR; + return 1; + } + break; + case STU300_EVENT_4: + if (status2 & I2C_SR2_STOPF_IND) + return 1; + break; + case STU300_EVENT_5: + if (status1 & I2C_SR1_SB_IND) + /* Clear start bit */ + return 1; + break; + case STU300_EVENT_6: + if (status2 & I2C_SR2_ENDAD_IND) { + /* First check for any errors */ + if (status2 & I2C_SR2_AF_IND) + dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE; + return 1; + } + break; + case STU300_EVENT_9: + if (status1 & I2C_SR1_ADD10_IND) + return 1; + break; + default: + break; + } + if (status2 & I2C_SR2_ARLO_IND) + dev->cmd_err = STU300_ERROR_ARBITRATION_LOST; + return 0; +} + +static irqreturn_t stu300_irh(int irq, void *data) +{ + struct stu300_dev *dev = data; + int res; + + /* See if this was what we were waiting for */ + spin_lock(&dev->cmd_issue_lock); + if (dev->cmd_event != STU300_EVENT_NONE) { + res = stu300_event_occurred(dev, dev->cmd_event); + if (res || dev->cmd_err != STU300_ERROR_NONE) { + u32 val; + + complete(&dev->cmd_complete); + /* Block any multiple interrupts */ + val = stu300_r8(dev->virtbase + I2C_CR); + val &= ~I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + } + } + spin_unlock(&dev->cmd_issue_lock); + return IRQ_HANDLED; +} + +/* + * Sends a command and then waits for the bits masked by *flagmask* + * to go high or low by IRQ awaiting. + */ +static int stu300_start_and_await_event(struct stu300_dev *dev, + u8 cr_value, + enum stu300_event mr_event) +{ + int ret; + + if (unlikely(irqs_disabled())) { + /* TODO: implement polling for this case if need be. */ + WARN(1, "irqs are disabled, cannot poll for event\n"); + return -EIO; + } + + /* Lock command issue, fill in an event we wait for */ + spin_lock_irq(&dev->cmd_issue_lock); + init_completion(&dev->cmd_complete); + dev->cmd_err = STU300_ERROR_NONE; + dev->cmd_event = mr_event; + spin_unlock_irq(&dev->cmd_issue_lock); + + /* Turn on interrupt, send command and wait. */ + cr_value |= I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(cr_value, dev->virtbase + I2C_CR); + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + STU300_TIMEOUT); + + if (ret < 0) { + dev_err(&dev->pdev->dev, + "wait_for_completion_interruptible_timeout() " + "returned %d waiting for event %04x\n", ret, mr_event); + return ret; + } + + if (ret == 0) { + dev_err(&dev->pdev->dev, "controller timed out " + "waiting for event %d, reinit hardware\n", mr_event); + (void) stu300_init_hw(dev); + return -ETIMEDOUT; + } + + if (dev->cmd_err != STU300_ERROR_NONE) { + dev_err(&dev->pdev->dev, "controller (start) " + "error %d waiting for event %d, reinit hardware\n", + dev->cmd_err, mr_event); + (void) stu300_init_hw(dev); + return -EIO; + } + + return 0; +} + +/* + * This waits for a flag to be set, if it is not set on entry, an interrupt is + * configured to wait for the flag using a completion. + */ +static int stu300_await_event(struct stu300_dev *dev, + enum stu300_event mr_event) +{ + int ret; + u32 val; + + if (unlikely(irqs_disabled())) { + /* TODO: implement polling for this case if need be. */ + dev_err(&dev->pdev->dev, "irqs are disabled on this " + "system!\n"); + return -EIO; + } + + /* Is it already here? */ + spin_lock_irq(&dev->cmd_issue_lock); + dev->cmd_err = STU300_ERROR_NONE; + if (stu300_event_occurred(dev, mr_event)) { + spin_unlock_irq(&dev->cmd_issue_lock); + goto exit_await_check_err; + } + init_completion(&dev->cmd_complete); + dev->cmd_err = STU300_ERROR_NONE; + dev->cmd_event = mr_event; + + /* Turn on the I2C interrupt for current operation */ + val = stu300_r8(dev->virtbase + I2C_CR); + val |= I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + + /* Twice paranoia (possible HW glitch) */ + stu300_wr8(val, dev->virtbase + I2C_CR); + + /* Check again: is it already here? */ + if (unlikely(stu300_event_occurred(dev, mr_event))) { + /* Disable IRQ again. */ + val &= ~I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + spin_unlock_irq(&dev->cmd_issue_lock); + goto exit_await_check_err; + } + + /* Unlock the command block and wait for the event to occur */ + spin_unlock_irq(&dev->cmd_issue_lock); + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + STU300_TIMEOUT); + + if (ret < 0) { + dev_err(&dev->pdev->dev, + "wait_for_completion_interruptible_timeout()" + "returned %d waiting for event %04x\n", ret, mr_event); + return ret; + } + + if (ret == 0) { + if (mr_event != STU300_EVENT_6) { + dev_err(&dev->pdev->dev, "controller " + "timed out waiting for event %d, reinit " + "hardware\n", mr_event); + (void) stu300_init_hw(dev); + } + return -ETIMEDOUT; + } + + exit_await_check_err: + if (dev->cmd_err != STU300_ERROR_NONE) { + if (mr_event != STU300_EVENT_6) { + dev_err(&dev->pdev->dev, "controller " + "error (await_event) %d waiting for event %d, " + "reinit hardware\n", dev->cmd_err, mr_event); + (void) stu300_init_hw(dev); + } + return -EIO; + } + + return 0; +} + +/* + * Waits for the busy bit to go low by repeated polling. + */ +#define BUSY_RELEASE_ATTEMPTS 10 +static int stu300_wait_while_busy(struct stu300_dev *dev) +{ + unsigned long timeout; + int i; + + for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) { + timeout = jiffies + STU300_TIMEOUT; + + while (!time_after(jiffies, timeout)) { + /* Is not busy? */ + if ((stu300_r8(dev->virtbase + I2C_SR1) & + I2C_SR1_BUSY_IND) == 0) + return 0; + msleep(1); + } + + dev_err(&dev->pdev->dev, "transaction timed out " + "waiting for device to be free (not busy). " + "Attempt: %d\n", i+1); + + dev_err(&dev->pdev->dev, "base address = " + "0x%08x, reinit hardware\n", (u32) dev->virtbase); + + (void) stu300_init_hw(dev); + } + + dev_err(&dev->pdev->dev, "giving up after %d attempts " + "to reset the bus.\n", BUSY_RELEASE_ATTEMPTS); + + return -ETIMEDOUT; +} + +struct stu300_clkset { + unsigned long rate; + u32 setting; +}; + +static const struct stu300_clkset stu300_clktable[] = { + { 0, 0xFFU }, + { 2500000, I2C_OAR2_FR_25_10MHZ }, + { 10000000, I2C_OAR2_FR_10_1667MHZ }, + { 16670000, I2C_OAR2_FR_1667_2667MHZ }, + { 26670000, I2C_OAR2_FR_2667_40MHZ }, + { 40000000, I2C_OAR2_FR_40_5333MHZ }, + { 53330000, I2C_OAR2_FR_5333_66MHZ }, + { 66000000, I2C_OAR2_FR_66_80MHZ }, + { 80000000, I2C_OAR2_FR_80_100MHZ }, + { 100000000, 0xFFU }, +}; + +static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) +{ + + u32 val; + int i = 0; + + /* Locate the apropriate clock setting */ + while (i < ARRAY_SIZE(stu300_clktable) && + stu300_clktable[i].rate < clkrate) + i++; + + if (stu300_clktable[i].setting == 0xFFU) { + dev_err(&dev->pdev->dev, "too %s clock rate requested " + "(%lu Hz).\n", i ? "high" : "low", clkrate); + return -EINVAL; + } + + stu300_wr8(stu300_clktable[i].setting, + dev->virtbase + I2C_OAR2); + + dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz " + "virtbase %p\n", clkrate, dev->speed, dev->virtbase); + + if (dev->speed > 100000) + /* Fast Mode I2C */ + val = ((clkrate/dev->speed)-9)/3; + else + /* Standard Mode I2C */ + val = ((clkrate/dev->speed)-7)/2; + + /* According to spec the divider must be > 2 */ + if (val < 0x002) { + dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n", + clkrate); + return -EINVAL; + } + + /* We have 12 bits clock divider only! */ + if (val & 0xFFFFF000U) { + dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n", + clkrate); + return -EINVAL; + } + + if (dev->speed > 100000) { + /* CC6..CC0 */ + stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM, + dev->virtbase + I2C_CCR); + dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, " + "Fast Mode I2C\n", val); + } else { + /* CC6..CC0 */ + stu300_wr8((val & I2C_CCR_CC_MASK), + dev->virtbase + I2C_CCR); + dev_dbg(&dev->pdev->dev, "set clock divider to " + "0x%08x, Standard Mode I2C\n", val); + } + + /* CC11..CC7 */ + stu300_wr8(((val >> 7) & 0x1F), + dev->virtbase + I2C_ECCR); + + return 0; +} + + +static int stu300_init_hw(struct stu300_dev *dev) +{ + u32 dummy; + unsigned long clkrate; + int ret; + + /* Disable controller */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + /* + * Set own address to some default value (0x00). + * We do not support slave mode anyway. + */ + stu300_wr8(0x00, dev->virtbase + I2C_OAR1); + /* + * The I2C controller only operates properly in 26 MHz but we + * program this driver as if we didn't know. This will also set the two + * high bits of the own address to zero as well. + * There is no known hardware issue with running in 13 MHz + * However, speeds over 200 kHz are not used. + */ + clkrate = clk_get_rate(dev->clk); + ret = stu300_set_clk(dev, clkrate); + if (ret) + return ret; + /* + * Enable block, do it TWICE (hardware glitch) + * Setting bit 7 can enable DDC mode. (Not used currently.) + */ + stu300_wr8(I2C_CR_PERIPHERAL_ENABLE, + dev->virtbase + I2C_CR); + stu300_wr8(I2C_CR_PERIPHERAL_ENABLE, + dev->virtbase + I2C_CR); + /* Make a dummy read of the status register SR1 & SR2 */ + dummy = stu300_r8(dev->virtbase + I2C_SR2); + dummy = stu300_r8(dev->virtbase + I2C_SR1); + + return 0; +} + + + +/* Send slave address. */ +static int stu300_send_address(struct stu300_dev *dev, + struct i2c_msg *msg, int resend) +{ + u32 val; + int ret; + + if (msg->flags & I2C_M_TEN) + /* This is probably how 10 bit addresses look */ + val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) & + I2C_DR_D_MASK; + else + val = ((msg->addr << 1) & I2C_DR_D_MASK); + + if (msg->flags & I2C_M_RD) { + /* This is the direction bit */ + val |= 0x01; + if (resend) + dev_dbg(&dev->pdev->dev, "read resend\n"); + } else if (resend) + dev_dbg(&dev->pdev->dev, "write resend\n"); + stu300_wr8(val, dev->virtbase + I2C_DR); + + /* For 10bit addressing, await 10bit request (EVENT 9) */ + if (msg->flags & I2C_M_TEN) { + ret = stu300_await_event(dev, STU300_EVENT_9); + /* + * The slave device wants a 10bit address, send the rest + * of the bits (the LSBits) + */ + val = msg->addr & I2C_DR_D_MASK; + /* This clears "event 9" */ + stu300_wr8(val, dev->virtbase + I2C_DR); + if (ret != 0) + return ret; + } + /* FIXME: Why no else here? two events for 10bit? + * Await event 6 (normal) or event 9 (10bit) + */ + + if (resend) + dev_dbg(&dev->pdev->dev, "await event 6\n"); + ret = stu300_await_event(dev, STU300_EVENT_6); + + /* + * Clear any pending EVENT 6 no matter what happend during + * await_event. + */ + val = stu300_r8(dev->virtbase + I2C_CR); + val |= I2C_CR_PERIPHERAL_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + + return ret; +} + +static int stu300_xfer_msg(struct i2c_adapter *adap, + struct i2c_msg *msg, int stop) +{ + u32 cr; + u32 val; + u32 i; + int ret; + int attempts = 0; + struct stu300_dev *dev = i2c_get_adapdata(adap); + + + clk_enable(dev->clk); + + /* Remove this if (0) to trace each and every message. */ + if (0) { + dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, " + "flags: 0x%04x, stop: %d\n", + msg->addr, msg->len, msg->flags, stop); + } + + /* Zero-length messages are not supported by this hardware */ + if (msg->len == 0) { + ret = -EINVAL; + goto exit_disable; + } + + /* + * For some reason, sending the address sometimes fails when running + * on the 13 MHz clock. No interrupt arrives. This is a work around, + * which tries to restart and send the address up to 10 times before + * really giving up. Usually 5 to 8 attempts are enough. + */ + do { + if (attempts) + dev_dbg(&dev->pdev->dev, "wait while busy\n"); + /* Check that the bus is free, or wait until some timeout */ + ret = stu300_wait_while_busy(dev); + if (ret != 0) + goto exit_disable; + + if (attempts) + dev_dbg(&dev->pdev->dev, "re-int hw\n"); + /* + * According to ST, there is no problem if the clock is + * changed between 13 and 26 MHz during a transfer. + */ + ret = stu300_init_hw(dev); + if (ret) + goto exit_disable; + + /* Send a start condition */ + cr = I2C_CR_PERIPHERAL_ENABLE; + /* Setting the START bit puts the block in master mode */ + if (!(msg->flags & I2C_M_NOSTART)) + cr |= I2C_CR_START_ENABLE; + if ((msg->flags & I2C_M_RD) && (msg->len > 1)) + /* On read more than 1 byte, we need ack. */ + cr |= I2C_CR_ACK_ENABLE; + /* Check that it gets through */ + if (!(msg->flags & I2C_M_NOSTART)) { + if (attempts) + dev_dbg(&dev->pdev->dev, "send start event\n"); + ret = stu300_start_and_await_event(dev, cr, + STU300_EVENT_5); + } + + if (attempts) + dev_dbg(&dev->pdev->dev, "send address\n"); + + if (ret == 0) + /* Send address */ + ret = stu300_send_address(dev, msg, attempts != 0); + + if (ret != 0) { + attempts++; + dev_dbg(&dev->pdev->dev, "failed sending address, " + "retrying. Attempt: %d msg_index: %d/%d\n", + attempts, dev->msg_index, dev->msg_len); + } + + } while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS); + + if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) { + dev_dbg(&dev->pdev->dev, "managed to get address " + "through after %d attempts\n", attempts); + } else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) { + dev_dbg(&dev->pdev->dev, "I give up, tried %d times " + "to resend address.\n", + NUM_ADDR_RESEND_ATTEMPTS); + goto exit_disable; + } + + if (msg->flags & I2C_M_RD) { + /* READ: we read the actual bytes one at a time */ + for (i = 0; i < msg->len; i++) { + if (i == msg->len-1) { + /* + * Disable ACK and set STOP condition before + * reading last byte + */ + val = I2C_CR_PERIPHERAL_ENABLE; + + if (stop) + val |= I2C_CR_STOP_ENABLE; + + stu300_wr8(val, + dev->virtbase + I2C_CR); + } + /* Wait for this byte... */ + ret = stu300_await_event(dev, STU300_EVENT_7); + if (ret != 0) + goto exit_disable; + /* This clears event 7 */ + msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR); + } + } else { + /* WRITE: we send the actual bytes one at a time */ + for (i = 0; i < msg->len; i++) { + /* Write the byte */ + stu300_wr8(msg->buf[i], + dev->virtbase + I2C_DR); + /* Check status */ + ret = stu300_await_event(dev, STU300_EVENT_8); + /* Next write to DR will clear event 8 */ + if (ret != 0) { + dev_err(&dev->pdev->dev, "error awaiting " + "event 8 (%d)\n", ret); + goto exit_disable; + } + } + /* Check NAK */ + if (!(msg->flags & I2C_M_IGNORE_NAK)) { + if (stu300_r8(dev->virtbase + I2C_SR2) & + I2C_SR2_AF_IND) { + dev_err(&dev->pdev->dev, "I2C payload " + "send returned NAK!\n"); + ret = -EIO; + goto exit_disable; + } + } + if (stop) { + /* Send stop condition */ + val = I2C_CR_PERIPHERAL_ENABLE; + val |= I2C_CR_STOP_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + } + } + + /* Check that the bus is free, or wait until some timeout occurs */ + ret = stu300_wait_while_busy(dev); + if (ret != 0) { + dev_err(&dev->pdev->dev, "timout waiting for transfer " + "to commence.\n"); + goto exit_disable; + } + + /* Dummy read status registers */ + val = stu300_r8(dev->virtbase + I2C_SR2); + val = stu300_r8(dev->virtbase + I2C_SR1); + ret = 0; + + exit_disable: + /* Disable controller */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + clk_disable(dev->clk); + return ret; +} + +static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret = -1; + int i; + struct stu300_dev *dev = i2c_get_adapdata(adap); + dev->msg_len = num; + for (i = 0; i < num; i++) { + /* + * Another driver appears to send stop for each message, + * here we only do that for the last message. Possibly some + * peripherals require this behaviour, then their drivers + * have to send single messages in order to get "stop" for + * each message. + */ + dev->msg_index = i; + + ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1))); + if (ret != 0) { + num = ret; + break; + } + } + + return num; +} + +static u32 stu300_func(struct i2c_adapter *adap) +{ + /* This is the simplest thing you can think of... */ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; +} + +static const struct i2c_algorithm stu300_algo = { + .master_xfer = stu300_xfer, + .functionality = stu300_func, +}; + +static int __init +stu300_probe(struct platform_device *pdev) +{ + struct stu300_dev *dev; + struct i2c_adapter *adap; + struct resource *res; + int bus_nr; + int ret = 0; + + dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "could not allocate device struct\n"); + ret = -ENOMEM; + goto err_no_devmem; + } + + bus_nr = pdev->id; + dev->clk = clk_get(&pdev->dev, NULL); + 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; + } + + 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->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_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; + } + + dev->irq = platform_get_irq(pdev, 0); + if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED, + NAME, dev)) { + ret = -EIO; + goto err_no_irq; + } + + dev->speed = scl_frequency; + + clk_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; + } + + /* IRQ event handling initialization */ + spin_lock_init(&dev->cmd_issue_lock); + dev->cmd_event = STU300_EVENT_NONE; + dev->cmd_err = STU300_ERROR_NONE; + + adap = &dev->adapter; + adap->owner = THIS_MODULE; + /* DDC class but actually often used for more generic I2C */ + adap->class = I2C_CLASS_DDC; + strncpy(adap->name, "ST Microelectronics DDC I2C adapter", + sizeof(adap->name)); + adap->nr = bus_nr; + adap->algo = &stu300_algo; + adap->dev.parent = &pdev->dev; + i2c_set_adapdata(adap, dev); + + /* 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 " + "I2C adapter\n"); + goto err_add_adapter; + } + return 0; + + err_add_adapter: + err_init_hw: + 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; +} + +#ifdef CONFIG_PM +static int stu300_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct stu300_dev *dev = platform_get_drvdata(pdev); + + /* Turn off everything */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + return 0; +} + +static int stu300_resume(struct platform_device *pdev) +{ + int ret = 0; + struct stu300_dev *dev = platform_get_drvdata(pdev); + + 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"); + return ret; +} +#else +#define stu300_suspend NULL +#define stu300_resume NULL +#endif + +static int __exit +stu300_remove(struct platform_device *pdev) +{ + struct stu300_dev *dev = platform_get_drvdata(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_put(dev->clk); + platform_set_drvdata(pdev, NULL); + kfree(dev); + return 0; +} + +static struct platform_driver stu300_i2c_driver = { + .driver = { + .name = NAME, + .owner = THIS_MODULE, + }, + .remove = __exit_p(stu300_remove), + .suspend = stu300_suspend, + .resume = stu300_resume, + +}; + +static int __init stu300_init(void) +{ + return platform_driver_probe(&stu300_i2c_driver, stu300_probe); +} + +static void __exit stu300_exit(void) +{ + platform_driver_unregister(&stu300_i2c_driver); +} + +/* + * The systems using this bus often have very basic devices such + * as regulators on the I2C bus, so this needs to be loaded early. + * Therefore it is registered in the subsys_initcall(). + */ +subsys_initcall(stu300_init); +module_exit(stu300_exit); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" NAME); -- cgit v1.2.3-70-g09d2 From c6ffddea36dd576b70dfbd10eb5d2b287b786dca Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 14 Jun 2009 00:20:36 +0200 Subject: i2c: Use resource_size macro This replace all instances in the i2c busses tree of res->end - res->start + 1 with the handy macro resource_size(res) from ioport.h (coming in from platform_device.h). This was created with a simple sed -i -e 's/\([a-z]*\)->end *- *[a-z]*->start *+ *1/resource_size(\1)/g' Then manually replacing the PXA redefiniton of the same kind of macro manually. Recompiled some ARM defconfigs I could find to make a rough test so it shouldn't break anything, though I couldn't see exactly which configs you need for all the drivers. Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-at91.c | 8 ++++---- drivers/i2c/busses/i2c-au1550.c | 2 +- drivers/i2c/busses/i2c-bfin-twi.c | 2 +- drivers/i2c/busses/i2c-highlander.c | 2 +- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- drivers/i2c/busses/i2c-ocores.c | 8 ++++---- drivers/i2c/busses/i2c-omap.c | 2 +- drivers/i2c/busses/i2c-pca-platform.c | 10 ++++------ drivers/i2c/busses/i2c-pmcmsp.c | 8 ++++---- drivers/i2c/busses/i2c-pxa.c | 9 ++++----- drivers/i2c/busses/i2c-versatile.c | 6 +++--- 11 files changed, 28 insertions(+), 31 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 67d9dc5b351..06e1ecb4919 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -200,10 +200,10 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev) if (!res) return -ENXIO; - if (!request_mem_region(res->start, res->end - res->start + 1, "at91_i2c")) + if (!request_mem_region(res->start, resource_size(res), "at91_i2c")) return -EBUSY; - twi_base = ioremap(res->start, res->end - res->start + 1); + twi_base = ioremap(res->start, resource_size(res)); if (!twi_base) { rc = -ENOMEM; goto fail0; @@ -252,7 +252,7 @@ fail2: fail1: iounmap(twi_base); fail0: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return rc; } @@ -268,7 +268,7 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(twi_base); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(twi_clk); /* disable peripheral clock */ clk_put(twi_clk); diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index f78ce523e3d..532828bc50e 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -389,7 +389,7 @@ i2c_au1550_probe(struct platform_device *pdev) goto out; } - priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, + priv->ioarea = request_mem_region(r->start, resource_size(r), pdev->name); if (!priv->ioarea) { ret = -EBUSY; diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 9fb114c274a..b309ac2c3d5 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -652,7 +652,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) goto out_error_get_res; } - iface->regs_base = ioremap(res->start, res->end - res->start + 1); + iface->regs_base = ioremap(res->start, resource_size(res)); if (iface->regs_base == NULL) { dev_err(&pdev->dev, "Cannot map IO\n"); rc = -ENXIO; diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index e5a8dae4a28..87ecace415d 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -373,7 +373,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev) if (unlikely(!dev)) return -ENOMEM; - dev->base = ioremap_nocache(res->start, res->end - res->start + 1); + dev->base = ioremap_nocache(res->start, resource_size(res)); if (unlikely(!dev->base)) { ret = -ENXIO; goto err; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 5a4945d1dba..c3869d94ad4 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -469,7 +469,7 @@ mv64xxx_i2c_map_regs(struct platform_device *pd, if (!r) return -ENODEV; - size = r->end - r->start + 1; + size = resource_size(r); if (!request_mem_region(r->start, size, drv_data->adapter.name)) return -EBUSY; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 3542c6ba98f..0dabe643ec5 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -234,14 +234,14 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Memory region busy\n"); ret = -EBUSY; goto request_mem_failed; } - i2c->base = ioremap(res->start, res->end - res->start + 1); + i2c->base = ioremap(res->start, resource_size(res)); if (!i2c->base) { dev_err(&pdev->dev, "Unable to map registers\n"); ret = -EIO; @@ -283,7 +283,7 @@ add_adapter_failed: request_irq_failed: iounmap(i2c->base); map_failed: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); request_mem_failed: kfree(i2c); @@ -311,7 +311,7 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); kfree(i2c); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c73475dd0fb..b606db85525 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -828,7 +828,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->idle = 1; dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, mem->end - mem->start + 1); + dev->base = ioremap(mem->start, resource_size(mem)); if (!dev->base) { r = -ENOMEM; goto err_free_mem; diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 7b23891b7d5..c4df9d411cd 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -27,8 +27,6 @@ #include #include -#define res_len(r) ((r)->end - (r)->start + 1) - struct i2c_pca_pf_data { void __iomem *reg_base; int irq; /* if 0, use polling */ @@ -148,7 +146,7 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) goto e_print; } - if (!request_mem_region(res->start, res_len(res), res->name)) { + if (!request_mem_region(res->start, resource_size(res), res->name)) { ret = -ENOMEM; goto e_print; } @@ -161,13 +159,13 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) init_waitqueue_head(&i2c->wait); - i2c->reg_base = ioremap(res->start, res_len(res)); + i2c->reg_base = ioremap(res->start, resource_size(res)); if (!i2c->reg_base) { ret = -ENOMEM; goto e_remap; } i2c->io_base = res->start; - i2c->io_size = res_len(res); + i2c->io_size = resource_size(res); i2c->irq = irq; i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; @@ -250,7 +248,7 @@ e_reqirq: e_remap: kfree(i2c); e_alloc: - release_mem_region(res->start, res_len(res)); + release_mem_region(res->start, resource_size(res)); e_print: printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret); return ret; diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 0bdb2d7f057..7b57d5f267e 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -283,7 +283,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) } /* reserve the memory region */ - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), pldev->name)) { dev_err(&pldev->dev, "Unable to get memory/io address region 0x%08x\n", @@ -294,7 +294,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) /* remap the memory */ pmcmsptwi_data.iobase = ioremap_nocache(res->start, - res->end - res->start + 1); + resource_size(res)); if (!pmcmsptwi_data.iobase) { dev_err(&pldev->dev, "Unable to ioremap address 0x%08x\n", res->start); @@ -360,7 +360,7 @@ ret_unmap: iounmap(pmcmsptwi_data.iobase); ret_unreserve: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); ret_err: return rc; @@ -385,7 +385,7 @@ static int __devexit pmcmsptwi_remove(struct platform_device *pldev) iounmap(pmcmsptwi_data.iobase); res = platform_get_resource(pldev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return 0; } diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 035a6c7e59d..762e1e53088 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -993,7 +993,6 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -#define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { struct pxa_i2c *i2c; @@ -1008,7 +1007,7 @@ static int i2c_pxa_probe(struct platform_device *dev) if (res == NULL || irq < 0) return -ENODEV; - if (!request_mem_region(res->start, res_len(res), res->name)) + if (!request_mem_region(res->start, resource_size(res), res->name)) return -ENOMEM; i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL); @@ -1038,7 +1037,7 @@ static int i2c_pxa_probe(struct platform_device *dev) goto eclk; } - i2c->reg_base = ioremap(res->start, res_len(res)); + i2c->reg_base = ioremap(res->start, resource_size(res)); if (!i2c->reg_base) { ret = -EIO; goto eremap; @@ -1046,7 +1045,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->reg_shift = REG_SHIFT(id->driver_data); i2c->iobase = res->start; - i2c->iosize = res_len(res); + i2c->iosize = resource_size(res); i2c->irq = irq; @@ -1110,7 +1109,7 @@ eremap: eclk: kfree(i2c); emalloc: - release_mem_region(res->start, res_len(res)); + release_mem_region(res->start, resource_size(res)); return ret; } diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index fede619ba22..70de8216346 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -76,7 +76,7 @@ static int i2c_versatile_probe(struct platform_device *dev) goto err_out; } - if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) { + if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) { ret = -EBUSY; goto err_out; } @@ -87,7 +87,7 @@ static int i2c_versatile_probe(struct platform_device *dev) goto err_release; } - i2c->base = ioremap(r->start, r->end - r->start + 1); + i2c->base = ioremap(r->start, resource_size(r)); if (!i2c->base) { ret = -ENOMEM; goto err_free; @@ -118,7 +118,7 @@ static int i2c_versatile_probe(struct platform_device *dev) err_free: kfree(i2c); err_release: - release_mem_region(r->start, r->end - r->start + 1); + release_mem_region(r->start, resource_size(r)); err_out: return ret; } -- cgit v1.2.3-70-g09d2 From 933a2aec8d08cda11c4b427ea7930b0e92eb9bc8 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 14 Jun 2009 14:04:20 +0100 Subject: i2c-s3c2410: use resource_size() Change the usage of res->end-res->start to resource_size(), missed by the last patch to change this. Signed-off-by: Ben Dooks --- 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 079a312d36f..8f42a4536cd 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -828,7 +828,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_clk; } - i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, + i2c->ioarea = request_mem_region(res->start, resource_size(res), pdev->name); if (i2c->ioarea == NULL) { @@ -837,7 +837,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_clk; } - i2c->regs = ioremap(res->start, (res->end-res->start)+1); + i2c->regs = ioremap(res->start, resource_size(res)); if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); -- cgit v1.2.3-70-g09d2 From 4eaad8ad296a78689f148c8dcd383fc4e51ee123 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 15 Jun 2009 00:30:18 +0200 Subject: i2c-stu300: Make driver depend on MACH_U300 This makes the stu300 driver for the ST Micro ST DDC I2C bus driver depend on MACH_U300, new platforms reusing this I2C driver will need to add in a similar dependency. Signed-off-by: Linus Walleij [ben-linux@fluff.org: re-aranged subject line] Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0e0a3904083..3c259ee7ddd 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -515,6 +515,7 @@ config I2C_SIMTEC config I2C_STU300 tristate "ST Microelectronics DDC I2C interface" + depends on MACH_U300 default y if MACH_U300 help If you say yes to this option, support will be included for the -- cgit v1.2.3-70-g09d2 From 87c441e54dfcf9f45593ecaf68e7e18ea53d5e13 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 17 Jun 2009 00:30:22 -0600 Subject: powerpc/5xxx: Add common mpc5xxx_get_bus_frequency() function So far, MPC512x used mpc512x_find_ips_freq() to get the bus frequency, while MPC52xx used mpc52xx_find_ipb_freq(). Despite the different clock names (IPS vs. IPB) the code was identical. Use common code for both processor families. Signed-off-by: Wolfgang Denk Signed-off-by: Grant Likely --- arch/powerpc/include/asm/mpc512x.h | 22 ------------------- arch/powerpc/include/asm/mpc52xx.h | 2 +- arch/powerpc/include/asm/mpc5xxx.h | 22 +++++++++++++++++++ arch/powerpc/platforms/512x/clock.c | 2 +- arch/powerpc/platforms/512x/mpc512x.h | 1 - arch/powerpc/platforms/512x/mpc512x_shared.c | 23 ------------------- arch/powerpc/platforms/52xx/mpc52xx_common.c | 32 +-------------------------- arch/powerpc/sysdev/Makefile | 3 +++ arch/powerpc/sysdev/mpc5xxx_clocks.c | 33 ++++++++++++++++++++++++++++ drivers/ata/pata_mpc52xx.c | 2 +- drivers/i2c/busses/i2c-mpc.c | 2 +- drivers/net/fec_mpc52xx.c | 2 +- drivers/net/fec_mpc52xx_phy.c | 2 +- drivers/serial/mpc52xx_uart.c | 5 ++--- drivers/watchdog/mpc5200_wdt.c | 2 +- 15 files changed, 68 insertions(+), 87 deletions(-) delete mode 100644 arch/powerpc/include/asm/mpc512x.h create mode 100644 arch/powerpc/include/asm/mpc5xxx.h create mode 100644 arch/powerpc/sysdev/mpc5xxx_clocks.c (limited to 'drivers/i2c') diff --git a/arch/powerpc/include/asm/mpc512x.h b/arch/powerpc/include/asm/mpc512x.h deleted file mode 100644 index c48a1658eea..00000000000 --- a/arch/powerpc/include/asm/mpc512x.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: John Rigby, , Friday Apr 13 2007 - * - * Description: - * MPC5121 Prototypes and definitions - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#ifndef __ASM_POWERPC_MPC512x_H__ -#define __ASM_POWERPC_MPC512x_H__ - -extern unsigned long mpc512x_find_ips_freq(struct device_node *node); - -#endif /* __ASM_POWERPC_MPC512x_H__ */ - diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h index 52e049cd9e6..1b4f697abbd 100644 --- a/arch/powerpc/include/asm/mpc52xx.h +++ b/arch/powerpc/include/asm/mpc52xx.h @@ -16,6 +16,7 @@ #ifndef __ASSEMBLY__ #include #include +#include #endif /* __ASSEMBLY__ */ #include @@ -268,7 +269,6 @@ struct mpc52xx_intr { #ifndef __ASSEMBLY__ /* mpc52xx_common.c */ -extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node); extern void mpc5200_setup_xlb_arbiter(void); extern void mpc52xx_declare_of_platform_devices(void); extern void mpc52xx_map_common_devices(void); diff --git a/arch/powerpc/include/asm/mpc5xxx.h b/arch/powerpc/include/asm/mpc5xxx.h new file mode 100644 index 00000000000..5ce9c5fa434 --- /dev/null +++ b/arch/powerpc/include/asm/mpc5xxx.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby, , Friday Apr 13 2007 + * + * Description: + * MPC5xxx Prototypes and definitions + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_POWERPC_MPC5xxx_H__ +#define __ASM_POWERPC_MPC5xxx_H__ + +extern unsigned long mpc5xxx_get_bus_frequency(struct device_node *node); + +#endif /* __ASM_POWERPC_MPC5xxx_H__ */ + diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c index 1bcff94eb92..f4c4c6f807d 100644 --- a/arch/powerpc/platforms/512x/clock.c +++ b/arch/powerpc/platforms/512x/clock.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #undef CLK_DEBUG diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h index 9c03693cb00..22a5352407e 100644 --- a/arch/powerpc/platforms/512x/mpc512x.h +++ b/arch/powerpc/platforms/512x/mpc512x.h @@ -11,7 +11,6 @@ #ifndef __MPC512X_H__ #define __MPC512X_H__ -extern unsigned long mpc512x_find_ips_freq(struct device_node *node); extern void __init mpc512x_init_IRQ(void); void __init mpc512x_declare_of_platform_devices(void); #endif /* __MPC512X_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index d8cd579f319..434d683df5a 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -24,29 +24,6 @@ #include "mpc512x.h" -unsigned long -mpc512x_find_ips_freq(struct device_node *node) -{ - struct device_node *np; - const unsigned int *p_ips_freq = NULL; - - of_node_get(node); - while (node) { - p_ips_freq = of_get_property(node, "bus-frequency", NULL); - if (p_ips_freq) - break; - - np = of_get_parent(node); - of_node_put(node); - node = np; - } - if (node) - of_node_put(node); - - return p_ips_freq ? *p_ips_freq : 0; -} -EXPORT_SYMBOL(mpc512x_find_ips_freq); - void __init mpc512x_init_IRQ(void) { struct device_node *np; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 8e3dd5a0f22..a46bad0c233 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -47,36 +47,6 @@ static DEFINE_SPINLOCK(mpc52xx_lock); static struct mpc52xx_gpt __iomem *mpc52xx_wdt; static struct mpc52xx_cdm __iomem *mpc52xx_cdm; -/** - * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device - * @node: device node - * - * Returns IPB bus frequency, or 0 if the bus frequency cannot be found. - */ -unsigned int -mpc52xx_find_ipb_freq(struct device_node *node) -{ - struct device_node *np; - const unsigned int *p_ipb_freq = NULL; - - of_node_get(node); - while (node) { - p_ipb_freq = of_get_property(node, "bus-frequency", NULL); - if (p_ipb_freq) - break; - - np = of_get_parent(node); - of_node_put(node); - node = np; - } - if (node) - of_node_put(node); - - return p_ipb_freq ? *p_ipb_freq : 0; -} -EXPORT_SYMBOL(mpc52xx_find_ipb_freq); - - /* * Configure the XLB arbiter settings to match what Linux expects. */ @@ -221,7 +191,7 @@ unsigned int mpc52xx_get_xtal_freq(struct device_node *node) if (!mpc52xx_cdm) return 0; - freq = mpc52xx_find_ipb_freq(node); + freq = mpc5xxx_get_bus_frequency(node); if (!freq) return 0; diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index d073bfdd222..9d4b17462f1 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -50,6 +50,9 @@ obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o +obj-$(CONFIG_PPC_MPC512x) += mpc5xxx_clocks.o +obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o + ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o endif diff --git a/arch/powerpc/sysdev/mpc5xxx_clocks.c b/arch/powerpc/sysdev/mpc5xxx_clocks.c new file mode 100644 index 00000000000..34e12f9995f --- /dev/null +++ b/arch/powerpc/sysdev/mpc5xxx_clocks.c @@ -0,0 +1,33 @@ +/** + * mpc5xxx_get_bus_frequency - Find the bus frequency for a device + * @node: device node + * + * Returns bus frequency (IPS on MPC512x, IPB on MPC52xx), + * or 0 if the bus frequency cannot be found. + */ + +#include +#include + +unsigned int +mpc5xxx_get_bus_frequency(struct device_node *node) +{ + struct device_node *np; + const unsigned int *p_bus_freq = NULL; + + of_node_get(node); + while (node) { + p_bus_freq = of_get_property(node, "bus-frequency", NULL); + if (p_bus_freq) + break; + + np = of_get_parent(node); + of_node_put(node); + node = np; + } + if (node) + of_node_put(node); + + return p_bus_freq ? *p_bus_freq : 0; +} +EXPORT_SYMBOL(mpc5xxx_get_bus_frequency); diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 68d27bc70d0..2bc2dbe30e8 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -694,7 +694,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) struct bcom_task *dmatsk = NULL; /* Get ipb frequency */ - ipb_freq = mpc52xx_find_ipb_freq(op->node); + ipb_freq = mpc5xxx_get_bus_frequency(op->node); if (!ipb_freq) { dev_err(&op->dev, "could not determine IPB bus frequency\n"); return -ENODEV; diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index dd778d7ae04..d325e86e310 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -197,7 +197,7 @@ int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler) return -EINVAL; /* Determine divider value */ - divider = mpc52xx_find_ipb_freq(node) / clock; + divider = mpc5xxx_get_bus_frequency(node) / clock; /* * We want to choose an FDR/DFSR that generates an I2C bus speed that diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 8bbe7f61799..5ddf03325d1 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -1006,7 +1006,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) priv->phy_addr = FEC5200_PHYADDR_NONE; priv->speed = 100; priv->duplex = DUPLEX_HALF; - priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; + priv->phy_speed = ((mpc5xxx_get_bus_frequency(op->node) >> 20) / 5) << 1; /* the 7-wire property means don't use MII mode */ if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index dd9bfa42ac3..176e9b8d710 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -120,7 +120,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, /* set MII speed */ out_be32(&priv->regs->mii_speed, - ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1); + ((mpc5xxx_get_bus_frequency(of->node) >> 20) / 5) << 1); err = mdiobus_register(bus); if (err) diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index b3feb6198d5..abbd146c50d 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -76,7 +76,6 @@ #include #include -#include #include #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -254,7 +253,7 @@ static unsigned long mpc52xx_getuartclk(void *p) * but the generic serial code assumes 16 * so return ipb freq / 2 */ - return mpc52xx_find_ipb_freq(p) / 2; + return mpc5xxx_get_bus_frequency(p) / 2; } static struct psc_ops mpc52xx_psc_ops = { @@ -391,7 +390,7 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port) static unsigned long mpc512x_getuartclk(void *p) { - return mpc512x_find_ips_freq(p); + return mpc5xxx_get_bus_frequency(p); } static struct psc_ops mpc512x_psc_ops = { diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c index 465fe36adad..fa9c47ce0ae 100644 --- a/drivers/watchdog/mpc5200_wdt.c +++ b/drivers/watchdog/mpc5200_wdt.c @@ -188,7 +188,7 @@ static int mpc5200_wdt_probe(struct of_device *op, if (!wdt) return -ENOMEM; - wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node); + wdt->ipb_freq = mpc5xxx_get_bus_frequency(op->node); err = of_address_to_resource(op->node, 0, &wdt->mem); if (err) -- cgit v1.2.3-70-g09d2 From 352da9820e5506e3b8496e6052a2ad9c488efae8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:17 +0200 Subject: i2c: Kill client_register and client_unregister methods These methods were useful in the legacy binding model but no longer in the new (standard) binding model. There are no users left so we can drop them. Signed-off-by: Jean Delvare Cc: David Brownell --- Documentation/feature-removal-schedule.txt | 3 +-- drivers/i2c/i2c-core.c | 30 +----------------------------- include/linux/i2c.h | 4 ---- 3 files changed, 2 insertions(+), 35 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 8d07ed31207..9163dade070 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -368,8 +368,7 @@ Who: Krzysztof Piotr Oledzki --------------------------- -What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client(), - i2c_adapter->client_register(), i2c_adapter->client_unregister +What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client() When: 2.6.30 Check: i2c_attach_client i2c_detach_client Why: Deprecated by the new (standard) device driver binding model. Use diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5ed622ee65c..fc18fdbffd3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -308,14 +308,6 @@ void i2c_unregister_device(struct i2c_client *client) return; } - if (adapter->client_unregister) { - if (adapter->client_unregister(client)) { - dev_warn(&client->dev, - "client_unregister [%s] failed\n", - client->name); - } - } - mutex_lock(&adapter->clist_lock); list_del(&client->list); mutex_unlock(&adapter->clist_lock); @@ -855,14 +847,6 @@ int i2c_attach_client(struct i2c_client *client) dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); - if (adapter->client_register) { - if (adapter->client_register(client)) { - dev_dbg(&adapter->dev, "client_register " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } - } - return 0; out_err: @@ -875,17 +859,6 @@ EXPORT_SYMBOL(i2c_attach_client); int i2c_detach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - int res = 0; - - if (adapter->client_unregister) { - res = adapter->client_unregister(client); - if (res) { - dev_err(&client->dev, - "client_unregister [%s] failed, " - "client not detached\n", client->name); - goto out; - } - } mutex_lock(&adapter->clist_lock); list_del(&client->list); @@ -895,8 +868,7 @@ int i2c_detach_client(struct i2c_client *client) device_unregister(&client->dev); wait_for_completion(&client->released); - out: - return res; + return 0; } EXPORT_SYMBOL(i2c_detach_client); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ad258059603..b3f4606afa0 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -352,10 +352,6 @@ struct i2c_adapter { const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data; - /* --- administration stuff. */ - int (*client_register)(struct i2c_client *) __deprecated; - int (*client_unregister)(struct i2c_client *) __deprecated; - /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; -- cgit v1.2.3-70-g09d2 From 729d6dd571464954f625e6b80950d9e4e3bd94f7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:18 +0200 Subject: i2c: Get rid of the legacy binding model We converted all the legacy i2c drivers so we can finally get rid of the legacy binding model. Hooray! Signed-off-by: Jean Delvare Cc: David Brownell --- Documentation/feature-removal-schedule.txt | 9 ---- Documentation/i2c/writing-clients | 16 ++---- drivers/i2c/i2c-core.c | 83 +++--------------------------- include/linux/i2c.h | 39 ++++---------- 4 files changed, 20 insertions(+), 127 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 9163dade070..f8cd450be9a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -368,15 +368,6 @@ Who: Krzysztof Piotr Oledzki --------------------------- -What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client() -When: 2.6.30 -Check: i2c_attach_client i2c_detach_client -Why: Deprecated by the new (standard) device driver binding model. Use - i2c_driver->probe() and ->remove() instead. -Who: Jean Delvare - ---------------------------- - What: fscher and fscpos drivers When: June 2009 Why: Deprecated by the new fschmd driver. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index c1a06f989cf..7860aafb483 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -126,19 +126,9 @@ different) configuration information, as do drivers handling chip variants that can't be distinguished by protocol probing, or which need some board specific information to operate correctly. -Accordingly, the I2C stack now has two models for associating I2C devices -with their drivers: the original "legacy" model, and a newer one that's -fully compatible with the Linux 2.6 driver model. These models do not mix, -since the "legacy" model requires drivers to create "i2c_client" device -objects after SMBus style probing, while the Linux driver model expects -drivers to be given such device objects in their probe() routines. -The legacy model is deprecated now and will soon be removed, so we no -longer document it here. - - -Standard Driver Model Binding ("New Style") -------------------------------------------- +Device/Driver Binding +--------------------- System infrastructure, typically board-specific initialization code or boot firmware, reports what I2C devices exist. For example, there may be @@ -201,7 +191,7 @@ a given I2C bus. This is for example the case of hardware monitoring devices on a PC's SMBus. In that case, you may want to let your driver detect supported devices automatically. This is how the legacy model was working, and is now available as an extension to the standard -driver model (so that we can finally get rid of the legacy model.) +driver model. You simply have to define a detect callback which will attempt to identify supported devices (returning 0 for supported ones and -ENODEV diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index fc18fdbffd3..dc8bc913144 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -43,6 +43,7 @@ static DEFINE_IDR(i2c_adapter_idr); #define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) +static int i2c_attach_client(struct i2c_client *client); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -83,10 +84,6 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - /* by definition, legacy drivers can't hotplug */ - if (dev->driver) - return 0; - if (add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, client->name)) return -ENOMEM; @@ -455,7 +452,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* create pre-declared device nodes for new-style drivers */ + /* create pre-declared device nodes */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -617,26 +614,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) if (res) goto out_unlock; - /* detach any active clients. This must be done first, because - * it can fail; in which case we give up. */ + /* Detach any active clients */ list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) { - struct i2c_driver *driver; - - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; - } + i2c_unregister_device(client); } /* clean up the sysfs representation */ @@ -680,11 +660,7 @@ static int __attach_adapter(struct device *dev, void *data) /* * An i2c_driver is used with one or more i2c_client (device) nodes to access - * i2c slave chips, on a bus instance associated with some i2c_adapter. There - * are two models for binding the driver to its device: "new style" drivers - * follow the standard Linux driver model and just respond to probe() calls - * issued if the driver core sees they match(); "legacy" drivers create device - * nodes themselves. + * i2c slave chips, on a bus instance associated with some i2c_adapter. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) @@ -695,21 +671,11 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (unlikely(WARN_ON(!i2c_bus_type.p))) return -EAGAIN; - /* new style driver methods can't mix with legacy ones */ - if (is_newstyle_driver(driver)) { - if (driver->detach_adapter || driver->detach_client) { - printk(KERN_WARNING - "i2c-core: driver [%s] is confused\n", - driver->driver.name); - return -EINVAL; - } - } - /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; - /* for new style drivers, when registration returns the driver core + /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); @@ -748,29 +714,11 @@ static int __detach_adapter(struct device *dev, void *data) if (is_newstyle_driver(driver)) return 0; - /* Have a look at each adapter, if clients of this driver are still - * attached. If so, detach them to be able to kill the driver - * afterwards. - */ if (driver->detach_adapter) { if (driver->detach_adapter(adapter)) dev_err(&adapter->dev, "detach_adapter failed for driver [%s]\n", driver->driver.name); - } else { - struct i2c_client *client, *_n; - - list_for_each_entry_safe(client, _n, &adapter->clients, list) { - if (client->driver != driver) - continue; - dev_dbg(&adapter->dev, - "detaching client [%s] at 0x%02x\n", - client->name, client->addr); - if (driver->detach_client(client)) - dev_err(&adapter->dev, "detach_client " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } } return 0; @@ -812,7 +760,7 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } -int i2c_attach_client(struct i2c_client *client) +static int i2c_attach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; int res; @@ -854,23 +802,6 @@ out_err: "(%d)\n", client->name, client->addr, res); return res; } -EXPORT_SYMBOL(i2c_attach_client); - -int i2c_detach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - - init_completion(&client->released); - device_unregister(&client->dev); - wait_for_completion(&client->released); - - return 0; -} -EXPORT_SYMBOL(i2c_detach_client); /** * i2c_use_client - increments the reference count of the i2c client structure diff --git a/include/linux/i2c.h b/include/linux/i2c.h index b3f4606afa0..43a3545670b 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -100,9 +100,8 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, * @class: What kind of i2c device we instantiate (for detect) * @attach_adapter: Callback for bus addition (for legacy drivers) * @detach_adapter: Callback for bus removal (for legacy drivers) - * @detach_client: Callback for device removal (for legacy drivers) - * @probe: Callback for device binding (new-style drivers) - * @remove: Callback for device unbinding (new-style drivers) + * @probe: Callback for device binding + * @remove: Callback for device unbinding * @shutdown: Callback for device shutdown * @suspend: Callback for device suspend * @resume: Callback for device resume @@ -137,26 +136,14 @@ struct i2c_driver { int id; unsigned int class; - /* Notifies the driver that a new bus has appeared. This routine - * can be used by the driver to test if the bus meets its conditions - * & seek for the presence of the chip(s) it supports. If found, it - * registers the client(s) that are on the bus to the i2c admin. via - * i2c_attach_client. (LEGACY I2C DRIVERS ONLY) + /* Notifies the driver that a new bus has appeared or is about to be + * removed. You should avoid using this if you can, it will probably + * be removed in a near future. */ int (*attach_adapter)(struct i2c_adapter *); int (*detach_adapter)(struct i2c_adapter *); - /* tells the driver that a client is about to be deleted & gives it - * the chance to remove its private data. Also, if the client struct - * has been dynamically allocated by the driver in the function above, - * it must be freed here. (LEGACY I2C DRIVERS ONLY) - */ - int (*detach_client)(struct i2c_client *) __deprecated; - - /* Standard driver model interfaces, for "new style" i2c drivers. - * With the driver model, device enumeration is NEVER done by drivers; - * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) - */ + /* Standard driver model interfaces */ int (*probe)(struct i2c_client *, const struct i2c_device_id *); int (*remove)(struct i2c_client *); @@ -248,11 +235,10 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) * that, such as chip type, configuration, associated IRQ, and so on. * * i2c_board_info is used to build tables of information listing I2C devices - * that are present. This information is used to grow the driver model tree - * for "new style" I2C drivers. For mainboards this is done statically using - * i2c_register_board_info(); bus numbers identify adapters that aren't - * yet available. For add-on boards, i2c_new_device() does this dynamically - * with the adapter already known. + * that are present. This information is used to grow the driver model tree. + * For mainboards this is done statically using i2c_register_board_info(); + * bus numbers identify adapters that aren't yet available. For add-on boards, + * i2c_new_device() does this dynamically with the adapter already known. */ struct i2c_board_info { char type[I2C_NAME_SIZE]; @@ -425,11 +411,6 @@ static inline int i2c_add_driver(struct i2c_driver *driver) return i2c_register_driver(THIS_MODULE, driver); } -/* These are deprecated, your driver should use the standard .probe() - * and .remove() methods instead. */ -extern int __deprecated i2c_attach_client(struct i2c_client *); -extern int __deprecated i2c_detach_client(struct i2c_client *); - extern struct i2c_client *i2c_use_client(struct i2c_client *client); extern void i2c_release_client(struct i2c_client *client); -- cgit v1.2.3-70-g09d2 From 36789b5ea52bba961122b45f4383f553ec3b5a6c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:18 +0200 Subject: i2c: Drop i2c_probe function The legacy i2c_probe() function has no users left, get rid of it. Signed-off-by: Jean Delvare Cc: David Brownell --- drivers/i2c/i2c-core.c | 137 ------------------------------------------------- include/linux/i2c.h | 8 --- 2 files changed, 145 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dc8bc913144..d48438908e1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1032,144 +1032,7 @@ EXPORT_SYMBOL(i2c_master_recv); * Will not work for 10-bit addresses! * ---------------------------------------------------- */ -static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int err; - - /* Make sure the address is valid */ - if (addr < 0x03 || addr > 0x77) { - dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", - addr); - return -EINVAL; - } - - /* Skip if already in use */ - if (i2c_check_addr(adapter, addr)) - return 0; - - /* Make sure there is something at this address, unless forced */ - if (kind < 0) { - if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; - - /* prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - } - - /* Finally call the custom detection function */ - err = found_proc(adapter, addr, kind); - /* -ENODEV can be returned if there is a chip at the given address - but it isn't supported by this chip driver. We catch it here as - this isn't an error. */ - if (err == -ENODEV) - err = 0; - - if (err) - dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n", - addr, err); - return err; -} - -int i2c_probe(struct i2c_adapter *adapter, - const struct i2c_client_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int i, err; - int adap_id = i2c_adapter_id(adapter); - - /* Force entries are done first, and are not affected by ignore - entries */ - if (address_data->forces) { - const unsigned short * const *forces = address_data->forces; - int kind; - - for (kind = 0; forces[kind]; kind++) { - for (i = 0; forces[kind][i] != I2C_CLIENT_END; - i += 2) { - if (forces[kind][i] == adap_id - || forces[kind][i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found force " - "parameter for adapter %d, " - "addr 0x%02x, kind %d\n", - adap_id, forces[kind][i + 1], - kind); - err = i2c_probe_address(adapter, - forces[kind][i + 1], - kind, found_proc); - if (err) - return err; - } - } - } - } - - /* Stop here if we can't use SMBUS_QUICK */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { - if (address_data->probe[0] == I2C_CLIENT_END - && address_data->normal_i2c[0] == I2C_CLIENT_END) - return 0; - - dev_dbg(&adapter->dev, "SMBus Quick command not supported, " - "can't probe for chips\n"); - return -EOPNOTSUPP; - } - - /* Probe entries are done second, and are not affected by ignore - entries either */ - for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { - if (address_data->probe[i] == adap_id - || address_data->probe[i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found probe parameter for " - "adapter %d, addr 0x%02x\n", adap_id, - address_data->probe[i + 1]); - err = i2c_probe_address(adapter, - address_data->probe[i + 1], - -1, found_proc); - if (err) - return err; - } - } - - /* Normal entries are done last, unless shadowed by an ignore entry */ - for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { - int j, ignore; - - ignore = 0; - for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; - j += 2) { - if ((address_data->ignore[j] == adap_id || - address_data->ignore[j] == ANY_I2C_BUS) - && address_data->ignore[j + 1] - == address_data->normal_i2c[i]) { - dev_dbg(&adapter->dev, "found ignore " - "parameter for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->ignore[j + 1]); - ignore = 1; - break; - } - } - if (ignore) - continue; - - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->normal_i2c[i]); - err = i2c_probe_address(adapter, address_data->normal_i2c[i], - -1, found_proc); - if (err) - return err; - } - - return 0; -} -EXPORT_SYMBOL(i2c_probe); -/* Separate detection function for new-style drivers */ static int i2c_detect_address(struct i2c_client *temp_client, int kind, struct i2c_driver *driver) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 43a3545670b..db25a870843 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -419,14 +419,6 @@ extern void i2c_release_client(struct i2c_client *client); extern void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg); -/* Detect function. It iterates over all possible addresses itself. - * It will only call found_proc if some client is connected at the - * specific address (unless a 'force' matched); - */ -extern int i2c_probe(struct i2c_adapter *adapter, - const struct i2c_client_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)); - extern struct i2c_adapter *i2c_get_adapter(int id); extern void i2c_put_adapter(struct i2c_adapter *adap); -- cgit v1.2.3-70-g09d2 From f8a227e8ac19c2d3e189833b8518b1805d9b443c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:18 +0200 Subject: i2c: Merge i2c_attach_client into i2c_new_device Now that i2c_attach_client is no longer exported, it doesn't need to be a separate function. Merge it into its only user, i2c_new_device. Signed-off-by: Jean Delvare Cc: David Brownell --- drivers/i2c/i2c-core.c | 100 ++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 59 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d48438908e1..06c428b5822 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -43,7 +43,7 @@ static DEFINE_IDR(i2c_adapter_idr); #define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) -static int i2c_attach_client(struct i2c_client *client); +static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -237,15 +237,17 @@ EXPORT_SYMBOL(i2c_verify_client); /** - * i2c_new_device - instantiate an i2c device for use with a new style driver + * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * - * Create a device to work with a new style i2c driver, where binding is - * handled through driver model probe()/remove() methods. This call is not - * appropriate for use by mainboad initialization logic, which usually runs - * during an arch_initcall() long before any i2c_adapter could exist. + * Create an i2c device. Binding is handled through driver model + * probe()/remove() methods. A driver may be bound to this device when we + * return from this function, or any later moment (e.g. maybe hotplugging will + * load the driver module). This call is not appropriate for use by mainboard + * initialization logic, which usually runs during an arch_initcall() long + * before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. @@ -273,17 +275,40 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); - /* a new style driver may be bound to this device when we - * return from this function, or any later moment (e.g. maybe - * hotplugging will load the driver module). and the device - * refcount model is the standard driver model one. - */ - status = i2c_attach_client(client); - if (status < 0) { - kfree(client); - client = NULL; - } + /* Check for address business */ + status = i2c_check_addr(adap, client->addr); + if (status) + goto out_err; + + client->dev.parent = &client->adapter->dev; + client->dev.bus = &i2c_bus_type; + + if (client->driver && !is_newstyle_driver(client->driver)) { + client->dev.release = i2c_client_release; + dev_set_uevent_suppress(&client->dev, 1); + } else + client->dev.release = i2c_client_dev_release; + + dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), + client->addr); + status = device_register(&client->dev); + if (status) + goto out_err; + + mutex_lock(&adap->clist_lock); + list_add_tail(&client->list, &adap->clients); + mutex_unlock(&adap->clist_lock); + + dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", + client->name, dev_name(&client->dev)); + return client; + +out_err: + dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " + "(%d)\n", client->name, client->addr, status); + kfree(client); + return NULL; } EXPORT_SYMBOL_GPL(i2c_new_device); @@ -760,49 +785,6 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } -static int i2c_attach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - int res; - - /* Check for address business */ - res = i2c_check_addr(adapter, client->addr); - if (res) - return res; - - client->dev.parent = &client->adapter->dev; - client->dev.bus = &i2c_bus_type; - - if (client->driver) - client->dev.driver = &client->driver->driver; - - if (client->driver && !is_newstyle_driver(client->driver)) { - client->dev.release = i2c_client_release; - dev_set_uevent_suppress(&client->dev, 1); - } else - client->dev.release = i2c_client_dev_release; - - dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter), - client->addr); - res = device_register(&client->dev); - if (res) - goto out_err; - - mutex_lock(&adapter->clist_lock); - list_add_tail(&client->list, &adapter->clients); - mutex_unlock(&adapter->clist_lock); - - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, dev_name(&client->dev)); - - return 0; - -out_err: - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); - return res; -} - /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced -- cgit v1.2.3-70-g09d2 From 1e40ac12dab22d98d0178e87364cf4e36862809c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:19 +0200 Subject: i2c: Kill is_newstyle_driver Legacy i2c drivers are gone, all drivers are new-style now, so there is no point to check. Signed-off-by: Jean Delvare Cc: David Brownell --- drivers/i2c/i2c-core.c | 32 +------------------------------- include/linux/i2c.h | 2 -- 2 files changed, 1 insertion(+), 33 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 06c428b5822..95fb997b41e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -41,8 +41,6 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); -#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) - static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); @@ -64,12 +62,6 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(drv); - /* make legacy i2c drivers bypass driver model probing entirely; - * such drivers scan each i2c adapter/bus themselves. - */ - if (!is_newstyle_driver(driver)) - return 0; - /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; @@ -172,12 +164,6 @@ static int i2c_device_resume(struct device *dev) return driver->resume(to_i2c_client(dev)); } -static void i2c_client_release(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); -} - static void i2c_client_dev_release(struct device *dev) { kfree(to_i2c_client(dev)); @@ -282,12 +268,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; - - if (client->driver && !is_newstyle_driver(client->driver)) { - client->dev.release = i2c_client_release; - dev_set_uevent_suppress(&client->dev, 1); - } else - client->dev.release = i2c_client_dev_release; + client->dev.release = i2c_client_dev_release; dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr); @@ -321,14 +302,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); void i2c_unregister_device(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - struct i2c_driver *driver = client->driver; - - if (driver && !is_newstyle_driver(driver)) { - dev_err(&client->dev, "can't unregister devices " - "with legacy drivers\n"); - WARN_ON(1); - return; - } mutex_lock(&adapter->clist_lock); list_del(&client->list); @@ -736,9 +709,6 @@ static int __detach_adapter(struct device *dev, void *data) i2c_unregister_device(client); } - if (is_newstyle_driver(driver)) - return 0; - if (driver->detach_adapter) { if (driver->detach_adapter(adapter)) dev_err(&adapter->dev, diff --git a/include/linux/i2c.h b/include/linux/i2c.h index db25a870843..28b27282496 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -180,7 +180,6 @@ struct i2c_driver { * @irq: indicates the IRQ generated by this device (if any) * @list: list of active/busy clients (DEPRECATED) * @detected: member of an i2c_driver.clients list - * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an * i2c bus. The behaviour exposed to Linux is defined by the driver @@ -198,7 +197,6 @@ struct i2c_client { int irq; /* irq issued by device */ struct list_head list; /* DEPRECATED */ struct list_head detected; - struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) -- cgit v1.2.3-70-g09d2 From e549c2b54dd90a056d6824b885d438b7437874f0 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:19 +0200 Subject: i2c: Kill the redundant client list We used to maintain our own per-adapter list of i2c clients, but this is redundant with what the driver core does, and no longer needed. Just drop the redundant list. Signed-off-by: Jean Delvare Cc: David Brownell --- drivers/i2c/i2c-core.c | 28 +++++++++++----------------- include/linux/i2c.h | 4 ---- 2 files changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 95fb997b41e..b1fd00d9a5c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -276,10 +276,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) if (status) goto out_err; - mutex_lock(&adap->clist_lock); - list_add_tail(&client->list, &adap->clients); - mutex_unlock(&adap->clist_lock); - dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); @@ -301,12 +297,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -432,8 +422,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return -EAGAIN; mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); mutex_lock(&core_lock); @@ -583,6 +571,14 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) return res; } +static int __unregister_client(struct device *dev, void *dummy) +{ + struct i2c_client *client = i2c_verify_client(dev); + if (client) + i2c_unregister_device(client); + return 0; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -593,7 +589,6 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct i2c_client *client, *_n; int res = 0; mutex_lock(&core_lock); @@ -612,10 +607,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) if (res) goto out_unlock; - /* Detach any active clients */ - list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) { - i2c_unregister_device(client); - } + /* Detach any active clients. This can't fail, thus we do not + checking the returned value. */ + res = device_for_each_child(&adap->dev, NULL, __unregister_client); /* clean up the sysfs representation */ init_completion(&adap->dev_released); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 28b27282496..5f8157610c6 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -178,7 +178,6 @@ struct i2c_driver { * @driver: device's driver, hence pointer to access routines * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) - * @list: list of active/busy clients (DEPRECATED) * @detected: member of an i2c_driver.clients list * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -195,7 +194,6 @@ struct i2c_client { struct i2c_driver *driver; /* and our access routines */ struct device dev; /* the device structure */ int irq; /* irq issued by device */ - struct list_head list; /* DEPRECATED */ struct list_head detected; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -339,14 +337,12 @@ struct i2c_adapter { /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; - struct mutex clist_lock; int timeout; /* in jiffies */ int retries; struct device dev; /* the adapter device */ int nr; - struct list_head clients; /* DEPRECATED */ char name[48]; struct completion dev_released; }; -- cgit v1.2.3-70-g09d2 From 35fc37f8188177e3ba3e7f99a6e3300e490e9181 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:19 +0200 Subject: i2c: Limit core locking to the necessary sections The i2c-core code tends to hold the core lock for longer than it should. Limit locking to the necessary sections for both performance and clarity. This is also a requirement to support I2C multiplexers in the future. Signed-off-by: Jean Delvare Tested-by: Rodolfo Giometti Cc: David Brownell --- drivers/i2c/i2c-core.c | 51 +++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b1fd00d9a5c..a2f1cd3766f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -38,6 +38,9 @@ #include "i2c-core.h" +/* core_lock protects i2c_adapter_idr, and guarantees + that device detection, deletion of detected devices, and attach_adapter + and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); @@ -418,13 +421,13 @@ static int i2c_register_adapter(struct i2c_adapter *adap) int res = 0, dummy; /* Can't register until after driver model init */ - if (unlikely(WARN_ON(!i2c_bus_type.p))) - return -EAGAIN; + if (unlikely(WARN_ON(!i2c_bus_type.p))) { + res = -EAGAIN; + goto out_list; + } mutex_init(&adap->bus_lock); - mutex_lock(&core_lock); - /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; @@ -443,16 +446,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap) i2c_scan_static_board_info(adap); /* Notify drivers */ + mutex_lock(&core_lock); dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); - -out_unlock: mutex_unlock(&core_lock); - return res; + + return 0; out_list: + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); - goto out_unlock; + mutex_unlock(&core_lock); + return res; } /** @@ -590,22 +595,25 @@ static int __unregister_client(struct device *dev, void *dummy) int i2c_del_adapter(struct i2c_adapter *adap) { int res = 0; - - mutex_lock(&core_lock); + struct i2c_adapter *found; /* First make sure that this adapter was ever added */ - if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { + mutex_lock(&core_lock); + found = idr_find(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); + if (found != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); - res = -EINVAL; - goto out_unlock; + return -EINVAL; } /* Tell drivers about this removal */ + mutex_lock(&core_lock); res = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_del_adapter); + mutex_unlock(&core_lock); if (res) - goto out_unlock; + return res; /* Detach any active clients. This can't fail, thus we do not checking the returned value. */ @@ -619,7 +627,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) wait_for_completion(&adap->dev_released); /* free bus id */ + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -627,9 +637,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) added again */ memset(&adap->dev, 0, sizeof(adap->dev)); - out_unlock: - mutex_unlock(&core_lock); - return res; + return 0; } EXPORT_SYMBOL(i2c_del_adapter); @@ -674,16 +682,15 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - mutex_lock(&core_lock); - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ + mutex_lock(&core_lock); class_for_each_device(&i2c_adapter_class, NULL, driver, __attach_adapter); - mutex_unlock(&core_lock); + return 0; } EXPORT_SYMBOL(i2c_register_driver); @@ -721,14 +728,12 @@ static int __detach_adapter(struct device *dev, void *data) void i2c_del_driver(struct i2c_driver *driver) { mutex_lock(&core_lock); - class_for_each_device(&i2c_adapter_class, NULL, driver, __detach_adapter); + mutex_unlock(&core_lock); driver_unregister(&driver->driver); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - - mutex_unlock(&core_lock); } EXPORT_SYMBOL(i2c_del_driver); -- cgit v1.2.3-70-g09d2 From 99cd8e25875a109455b709b5a41d4891b8d8e58e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:20 +0200 Subject: i2c: Add a sysfs interface to instantiate devices Add a sysfs interface to instantiate and delete I2C devices. This is primarily a replacement of the force_* module parameters implemented by some i2c drivers. These module parameters were implemented internally by the I2C_CLIENT_INSMOD* macros, which don't scale well. This can also be used when developing a driver on a self-soldered board which doesn't yet have proper I2C device declaration at the platform level, and presumably for various debugging situations. Signed-off-by: Jean Delvare Cc: David Brownell --- Documentation/i2c/instantiating-devices | 44 ++++++++++++ drivers/i2c/i2c-core.c | 123 +++++++++++++++++++++++++++++++- include/linux/i2c.h | 3 +- 3 files changed, 168 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices index b55ce57a84d..c740b7b4108 100644 --- a/Documentation/i2c/instantiating-devices +++ b/Documentation/i2c/instantiating-devices @@ -165,3 +165,47 @@ was done there. Two significant differences are: Once again, method 3 should be avoided wherever possible. Explicit device instantiation (methods 1 and 2) is much preferred for it is safer and faster. + + +Method 4: Instantiate from user-space +------------------------------------- + +In general, the kernel should know which I2C devices are connected and +what addresses they live at. However, in certain cases, it does not, so a +sysfs interface was added to let the user provide the information. This +interface is made of 2 attribute files which are created in every I2C bus +directory: new_device and delete_device. Both files are write only and you +must write the right parameters to them in order to properly instantiate, +respectively delete, an I2C device. + +File new_device takes 2 parameters: the name of the I2C device (a string) +and the address of the I2C device (a number, typically expressed in +hexadecimal starting with 0x, but can also be expressed in decimal.) + +File delete_device takes a single parameter: the address of the I2C +device. As no two devices can live at the same address on a given I2C +segment, the address is sufficient to uniquely identify the device to be +deleted. + +Example: +# echo eeprom 0x50 > /sys/class/i2c-adapter/i2c-3/new_device + +While this interface should only be used when in-kernel device declaration +can't be done, there is a variety of cases where it can be helpful: +* The I2C driver usually detects devices (method 3 above) but the bus + segment your device lives on doesn't have the proper class bit set and + thus detection doesn't trigger. +* The I2C driver usually detects devices, but your device lives at an + unexpected address. +* The I2C driver usually detects devices, but your device is not detected, + either because the detection routine is too strict, or because your + device is not officially supported yet but you know it is compatible. +* You are developing a driver on a test board, where you soldered the I2C + device yourself. + +This interface is a replacement for the force_* module parameters some I2C +drivers implement. Being implemented in i2c-core rather than in each +device driver individually, it is much more efficient, and also has the +advantage that you do not have to reload the driver to change a setting. +You can also instantiate the device before the driver is loaded or even +available, and you don't need to know what driver the device needs. diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a2f1cd3766f..eb084fa0df8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -38,11 +38,12 @@ #include "i2c-core.h" -/* core_lock protects i2c_adapter_idr, and guarantees +/* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees that device detection, deletion of detected devices, and attach_adapter and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); +static LIST_HEAD(userspace_devices); static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); @@ -373,8 +374,128 @@ show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", adap->name); } +/* + * Let users instantiate I2C devices through sysfs. This can be used when + * platform initialization code doesn't contain the proper data for + * whatever reason. Also useful for drivers that do device detection and + * detection fails, either because the device uses an unexpected address, + * or this is a compatible device with different ID register values. + * + * Parameter checking may look overzealous, but we really don't want + * the user to provide incorrect parameters. + */ +static ssize_t +i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_board_info info; + struct i2c_client *client; + char *blank, end; + int res; + + dev_warn(dev, "The new_device interface is still experimental " + "and may change in a near future\n"); + memset(&info, 0, sizeof(struct i2c_board_info)); + + blank = strchr(buf, ' '); + if (!blank) { + dev_err(dev, "%s: Missing parameters\n", "new_device"); + return -EINVAL; + } + if (blank - buf > I2C_NAME_SIZE - 1) { + dev_err(dev, "%s: Invalid device name\n", "new_device"); + return -EINVAL; + } + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ + res = sscanf(++blank, "%hi%c", &info.addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "new_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "new_device"); + return -EINVAL; + } + + if (info.addr < 0x03 || info.addr > 0x77) { + dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", + info.addr); + return -EINVAL; + } + + client = i2c_new_device(adap, &info); + if (!client) + return -EEXIST; + + /* Keep track of the added device */ + mutex_lock(&core_lock); + list_add_tail(&client->detected, &userspace_devices); + mutex_unlock(&core_lock); + dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", + info.type, info.addr); + + return count; +} + +/* + * And of course let the users delete the devices they instantiated, if + * they got it wrong. This interface can only be used to delete devices + * instantiated by i2c_sysfs_new_device above. This guarantees that we + * don't delete devices to which some kernel code still has references. + * + * Parameter checking may look overzealous, but we really don't want + * the user to delete the wrong device. + */ +static ssize_t +i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_client *client, *next; + unsigned short addr; + char end; + int res; + + /* Parse parameters, reject extra parameters */ + res = sscanf(buf, "%hi%c", &addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "delete_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "delete_device"); + return -EINVAL; + } + + /* Make sure the device was added through sysfs */ + res = -ENOENT; + mutex_lock(&core_lock); + list_for_each_entry_safe(client, next, &userspace_devices, detected) { + if (client->addr == addr && client->adapter == adap) { + dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", + "delete_device", client->name, client->addr); + + list_del(&client->detected); + i2c_unregister_device(client); + res = count; + break; + } + } + mutex_unlock(&core_lock); + + if (res < 0) + dev_err(dev, "%s: Can't find device in list\n", + "delete_device"); + return res; +} + static struct device_attribute i2c_adapter_attrs[] = { __ATTR(name, S_IRUGO, show_adapter_name, NULL), + __ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device), + __ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device), { }, }; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 5f8157610c6..844d2662a87 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -178,7 +178,8 @@ struct i2c_driver { * @driver: device's driver, hence pointer to access routines * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) - * @detected: member of an i2c_driver.clients list + * @detected: member of an i2c_driver.clients list or i2c-core's + * userspace_devices list * * An i2c_client identifies a single device (i.e. chip) connected to an * i2c bus. The behaviour exposed to Linux is defined by the driver -- cgit v1.2.3-70-g09d2 From f18c41daea14baee11252da268cdf5dcd57c7c10 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Fri, 19 Jun 2009 16:58:20 +0200 Subject: i2c: Use rwsem instead of mutex for board info By using rwsem we can easily manage recursive calls of i2c_scan_static_board_info() function without breaking the locking. Signed-off-by: Rodolfo Giometti Signed-off-by: Jean Delvare --- drivers/i2c/i2c-boardinfo.c | 7 ++++--- drivers/i2c/i2c-core.c | 5 +++-- drivers/i2c/i2c-core.h | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index ffb35f09df0..a26a34a0664 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -18,6 +18,7 @@ #include #include +#include #include "i2c-core.h" @@ -25,7 +26,7 @@ /* These symbols are exported ONLY FOR the i2c core. * No other users will be supported. */ -DEFINE_MUTEX(__i2c_board_lock); +DECLARE_RWSEM(__i2c_board_lock); EXPORT_SYMBOL_GPL(__i2c_board_lock); LIST_HEAD(__i2c_board_list); @@ -63,7 +64,7 @@ i2c_register_board_info(int busnum, { int status; - mutex_lock(&__i2c_board_lock); + down_write(&__i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= __i2c_first_dynamic_bus_num) @@ -84,7 +85,7 @@ i2c_register_board_info(int busnum, list_add_tail(&devinfo->list, &__i2c_board_list); } - mutex_unlock(&__i2c_board_lock); + up_write(&__i2c_board_lock); return status; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index eb084fa0df8..0e45c296d3d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "i2c-core.h" @@ -509,7 +510,7 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; - mutex_lock(&__i2c_board_lock); + down_read(&__i2c_board_lock); list_for_each_entry(devinfo, &__i2c_board_list, list) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, @@ -518,7 +519,7 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) "Can't create device at 0x%02x\n", devinfo->board_info.addr); } - mutex_unlock(&__i2c_board_lock); + up_read(&__i2c_board_lock); } static int i2c_do_add_adapter(struct device_driver *d, void *data) diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index cd5bff87485..9f9c57ff670 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + struct i2c_devinfo { struct list_head list; int busnum; @@ -25,7 +27,7 @@ struct i2c_devinfo { /* board_lock protects board_list and first_dynamic_bus_num. * only i2c core components are allowed to use these symbols. */ -extern struct mutex __i2c_board_lock; +extern struct rw_semaphore __i2c_board_lock; extern struct list_head __i2c_board_list; extern int __i2c_first_dynamic_bus_num; -- cgit v1.2.3-70-g09d2 From ff0f242626313f3544254cb882039794b7b70e4b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 17 Jun 2009 03:20:21 -0700 Subject: i2c-omap: Fix build breaking typo cpu_is_omap_2430 Hi Ben, Can you please queue this fix? Thanks, Tony >From ffe2b2cdf6283770b70a197e3748c6b40a1006be Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 17 Jun 2009 13:14:23 +0300 Subject: [PATCH] i2c-omap: Fix build breaking typo in cpu_is_omap_2430 Commit 84bf2c86 introduced a typo, it should be cpu_is_omap2430 instead. The typo was probably caused by a mismerge. Without this patch all omaps fail to build with: error: implicit declaration of function 'cpu_is_omap_2430' Signed-off-by: Tony Lindgren Signed-off-by: Ben Dooks --- 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 b606db85525..ad8d2010c92 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -339,7 +339,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * to get longer filter period for better noise suppression. * The filter is iclk (fclk for HS) period. */ - if (dev->speed > 400 || cpu_is_omap_2430()) + if (dev->speed > 400 || cpu_is_omap2430()) internal_clk = 19200; else if (dev->speed > 100) internal_clk = 9600; -- cgit v1.2.3-70-g09d2 From dc1972d02747d2170fb1d78d114801f5ecb27506 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Fri, 19 Jun 2009 14:50:02 +0200 Subject: i2c: Fix stuck transaction on cpm-i2c driver When a process tries to read/write a disconnected i2c device, it receives a signal (e.g. ctrl-c) and the kernel gets stuck. BUG: soft lockup - CPU#0 stuck for 61s! [I2CEEpromTest:392] NIP: c01628f8 LR: c01628f0 CTR: c00177cc REGS: c39abd70 TRAP: 0901 Not tainted (2.6.25.7-alcore) MSR: 00009032 CR: 42042048 XER: 20000000 TASK = c3889bd0[392] 'I2CEEpromTest' THREAD: c39aa000 GPR00: 00009000 c39abe20 c3889bd0 c39075c8 c39abe28 00000001 00000000 00000001 GPR08: c3889bd0 c39075c8 00009032 c39abe34 00002437 NIP [c01628f8] cpm_i2c_xfer+0x5fc/0x6d0 LR [c01628f0] cpm_i2c_xfer+0x5f4/0x6d0 Call Trace: [c39abe20] [c0162924] cpm_i2c_xfer+0x628/0x6d0 (unreliable) [c39abe90] [c015f6a0] i2c_transfer+0x88/0xb4 [c39abeb0] [c0160164] i2c_master_recv+0x48/0x6c [c39abed0] [c01618dc] i2cdev_read+0x50/0xe4 [c39abef0] [c0068b24] vfs_read+0xc4/0x108 [c39abf10] [c0068f4c] sys_read+0x4c/0x90 [c39abf40] [c000d348] ret_from_syscall+0x0/0x38 Instruction dump: 3bc00064 92610010 3bf201c8 92810014 3b61 This happen because though the wait_event_interruptible_timeout takes the signals into account, the driver does not handle them. We propose to change the wait_event_interruptible_timeout with wait_event_timeout, leaving the signals to be handled in other points on the upper layers. Signed-off-by: Bruno Morelli Signed-off-by: Michael Trimarchi Acked-by: Jochen Friedrich [ben-linux@fluff.org: fix title for patch] Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-cpm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b5db8b88361..9c2e10082b7 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -140,7 +140,7 @@ static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id) dev_dbg(&adap->dev, "Interrupt: %x\n", i); - wake_up_interruptible(&cpm->i2c_wait); + wake_up(&cpm->i2c_wait); return i ? IRQ_HANDLED : IRQ_NONE; } @@ -364,12 +364,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) dev_dbg(&adap->dev, "test ready.\n"); pmsg = &msgs[tptr]; if (pmsg->flags & I2C_M_RD) - ret = wait_event_interruptible_timeout(cpm->i2c_wait, + ret = wait_event_timeout(cpm->i2c_wait, (in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) || !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY), 1 * HZ); else - ret = wait_event_interruptible_timeout(cpm->i2c_wait, + ret = wait_event_timeout(cpm->i2c_wait, !(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY), 1 * HZ); if (ret == 0) { -- cgit v1.2.3-70-g09d2 From 1ab52cf910bbbee92861227e6ed77c56b1dc233c Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 22 Jun 2009 16:36:29 +0300 Subject: i2c: driver for the Synopsys DesignWare I2C controller The i2c Linux driver for the DesignWare i2c block of Synopsys, which is meant for AMBA Peripheral Bus. This i2c block is used on SoC chips like the ARM9 based PVG610. Signed-off-by: Baruch Siach Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-designware.c | 624 ++++++++++++++++++++++++++++++++++++ 3 files changed, 634 insertions(+) create mode 100644 drivers/i2c/busses/i2c-designware.c (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3c259ee7ddd..aa87b6a3bbe 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -326,6 +326,15 @@ config I2C_DAVINCI devices such as DaVinci NIC. For details please see http://www.ti.com/davinci +config I2C_DESIGNWARE + tristate "Synopsys DesignWare" + help + If you say yes to this option, support will be included for the + Synopsys DesignWare I2C adapter. Only master mode is supported. + + This driver can also be built as a module. If so, the module + will be called i2c-designware. + config I2C_GPIO tristate "GPIO-based bitbanging I2C" depends on GENERIC_GPIO diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index edeabf00310..e654263bfc0 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o +obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c new file mode 100644 index 00000000000..b444762e9b9 --- /dev/null +++ b/drivers/i2c/busses/i2c-designware.c @@ -0,0 +1,624 @@ +/* + * Synopsys Designware I2C adapter driver (master only). + * + * Based on the TI DAVINCI I2C adapter driver. + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software Inc. + * Copyright (C) 2009 Provigent Ltd. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Registers offset + */ +#define DW_IC_CON 0x0 +#define DW_IC_TAR 0x4 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_TX_ABRT_SOURCE 0x80 + +#define DW_IC_CON_MASTER 0x1 +#define DW_IC_CON_SPEED_STD 0x2 +#define DW_IC_CON_SPEED_FAST 0x4 +#define DW_IC_CON_10BITADDR_MASTER 0x10 +#define DW_IC_CON_RESTART_EN 0x20 +#define DW_IC_CON_SLAVE_DISABLE 0x40 + +#define DW_IC_INTR_TX_EMPTY 0x10 +#define DW_IC_INTR_TX_ABRT 0x40 +#define DW_IC_INTR_STOP_DET 0x200 + +#define DW_IC_STATUS_ACTIVITY 0x1 + +#define DW_IC_ERR_TX_ABRT 0x1 + +/* + * status codes + */ +#define STATUS_IDLE 0x0 +#define STATUS_WRITE_IN_PROGRESS 0x1 +#define STATUS_READ_IN_PROGRESS 0x2 + +#define TIMEOUT 20 /* ms */ + +/* + * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register + * + * only expected abort codes are listed here + * refer to the datasheet for the full list + */ +#define ABRT_7B_ADDR_NOACK 0 +#define ABRT_10ADDR1_NOACK 1 +#define ABRT_10ADDR2_NOACK 2 +#define ABRT_TXDATA_NOACK 3 +#define ABRT_GCALL_NOACK 4 +#define ABRT_GCALL_READ 5 +#define ABRT_SBYTE_ACKDET 7 +#define ABRT_SBYTE_NORSTRT 9 +#define ABRT_10B_RD_NORSTRT 10 +#define ARB_MASTER_DIS 11 +#define ARB_LOST 12 + +static char *abort_sources[] = { + [ABRT_7B_ADDR_NOACK] = + "slave address not acknowledged (7bit mode)", + [ABRT_10ADDR1_NOACK] = + "first address byte not acknowledged (10bit mode)", + [ABRT_10ADDR2_NOACK] = + "second address byte not acknowledged (10bit mode)", + [ABRT_TXDATA_NOACK] = + "data not acknowledged", + [ABRT_GCALL_NOACK] = + "no acknowledgement for a general call", + [ABRT_GCALL_READ] = + "read after general call", + [ABRT_SBYTE_ACKDET] = + "start byte acknowledged", + [ABRT_SBYTE_NORSTRT] = + "trying to send start byte when restart is disabled", + [ABRT_10B_RD_NORSTRT] = + "trying to read when restart is disabled (10bit mode)", + [ARB_MASTER_DIS] = + "trying to use disabled adapter", + [ARB_LOST] = + "lost arbitration", +}; + +/** + * struct dw_i2c_dev - private i2c-designware data + * @dev: driver model device node + * @base: IO registers pointer + * @cmd_complete: tx completion indicator + * @pump_msg: continue in progress transfers + * @lock: protect this struct and IO registers + * @clk: input reference clock + * @cmd_err: run time hadware error code + * @msgs: points to an array of messages currently being transfered + * @msgs_num: the number of elements in msgs + * @msg_write_idx: the element index of the current tx message in the msgs + * array + * @tx_buf_len: the length of the current tx buffer + * @tx_buf: the current tx buffer + * @msg_read_idx: the element index of the current rx message in the msgs + * array + * @rx_buf_len: the length of the current rx buffer + * @rx_buf: the current rx buffer + * @msg_err: error status of the current transfer + * @status: i2c master status, one of STATUS_* + * @abort_source: copy of the TX_ABRT_SOURCE register + * @irq: interrupt number for the i2c master + * @adapter: i2c subsystem adapter node + * @tx_fifo_depth: depth of the hardware tx fifo + * @rx_fifo_depth: depth of the hardware rx fifo + */ +struct dw_i2c_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct tasklet_struct pump_msg; + struct mutex lock; + struct clk *clk; + int cmd_err; + struct i2c_msg *msgs; + int msgs_num; + int msg_write_idx; + u16 tx_buf_len; + u8 *tx_buf; + int msg_read_idx; + u16 rx_buf_len; + u8 *rx_buf; + int msg_err; + unsigned int status; + u16 abort_source; + int irq; + struct i2c_adapter adapter; + unsigned int tx_fifo_depth; + unsigned int rx_fifo_depth; +}; + +/** + * i2c_dw_init() - initialize the designware i2c master hardware + * @dev: device private data + * + * This functions configures and enables the I2C master. + * This function is called during I2C init function, and in case of timeout at + * run time. + */ +static void i2c_dw_init(struct dw_i2c_dev *dev) +{ + u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; + u16 ic_con; + + /* Disable the adapter */ + writeb(0, dev->base + DW_IC_ENABLE); + + /* set standard and fast speed deviders for high/low periods */ + writew((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */ + dev->base + DW_IC_SS_SCL_HCNT); + writew((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */ + dev->base + DW_IC_SS_SCL_LCNT); + writew((input_clock_khz * 6 / 10000)+1, /* fast speed high, 0.6us */ + dev->base + DW_IC_FS_SCL_HCNT); + writew((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */ + dev->base + DW_IC_FS_SCL_LCNT); + + /* configure the i2c master */ + ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; + writew(ic_con, dev->base + DW_IC_CON); +} + +/* + * Waiting for bus not busy + */ +static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) +{ + int timeout = TIMEOUT; + + while (readb(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { + if (timeout <= 0) { + dev_warn(dev->dev, "timeout waiting for bus ready\n"); + return -ETIMEDOUT; + } + timeout--; + mdelay(1); + } + + return 0; +} + +/* + * Initiate low level master read/write transaction. + * This function is called from i2c_dw_xfer when starting a transfer. + * This function is also called from dw_i2c_pump_msg to continue a transfer + * that is longer than the size of the TX FIFO. + */ +static void +i2c_dw_xfer_msg(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + struct i2c_msg *msgs = dev->msgs; + int num = dev->msgs_num; + u16 ic_con, intr_mask; + int tx_limit = dev->tx_fifo_depth - readb(dev->base + DW_IC_TXFLR); + int rx_limit = dev->rx_fifo_depth - readb(dev->base + DW_IC_RXFLR); + u16 addr = msgs[dev->msg_write_idx].addr; + u16 buf_len = dev->tx_buf_len; + + if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { + /* Disable the adapter */ + writeb(0, dev->base + DW_IC_ENABLE); + + /* set the slave (target) address */ + writew(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR); + + /* if the slave address is ten bit address, enable 10BITADDR */ + ic_con = readw(dev->base + DW_IC_CON); + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_con |= DW_IC_CON_10BITADDR_MASTER; + else + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + writew(ic_con, dev->base + DW_IC_CON); + + /* Enable the adapter */ + writeb(1, dev->base + DW_IC_ENABLE); + } + + for (; dev->msg_write_idx < num; dev->msg_write_idx++) { + /* if target address has changed, we need to + * reprogram the target address in the i2c + * adapter when we are done with this transfer + */ + if (msgs[dev->msg_write_idx].addr != addr) + return; + + if (msgs[dev->msg_write_idx].len == 0) { + dev_err(dev->dev, + "%s: invalid message length\n", __func__); + dev->msg_err = -EINVAL; + return; + } + + if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { + /* new i2c_msg */ + dev->tx_buf = msgs[dev->msg_write_idx].buf; + buf_len = msgs[dev->msg_write_idx].len; + } + + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { + writew(0x100, dev->base + DW_IC_DATA_CMD); + rx_limit--; + } else + writew(*(dev->tx_buf++), + dev->base + DW_IC_DATA_CMD); + tx_limit--; buf_len--; + } + } + + intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT; + if (buf_len > 0) { /* more bytes to be written */ + intr_mask |= DW_IC_INTR_TX_EMPTY; + dev->status |= STATUS_WRITE_IN_PROGRESS; + } else + dev->status &= ~STATUS_WRITE_IN_PROGRESS; + writew(intr_mask, dev->base + DW_IC_INTR_MASK); + + dev->tx_buf_len = buf_len; +} + +static void +i2c_dw_read(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + struct i2c_msg *msgs = dev->msgs; + int num = dev->msgs_num; + u16 addr = msgs[dev->msg_read_idx].addr; + int rx_valid = readw(dev->base + DW_IC_RXFLR); + + for (; dev->msg_read_idx < num; dev->msg_read_idx++) { + u16 len; + u8 *buf; + + if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD)) + continue; + + /* different i2c client, reprogram the i2c adapter */ + if (msgs[dev->msg_read_idx].addr != addr) + return; + + if (!(dev->status & STATUS_READ_IN_PROGRESS)) { + len = msgs[dev->msg_read_idx].len; + buf = msgs[dev->msg_read_idx].buf; + } else { + len = dev->rx_buf_len; + buf = dev->rx_buf; + } + + for (; len > 0 && rx_valid > 0; len--, rx_valid--) + *buf++ = readb(dev->base + DW_IC_DATA_CMD); + + if (len > 0) { + dev->status |= STATUS_READ_IN_PROGRESS; + dev->rx_buf_len = len; + dev->rx_buf = buf; + return; + } else + dev->status &= ~STATUS_READ_IN_PROGRESS; + } +} + +/* + * Prepare controller for a transaction and call i2c_dw_xfer_msg + */ +static int +i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + + mutex_lock(&dev->lock); + + INIT_COMPLETION(dev->cmd_complete); + dev->msgs = msgs; + dev->msgs_num = num; + dev->cmd_err = 0; + dev->msg_write_idx = 0; + dev->msg_read_idx = 0; + dev->msg_err = 0; + dev->status = STATUS_IDLE; + + ret = i2c_dw_wait_bus_not_busy(dev); + if (ret < 0) + goto done; + + /* start the transfers */ + i2c_dw_xfer_msg(adap); + + /* wait for tx to complete */ + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); + if (ret == 0) { + dev_err(dev->dev, "controller timed out\n"); + i2c_dw_init(dev); + ret = -ETIMEDOUT; + goto done; + } else if (ret < 0) + goto done; + + if (dev->msg_err) { + ret = dev->msg_err; + goto done; + } + + /* no error */ + if (likely(!dev->cmd_err)) { + /* read rx fifo, and disable the adapter */ + do { + i2c_dw_read(adap); + } while (dev->status & STATUS_READ_IN_PROGRESS); + writeb(0, dev->base + DW_IC_ENABLE); + ret = num; + goto done; + } + + /* We have an error */ + if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { + unsigned long abort_source = dev->abort_source; + int i; + + for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) { + dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); + } + } + ret = -EIO; + +done: + mutex_unlock(&dev->lock); + + return ret; +} + +static u32 i2c_dw_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; +} + +static void dw_i2c_pump_msg(unsigned long data) +{ + struct dw_i2c_dev *dev = (struct dw_i2c_dev *) data; + u16 intr_mask; + + i2c_dw_read(&dev->adapter); + i2c_dw_xfer_msg(&dev->adapter); + + intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT; + if (dev->status & STATUS_WRITE_IN_PROGRESS) + intr_mask |= DW_IC_INTR_TX_EMPTY; + writew(intr_mask, dev->base + DW_IC_INTR_MASK); +} + +/* + * Interrupt service routine. This gets called whenever an I2C interrupt + * occurs. + */ +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +{ + struct dw_i2c_dev *dev = dev_id; + u16 stat; + + stat = readw(dev->base + DW_IC_INTR_STAT); + dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); + if (stat & DW_IC_INTR_TX_ABRT) { + dev->abort_source = readw(dev->base + DW_IC_TX_ABRT_SOURCE); + dev->cmd_err |= DW_IC_ERR_TX_ABRT; + dev->status = STATUS_IDLE; + } else if (stat & DW_IC_INTR_TX_EMPTY) + tasklet_schedule(&dev->pump_msg); + + readb(dev->base + DW_IC_CLR_INTR); /* clear interrupts */ + writew(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */ + if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) + complete(&dev->cmd_complete); + + return IRQ_HANDLED; +} + +static struct i2c_algorithm i2c_dw_algo = { + .master_xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, +}; + +static int __devinit dw_i2c_probe(struct platform_device *pdev) +{ + struct dw_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *mem, *irq, *ioarea; + int r; + + /* NOTE: driver uses the static register mapping */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -EINVAL; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -EINVAL; + } + + ioarea = request_mem_region(mem->start, resource_size(mem), + pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -EBUSY; + } + + dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); + if (!dev) { + r = -ENOMEM; + goto err_release_region; + } + + init_completion(&dev->cmd_complete); + tasklet_init(&dev->pump_msg, dw_i2c_pump_msg, (unsigned long) dev); + mutex_init(&dev->lock); + dev->dev = get_device(&pdev->dev); + dev->irq = irq->start; + platform_set_drvdata(pdev, dev); + + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) { + r = -ENODEV; + goto err_free_mem; + } + clk_enable(dev->clk); + + dev->base = ioremap(mem->start, resource_size(mem)); + if (dev->base == NULL) { + dev_err(&pdev->dev, "failure mapping io resources\n"); + r = -EBUSY; + goto err_unuse_clocks; + } + { + u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1); + + dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; + dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; + } + i2c_dw_init(dev); + + writew(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */ + r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev); + if (r) { + dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); + goto err_iounmap; + } + + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + strlcpy(adap->name, "Synopsys DesignWare I2C adapter", + sizeof(adap->name)); + adap->algo = &i2c_dw_algo; + adap->dev.parent = &pdev->dev; + + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); + if (r) { + dev_err(&pdev->dev, "failure adding adapter\n"); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_iounmap: + iounmap(dev->base); +err_unuse_clocks: + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; +err_free_mem: + platform_set_drvdata(pdev, NULL); + put_device(&pdev->dev); + kfree(dev); +err_release_region: + release_mem_region(mem->start, resource_size(mem)); + + return r; +} + +static int __devexit dw_i2c_remove(struct platform_device *pdev) +{ + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&dev->adapter); + put_device(&pdev->dev); + + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; + + writeb(0, dev->base + DW_IC_ENABLE); + free_irq(dev->irq, dev); + kfree(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + return 0; +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:i2c_designware"); + +static struct platform_driver dw_i2c_driver = { + .remove = __devexit_p(dw_i2c_remove), + .driver = { + .name = "i2c_designware", + .owner = THIS_MODULE, + }, +}; + +static int __init dw_i2c_init_driver(void) +{ + return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); +} +module_init(dw_i2c_init_driver); + +static void __exit dw_i2c_exit_driver(void) +{ + platform_driver_unregister(&dw_i2c_driver); +} +module_exit(dw_i2c_exit_driver); + +MODULE_AUTHOR("Baruch Siach "); +MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2