From bac3e7c2aa2575a1c71f6fa643499676ca7c12c3 Mon Sep 17 00:00:00 2001 From: Frank Seidel Date: Sat, 28 Mar 2009 21:34:44 +0100 Subject: i2c: Adapt debug macros for KERN_* constants According to kerneljanitors todo list all printk calls (beginning a new line) should have an according KERN_* constant. Those are the changes to the debug macros in the i2c subsystem to meet this requirement. Also changing no-debug statements to raw printks again. Signed-off-by: Frank Seidel Signed-off-by: Jean Delvare Tested-by: Wolfram Sang --- drivers/i2c/algos/i2c-algo-pca.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/i2c/algos/i2c-algo-pca.c') diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index d50b329a3c94..943d70ee5d59 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -27,9 +27,12 @@ #include #include -#define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0) -#define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) -#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0) +#define DEB1(fmt, args...) do { if (i2c_debug >= 1) \ + printk(KERN_DEBUG fmt, ## args); } while (0) +#define DEB2(fmt, args...) do { if (i2c_debug >= 2) \ + printk(KERN_DEBUG fmt, ## args); } while (0) +#define DEB3(fmt, args...) do { if (i2c_debug >= 3) \ + printk(KERN_DEBUG fmt, ## args); } while (0) static int i2c_debug; @@ -313,7 +316,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, ret = curmsg; out: - DEB1(KERN_CRIT "}}} transfered %d/%d messages. " + DEB1("}}} transfered %d/%d messages. " "status is %#04x. control is %#04x\n", curmsg, num, pca_status(adap), pca_get_con(adap)); @@ -347,7 +350,8 @@ static int pca_init(struct i2c_adapter *adap) pca_reset(pca_data); clock = pca_clock(pca_data); - DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]); + printk(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, + freqs[clock]); pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); udelay(500); /* 500 us for oscilator to stabilise */ -- cgit v1.2.3 From eff9ec95efaaf6b12d230f0ea7d3c295d3bc9d57 Mon Sep 17 00:00:00 2001 From: Marco Aurelio da Costa Date: Sat, 28 Mar 2009 21:34:44 +0100 Subject: i2c-algo-pca: Add PCA9665 support Add support for the PCA9665 I2C controller. Signed-off-by: Wolfram Sang Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-pca.c | 180 +++++++++++++++++++++++++++++++--- drivers/i2c/busses/Kconfig | 8 +- drivers/i2c/busses/i2c-pca-isa.c | 14 ++- drivers/i2c/busses/i2c-pca-platform.c | 9 +- include/linux/i2c-algo-pca.h | 33 ++++++- 5 files changed, 216 insertions(+), 28 deletions(-) (limited to 'drivers/i2c/algos/i2c-algo-pca.c') diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 943d70ee5d59..a8e51bd1a4f5 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -46,6 +46,14 @@ static int i2c_debug; #define pca_wait(adap) adap->wait_for_completion(adap->data) #define pca_reset(adap) adap->reset_chip(adap->data) +static void pca9665_reset(void *pd) +{ + struct i2c_algo_pca_data *adap = pd; + pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); + pca_outw(adap, I2C_PCA_IND, 0xA5); + pca_outw(adap, I2C_PCA_IND, 0x5A); +} + /* * Generate a start condition on the i2c bus. * @@ -333,27 +341,171 @@ static const struct i2c_algorithm pca_algo = { .functionality = pca_func, }; -static int pca_init(struct i2c_adapter *adap) +static unsigned int pca_probe_chip(struct i2c_adapter *adap) { - static int freqs[] = {330,288,217,146,88,59,44,36}; - int clock; struct i2c_algo_pca_data *pca_data = adap->algo_data; - - if (pca_data->i2c_clock > 7) { - printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n", - adap->name); - pca_data->i2c_clock = I2C_PCA_CON_59kHz; + /* The trick here is to check if there is an indirect register + * available. If there is one, we will read the value we first + * wrote on I2C_PCA_IADR. Otherwise, we will read the last value + * we wrote on I2C_PCA_ADR + */ + pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); + pca_outw(pca_data, I2C_PCA_IND, 0xAA); + pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ITO); + pca_outw(pca_data, I2C_PCA_IND, 0x00); + pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); + if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { + printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); + return I2C_PCA_CHIP_9665; + } else { + printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); + return I2C_PCA_CHIP_9564; } +} + +static int pca_init(struct i2c_adapter *adap) +{ + struct i2c_algo_pca_data *pca_data = adap->algo_data; adap->algo = &pca_algo; - pca_reset(pca_data); + if (pca_probe_chip(adap) == I2C_PCA_CHIP_9564) { + static int freqs[] = {330, 288, 217, 146, 88, 59, 44, 36}; + int clock; + + if (pca_data->i2c_clock > 7) { + switch (pca_data->i2c_clock) { + case 330000: + pca_data->i2c_clock = I2C_PCA_CON_330kHz; + break; + case 288000: + pca_data->i2c_clock = I2C_PCA_CON_288kHz; + break; + case 217000: + pca_data->i2c_clock = I2C_PCA_CON_217kHz; + break; + case 146000: + pca_data->i2c_clock = I2C_PCA_CON_146kHz; + break; + case 88000: + pca_data->i2c_clock = I2C_PCA_CON_88kHz; + break; + case 59000: + pca_data->i2c_clock = I2C_PCA_CON_59kHz; + break; + case 44000: + pca_data->i2c_clock = I2C_PCA_CON_44kHz; + break; + case 36000: + pca_data->i2c_clock = I2C_PCA_CON_36kHz; + break; + default: + printk(KERN_WARNING + "%s: Invalid I2C clock speed selected." + " Using default 59kHz.\n", adap->name); + pca_data->i2c_clock = I2C_PCA_CON_59kHz; + } + } else { + printk(KERN_WARNING "%s: " + "Choosing the clock frequency based on " + "index is deprecated." + " Use the nominal frequency.\n", adap->name); + } + + pca_reset(pca_data); + + clock = pca_clock(pca_data); + printk(KERN_INFO "%s: Clock frequency is %dkHz\n", + adap->name, freqs[clock]); + + pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); + } else { + int clock; + int mode; + int tlow, thi; + /* Values can be found on PCA9665 datasheet section 7.3.2.6 */ + int min_tlow, min_thi; + /* These values are the maximum raise and fall values allowed + * by the I2C operation mode (Standard, Fast or Fast+) + * They are used (added) below to calculate the clock dividers + * of PCA9665. Note that they are slightly different of the + * real maximum, to allow the change on mode exactly on the + * maximum clock rate for each mode + */ + int raise_fall_time; + + struct i2c_algo_pca_data *pca_data = adap->algo_data; + + /* Ignore the reset function from the module, + * we can use the parallel bus reset + */ + pca_data->reset_chip = pca9665_reset; + + if (pca_data->i2c_clock > 1265800) { + printk(KERN_WARNING "%s: I2C clock speed too high." + " Using 1265.8kHz.\n", adap->name); + pca_data->i2c_clock = 1265800; + } + + if (pca_data->i2c_clock < 60300) { + printk(KERN_WARNING "%s: I2C clock speed too low." + " Using 60.3kHz.\n", adap->name); + pca_data->i2c_clock = 60300; + } + + /* To avoid integer overflow, use clock/100 for calculations */ + clock = pca_clock(pca_data) / 100; + + if (pca_data->i2c_clock > 10000) { + mode = I2C_PCA_MODE_TURBO; + min_tlow = 14; + min_thi = 5; + raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ + } else if (pca_data->i2c_clock > 4000) { + mode = I2C_PCA_MODE_FASTP; + min_tlow = 17; + min_thi = 9; + raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ + } else if (pca_data->i2c_clock > 1000) { + mode = I2C_PCA_MODE_FAST; + min_tlow = 44; + min_thi = 20; + raise_fall_time = 58; /* Raise 29e-8s, Fall 29e-8s */ + } else { + mode = I2C_PCA_MODE_STD; + min_tlow = 157; + min_thi = 134; + raise_fall_time = 127; /* Raise 29e-8s, Fall 98e-8s */ + } + + /* The minimum clock that respects the thi/tlow = 134/157 is + * 64800 Hz. Below that, we have to fix the tlow to 255 and + * calculate the thi factor. + */ + if (clock < 648) { + tlow = 255; + thi = 1000000 - clock * raise_fall_time; + thi /= (I2C_PCA_OSC_PER * clock) - tlow; + } else { + tlow = (1000000 - clock * raise_fall_time) * min_tlow; + tlow /= I2C_PCA_OSC_PER * clock * (min_thi + min_tlow); + thi = tlow * min_thi / min_tlow; + } + + pca_reset(pca_data); - clock = pca_clock(pca_data); - printk(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, - freqs[clock]); + printk(KERN_INFO + "%s: Clock frequency is %dHz\n", adap->name, clock * 100); - pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); + pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE); + pca_outw(pca_data, I2C_PCA_IND, mode); + pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL); + pca_outw(pca_data, I2C_PCA_IND, tlow); + pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH); + pca_outw(pca_data, I2C_PCA_IND, thi); + + pca_set_con(pca_data, I2C_PCA_CON_ENSIO); + } udelay(500); /* 500 us for oscilator to stabilise */ return 0; @@ -388,7 +540,7 @@ EXPORT_SYMBOL(i2c_pca_add_numbered_bus); MODULE_AUTHOR("Ian Campbell , " "Wolfram Sang "); -MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); +MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm"); MODULE_LICENSE("GPL"); module_param(i2c_debug, int, 0); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7f95905bbb9d..68650643d116 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -617,12 +617,12 @@ config I2C_ELEKTOR will be called i2c-elektor. config I2C_PCA_ISA - tristate "PCA9564 on an ISA bus" + tristate "PCA9564/PCA9665 on an ISA bus" depends on ISA select I2C_ALGOPCA default n help - This driver supports ISA boards using the Philips PCA9564 + This driver supports ISA boards using the Philips PCA9564/PCA9665 parallel bus to I2C bus controller. This driver can also be built as a module. If so, the module @@ -634,11 +634,11 @@ config I2C_PCA_ISA time). If unsure, say N. config I2C_PCA_PLATFORM - tristate "PCA9564 as platform device" + tristate "PCA9564/PCA9665 as platform device" select I2C_ALGOPCA default n help - This driver supports a memory mapped Philips PCA9564 + This driver supports a memory mapped Philips PCA9564/PCA9665 parallel bus to I2C bus controller. This driver can also be built as a module. If so, the module diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index c420a7c0f3e4..0cc8017b3f64 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -41,7 +41,7 @@ static int irq = -1; /* Data sheet recommends 59kHz for 100kHz operation due to variation * in the actual clock rate */ -static int clock = I2C_PCA_CON_59kHz; +static int clock = 59000; static wait_queue_head_t pca_wait; @@ -103,7 +103,7 @@ static struct i2c_algo_pca_data pca_isa_data = { static struct i2c_adapter pca_isa_ops = { .owner = THIS_MODULE, .algo_data = &pca_isa_data, - .name = "PCA9564 ISA Adapter", + .name = "PCA9564/PCA9665 ISA Adapter", .timeout = 100, }; @@ -196,7 +196,7 @@ static void __exit pca_isa_exit(void) } MODULE_AUTHOR("Ian Campbell "); -MODULE_DESCRIPTION("ISA base PCA9564 driver"); +MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver"); MODULE_LICENSE("GPL"); module_param(base, ulong, 0); @@ -205,7 +205,13 @@ MODULE_PARM_DESC(base, "I/O base address"); module_param(irq, int, 0); MODULE_PARM_DESC(irq, "IRQ"); module_param(clock, int, 0); -MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet"); +MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t" + "For PCA9564: 330000,288000,217000,146000," + "88000,59000,44000,36000\n" + "\t\tFor PCA9665:\tStandard: 60300 - 100099\n" + "\t\t\t\tFast: 100100 - 400099\n" + "\t\t\t\tFast+: 400100 - 10000099\n" + "\t\t\t\tTurbo: Up to 1265800"); module_init(pca_isa_init); module_exit(pca_isa_exit); diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 6bb15ad0a6b6..51d179bbddf9 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -172,8 +172,9 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; i2c->adap.owner = THIS_MODULE; - snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564 at 0x%08lx", - (unsigned long) res->start); + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + "PCA9564/PCA9665 at 0x%08lx", + (unsigned long) res->start); i2c->adap.algo_data = &i2c->algo_data; i2c->adap.dev.parent = &pdev->dev; i2c->adap.timeout = platform_data->timeout; @@ -246,7 +247,7 @@ e_remap: e_alloc: release_mem_region(res->start, res_len(res)); e_print: - printk(KERN_ERR "Registering PCA9564 FAILED! (%d)\n", ret); + printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret); return ret; } @@ -290,7 +291,7 @@ static void __exit i2c_pca_pf_exit(void) } MODULE_AUTHOR("Wolfram Sang "); -MODULE_DESCRIPTION("I2C-PCA9564 platform driver"); +MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver"); MODULE_LICENSE("GPL"); module_init(i2c_pca_pf_init); diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h index adcb3dc7ac26..1364d62e2fbe 100644 --- a/include/linux/i2c-algo-pca.h +++ b/include/linux/i2c-algo-pca.h @@ -1,7 +1,14 @@ #ifndef _LINUX_I2C_ALGO_PCA_H #define _LINUX_I2C_ALGO_PCA_H -/* Clock speeds for the bus */ +/* Chips known to the pca algo */ +#define I2C_PCA_CHIP_9564 0x00 +#define I2C_PCA_CHIP_9665 0x01 + +/* Internal period for PCA9665 oscilator */ +#define I2C_PCA_OSC_PER 3 /* e10-8s */ + +/* Clock speeds for the bus for PCA9564*/ #define I2C_PCA_CON_330kHz 0x00 #define I2C_PCA_CON_288kHz 0x01 #define I2C_PCA_CON_217kHz 0x02 @@ -18,6 +25,26 @@ #define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */ #define I2C_PCA_CON 0x03 /* CONTROL Read/Write */ +/* PCA9665 registers */ +#define I2C_PCA_INDPTR 0x00 /* INDIRECT Pointer Write Only */ +#define I2C_PCA_IND 0x02 /* INDIRECT Read/Write */ + +/* PCA9665 indirect registers */ +#define I2C_PCA_ICOUNT 0x00 /* Byte Count for buffered mode */ +#define I2C_PCA_IADR 0x01 /* OWN ADR */ +#define I2C_PCA_ISCLL 0x02 /* SCL LOW period */ +#define I2C_PCA_ISCLH 0x03 /* SCL HIGH period */ +#define I2C_PCA_ITO 0x04 /* TIMEOUT */ +#define I2C_PCA_IPRESET 0x05 /* Parallel bus reset */ +#define I2C_PCA_IMODE 0x06 /* I2C Bus mode */ + +/* PCA9665 I2C bus mode */ +#define I2C_PCA_MODE_STD 0x00 /* Standard mode */ +#define I2C_PCA_MODE_FAST 0x01 /* Fast mode */ +#define I2C_PCA_MODE_FASTP 0x02 /* Fast Plus mode */ +#define I2C_PCA_MODE_TURBO 0x03 /* Turbo mode */ + + #define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */ #define I2C_PCA_CON_ENSIO 0x40 /* Enable */ #define I2C_PCA_CON_STA 0x20 /* Start */ @@ -31,7 +58,9 @@ struct i2c_algo_pca_data { int (*read_byte) (void *data, int reg); int (*wait_for_completion) (void *data); void (*reset_chip) (void *data); - /* i2c_clock values are defined in linux/i2c-algo-pca.h */ + /* For PCA9564, use one of the predefined frequencies: + * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000 + * For PCA9665, use the frequency you want here. */ unsigned int i2c_clock; }; -- cgit v1.2.3 From 8e99ada8deaa9033600cd2c7d0a9366b0e99ab68 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 28 Mar 2009 21:34:45 +0100 Subject: i2c-algo-pca: Rework waiting for a free bus Waiting for a free bus now accepts the timeout value in jiffies and does proper checking using time_before. Signed-off-by: Wolfram Sang Signed-off-by: Jean Delvare --- arch/sh/boards/board-sh7785lcr.c | 2 +- drivers/i2c/algos/i2c-algo-pca.c | 17 ++++++++++------- drivers/i2c/busses/i2c-pca-isa.c | 2 +- include/linux/i2c-pca-platform.h | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/i2c/algos/i2c-algo-pca.c') diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c index 94c0296bc35d..6f94f17adc46 100644 --- a/arch/sh/boards/board-sh7785lcr.c +++ b/arch/sh/boards/board-sh7785lcr.c @@ -229,7 +229,7 @@ static struct resource i2c_resources[] = { static struct i2c_pca9564_pf_platform_data i2c_platform_data = { .gpio = 0, .i2c_clock_speed = I2C_PCA_CON_330kHz, - .timeout = 100, + .timeout = HZ, }; static struct platform_device i2c_device = { diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index a8e51bd1a4f5..9e134fad7bda 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -186,14 +187,16 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, int numbytes = 0; int state; int ret; - int timeout = i2c_adap->timeout; + unsigned long timeout = jiffies + i2c_adap->timeout; - while ((state = pca_status(adap)) != 0xf8 && timeout--) { - msleep(10); - } - if (state != 0xf8) { - dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state); - return -EAGAIN; + while (pca_status(adap) != 0xf8) { + if (time_before(jiffies, timeout)) { + msleep(10); + } else { + dev_dbg(&i2c_adap->dev, "bus is not idle. status is " + "%#04x\n", state); + return -EAGAIN; + } } DEB1("{{{ XFER %d messages\n", num); diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 0cc8017b3f64..b9403fdfb6d8 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -104,7 +104,7 @@ static struct i2c_adapter pca_isa_ops = { .owner = THIS_MODULE, .algo_data = &pca_isa_data, .name = "PCA9564/PCA9665 ISA Adapter", - .timeout = 100, + .timeout = HZ, }; static int __devinit pca_isa_match(struct device *dev, unsigned int id) diff --git a/include/linux/i2c-pca-platform.h b/include/linux/i2c-pca-platform.h index 3d191873f2d1..aba33759dec4 100644 --- a/include/linux/i2c-pca-platform.h +++ b/include/linux/i2c-pca-platform.h @@ -6,7 +6,7 @@ struct i2c_pca9564_pf_platform_data { * not supplied (negative value), but it * cannot exit some error conditions then */ int i2c_clock_speed; /* values are defined in linux/i2c-algo-pca.h */ - int timeout; /* timeout = this value * 10us */ + int timeout; /* timeout in jiffies */ }; #endif /* I2C_PCA9564_PLATFORM_H */ -- cgit v1.2.3 From 2378bc09b91b0702fac7823828a614fd8016a29f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 28 Mar 2009 21:34:45 +0100 Subject: i2c-algo-pca: Use timeout for checking the state machine We now timeout also if the state machine does not change within the given time. For that, the driver-specific completion-functions are extended to return true or false depending on the timeout. This then gets checked in the algorithm. Signed-off-by: Wolfram Sang Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-pca.c | 41 ++++++++++++++++++++--------------- drivers/i2c/busses/i2c-pca-isa.c | 18 ++++++++++----- drivers/i2c/busses/i2c-pca-platform.c | 20 ++++++++--------- 3 files changed, 46 insertions(+), 33 deletions(-) (limited to 'drivers/i2c/algos/i2c-algo-pca.c') diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 9e134fad7bda..f68e5f8e23ee 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -60,14 +60,14 @@ static void pca9665_reset(void *pd) * * returns after the start condition has occurred */ -static void pca_start(struct i2c_algo_pca_data *adap) +static int pca_start(struct i2c_algo_pca_data *adap) { int sta = pca_get_con(adap); DEB2("=== START\n"); sta |= I2C_PCA_CON_STA; sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); pca_set_con(adap, sta); - pca_wait(adap); + return pca_wait(adap); } /* @@ -75,14 +75,14 @@ static void pca_start(struct i2c_algo_pca_data *adap) * * return after the repeated start condition has occurred */ -static void pca_repeated_start(struct i2c_algo_pca_data *adap) +static int pca_repeated_start(struct i2c_algo_pca_data *adap) { int sta = pca_get_con(adap); DEB2("=== REPEATED START\n"); sta |= I2C_PCA_CON_STA; sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); pca_set_con(adap, sta); - pca_wait(adap); + return pca_wait(adap); } /* @@ -108,7 +108,7 @@ static void pca_stop(struct i2c_algo_pca_data *adap) * * returns after the address has been sent */ -static void pca_address(struct i2c_algo_pca_data *adap, +static int pca_address(struct i2c_algo_pca_data *adap, struct i2c_msg *msg) { int sta = pca_get_con(adap); @@ -125,7 +125,7 @@ static void pca_address(struct i2c_algo_pca_data *adap, sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); pca_set_con(adap, sta); - pca_wait(adap); + return pca_wait(adap); } /* @@ -133,7 +133,7 @@ static void pca_address(struct i2c_algo_pca_data *adap, * * Returns after the byte has been transmitted */ -static void pca_tx_byte(struct i2c_algo_pca_data *adap, +static int pca_tx_byte(struct i2c_algo_pca_data *adap, __u8 b) { int sta = pca_get_con(adap); @@ -143,7 +143,7 @@ static void pca_tx_byte(struct i2c_algo_pca_data *adap, sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); pca_set_con(adap, sta); - pca_wait(adap); + return pca_wait(adap); } /* @@ -163,7 +163,7 @@ static void pca_rx_byte(struct i2c_algo_pca_data *adap, * * Returns after next byte has arrived. */ -static void pca_rx_ack(struct i2c_algo_pca_data *adap, +static int pca_rx_ack(struct i2c_algo_pca_data *adap, int ack) { int sta = pca_get_con(adap); @@ -174,7 +174,7 @@ static void pca_rx_ack(struct i2c_algo_pca_data *adap, sta |= I2C_PCA_CON_AA; pca_set_con(adap, sta); - pca_wait(adap); + return pca_wait(adap); } static int pca_xfer(struct i2c_adapter *i2c_adap, @@ -187,6 +187,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, int numbytes = 0; int state; int ret; + int completed = 1; unsigned long timeout = jiffies + i2c_adap->timeout; while (pca_status(adap) != 0xf8) { @@ -232,18 +233,19 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, switch (state) { case 0xf8: /* On reset or stop the bus is idle */ - pca_start(adap); + completed = pca_start(adap); break; case 0x08: /* A START condition has been transmitted */ case 0x10: /* A repeated start condition has been transmitted */ - pca_address(adap, msg); + completed = pca_address(adap, msg); break; case 0x18: /* SLA+W has been transmitted; ACK has been received */ case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */ if (numbytes < msg->len) { - pca_tx_byte(adap, msg->buf[numbytes]); + completed = pca_tx_byte(adap, + msg->buf[numbytes]); numbytes++; break; } @@ -251,7 +253,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, if (curmsg == num) pca_stop(adap); else - pca_repeated_start(adap); + completed = pca_repeated_start(adap); break; case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */ @@ -260,21 +262,22 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, goto out; case 0x40: /* SLA+R has been transmitted; ACK has been received */ - pca_rx_ack(adap, msg->len > 1); + completed = pca_rx_ack(adap, msg->len > 1); break; case 0x50: /* Data bytes has been received; ACK has been returned */ if (numbytes < msg->len) { pca_rx_byte(adap, &msg->buf[numbytes], 1); numbytes++; - pca_rx_ack(adap, numbytes < msg->len - 1); + completed = pca_rx_ack(adap, + numbytes < msg->len - 1); break; } curmsg++; numbytes = 0; if (curmsg == num) pca_stop(adap); else - pca_repeated_start(adap); + completed = pca_repeated_start(adap); break; case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */ @@ -297,7 +300,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, if (curmsg == num) pca_stop(adap); else - pca_repeated_start(adap); + completed = pca_repeated_start(adap); } else { DEB2("NOT ACK sent after data byte received. " "Not final byte. numbytes %d. len %d\n", @@ -323,6 +326,8 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, break; } + if (!completed) + goto out; } ret = curmsg; diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index b9403fdfb6d8..0ed68e2ccd22 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ static int irq = -1; * in the actual clock rate */ static int clock = 59000; +static struct i2c_adapter pca_isa_ops; static wait_queue_head_t pca_wait; static void pca_isa_writebyte(void *pd, int reg, int val) @@ -69,16 +71,22 @@ static int pca_isa_readbyte(void *pd, int reg) static int pca_isa_waitforcompletion(void *pd) { - int ret = 0; + long ret = ~0; + unsigned long timeout; if (irq > -1) { - ret = wait_event_interruptible(pca_wait, - pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI); + ret = wait_event_interruptible_timeout(pca_wait, + pca_isa_readbyte(pd, I2C_PCA_CON) + & I2C_PCA_CON_SI, pca_isa_ops.timeout); } else { - while ((pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) + /* Do polling */ + timeout = jiffies + pca_isa_ops.timeout; + while (((pca_isa_readbyte(pd, I2C_PCA_CON) + & I2C_PCA_CON_SI) == 0) + && (ret = time_before(jiffies, timeout))) udelay(100); } - return ret; + return ret > 0; } static void pca_isa_resetchip(void *pd) diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 51d179bbddf9..df5e593a1d76 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -81,24 +82,23 @@ static void i2c_pca_pf_writebyte32(void *pd, int reg, int val) static int i2c_pca_pf_waitforcompletion(void *pd) { struct i2c_pca_pf_data *i2c = pd; - int ret = 0; + long ret = ~0; + unsigned long timeout; if (i2c->irq) { - ret = wait_event_interruptible(i2c->wait, + ret = wait_event_interruptible_timeout(i2c->wait, i2c->algo_data.read_byte(i2c, I2C_PCA_CON) - & I2C_PCA_CON_SI); + & I2C_PCA_CON_SI, i2c->adap.timeout); } else { - /* - * Do polling... - * XXX: Could get stuck in extreme cases! - * Maybe add timeout, but using irqs is preferred anyhow. - */ - while ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) + /* Do polling */ + timeout = jiffies + i2c->adap.timeout; + while (((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) + && (ret = time_before(jiffies, timeout))) udelay(100); } - return ret; + return ret > 0; } static void i2c_pca_pf_dummyreset(void *pd) -- cgit v1.2.3