Commit a76e7c68 authored by Thomas Kavanagh's avatar Thomas Kavanagh Committed by Wolfram Sang

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: default avatarThomas Kavanagh <tkavanagh@juniper.net>
Signed-off-by: default avatarGuenter Roeck <groeck@juniper.net>
Signed-off-by: default avatarWolfram Sang <w.sang@pengutronix.de>
parent 0c25aefa
...@@ -46,14 +46,19 @@ static int i2c_debug; ...@@ -46,14 +46,19 @@ static int i2c_debug;
#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
#define pca_wait(adap) adap->wait_for_completion(adap->data) #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) static void pca_reset(struct i2c_algo_pca_data *adap)
{ {
struct i2c_algo_pca_data *adap = pd; if (adap->chip == I2C_PCA_CHIP_9665) {
pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); /* Ignore the reset function from the module,
pca_outw(adap, I2C_PCA_IND, 0xA5); * we can use the parallel bus reset.
pca_outw(adap, I2C_PCA_IND, 0x5A); */
pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
pca_outw(adap, I2C_PCA_IND, 0xA5);
pca_outw(adap, I2C_PCA_IND, 0x5A);
} else {
adap->reset_chip(adap->data);
}
} }
/* /*
...@@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap) ...@@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap)
pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {
printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name);
return I2C_PCA_CHIP_9665; pca_data->chip = I2C_PCA_CHIP_9665;
} else { } else {
printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name);
return I2C_PCA_CHIP_9564; pca_data->chip = I2C_PCA_CHIP_9564;
} }
return pca_data->chip;
} }
static int pca_init(struct i2c_adapter *adap) static int pca_init(struct i2c_adapter *adap)
...@@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap) ...@@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap)
*/ */
int raise_fall_time; int raise_fall_time;
/* 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) { if (pca_data->i2c_clock > 1265800) {
printk(KERN_WARNING "%s: I2C clock speed too high." printk(KERN_WARNING "%s: I2C clock speed too high."
" Using 1265.8kHz.\n", adap->name); " Using 1265.8kHz.\n", adap->name);
......
...@@ -62,6 +62,7 @@ struct i2c_algo_pca_data { ...@@ -62,6 +62,7 @@ struct i2c_algo_pca_data {
* 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000 * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000
* For PCA9665, use the frequency you want here. */ * For PCA9665, use the frequency you want here. */
unsigned int i2c_clock; unsigned int i2c_clock;
unsigned int chip;
}; };
int i2c_pca_add_bus(struct i2c_adapter *); int i2c_pca_add_bus(struct i2c_adapter *);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment