diff options
| author | Thomas Kavanagh <tkavanagh@juniper.net> | 2012-09-20 23:20:46 -0400 |
|---|---|---|
| committer | Wolfram Sang <w.sang@pengutronix.de> | 2012-10-06 07:14:36 -0400 |
| commit | a76e7c6821b5dddf69db9d76ec282819545f5b73 (patch) | |
| tree | b86ced7ed1c3187cf1757e0f4b5acd68b423d8a4 /drivers/i2c | |
| parent | 0c25aefa35c2fb5592895615f77d9f6fa36a849d (diff) | |
i2c: algo: pca: Fix chip reset function for PCA9665
The parameter passed to pca9665_reset is adap->data (which is bus driver
specific), not i2c_algp_pca_data *adap. pca9665_reset expects it to be
i2c_algp_pca_data *adap. All other wrappers from the algo call back to
the bus driver, which knows to handle its custom data. Only pca9665_reset
resides inside the algorithm code and does not know how to handle a custom
data structure. This can result in a kernel crash.
Fix by re-factoring pca_reset() from a macro to a function handling chip
specific code, and only call adap->reset_chip() if the chip is not PCA9665.
Signed-off-by: Thomas Kavanagh <tkavanagh@juniper.net>
Signed-off-by: Guenter Roeck <groeck@juniper.net>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 27 |
1 files changed, 14 insertions, 13 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 73133b1063f0..07ccbef6cc14 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c | |||
| @@ -46,14 +46,19 @@ static int i2c_debug; | |||
| 46 | #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) | 46 | #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) |
| 47 | #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) | 47 | #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) |
| 48 | #define pca_wait(adap) adap->wait_for_completion(adap->data) | 48 | #define pca_wait(adap) adap->wait_for_completion(adap->data) |
| 49 | #define pca_reset(adap) adap->reset_chip(adap->data) | ||
| 50 | 49 | ||
| 51 | static void pca9665_reset(void *pd) | 50 | static void pca_reset(struct i2c_algo_pca_data *adap) |
| 52 | { | 51 | { |
| 53 | struct i2c_algo_pca_data *adap = pd; | 52 | if (adap->chip == I2C_PCA_CHIP_9665) { |
| 54 | pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); | 53 | /* Ignore the reset function from the module, |
| 55 | pca_outw(adap, I2C_PCA_IND, 0xA5); | 54 | * we can use the parallel bus reset. |
| 56 | pca_outw(adap, I2C_PCA_IND, 0x5A); | 55 | */ |
| 56 | pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); | ||
| 57 | pca_outw(adap, I2C_PCA_IND, 0xA5); | ||
| 58 | pca_outw(adap, I2C_PCA_IND, 0x5A); | ||
| 59 | } else { | ||
| 60 | adap->reset_chip(adap->data); | ||
| 61 | } | ||
| 57 | } | 62 | } |
| 58 | 63 | ||
| 59 | /* | 64 | /* |
| @@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap) | |||
| 378 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); | 383 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); |
| 379 | if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { | 384 | if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { |
| 380 | printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); | 385 | printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); |
| 381 | return I2C_PCA_CHIP_9665; | 386 | pca_data->chip = I2C_PCA_CHIP_9665; |
| 382 | } else { | 387 | } else { |
| 383 | printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); | 388 | printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); |
| 384 | return I2C_PCA_CHIP_9564; | 389 | pca_data->chip = I2C_PCA_CHIP_9564; |
| 385 | } | 390 | } |
| 391 | return pca_data->chip; | ||
| 386 | } | 392 | } |
| 387 | 393 | ||
| 388 | static int pca_init(struct i2c_adapter *adap) | 394 | static int pca_init(struct i2c_adapter *adap) |
| @@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap) | |||
| 456 | */ | 462 | */ |
| 457 | int raise_fall_time; | 463 | int raise_fall_time; |
| 458 | 464 | ||
| 459 | /* Ignore the reset function from the module, | ||
| 460 | * we can use the parallel bus reset | ||
| 461 | */ | ||
| 462 | pca_data->reset_chip = pca9665_reset; | ||
| 463 | |||
| 464 | if (pca_data->i2c_clock > 1265800) { | 465 | if (pca_data->i2c_clock > 1265800) { |
| 465 | printk(KERN_WARNING "%s: I2C clock speed too high." | 466 | printk(KERN_WARNING "%s: I2C clock speed too high." |
| 466 | " Using 1265.8kHz.\n", adap->name); | 467 | " Using 1265.8kHz.\n", adap->name); |
