From mboxrd@z Thu Jan 1 00:00:00 1970 From: Guenter Roeck Subject: [PATCH 1/2] i2c: (algo-pca) Fix chip reset function for PCA9665 Date: Wed, 12 Sep 2012 20:39:50 -0700 Message-ID: <1347507591-32352-1-git-send-email-linux@roeck-us.net> Return-path: Sender: linux-i2c-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org To: Jean Delvare , Ben Dooks Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Thomas Kavanagh , Wolfram Sang , Guenter Roeck List-Id: linux-i2c@vger.kernel.org From: Thomas Kavanagh The parameter passed to pca9665_reset is adap->data, not adap. Unless adap->data happens to point back to adap, this can result in a kernel panic. Fix re-factoring pca_reset() from a macro to a function to handle chip specific code, and only call adap->reset_chip() if the chip is not PCA9665. Cc: Wolfram Sang Signed-off-by: Thomas Kavanagh Signed-off-by: Guenter Roeck --- drivers/i2c/algos/i2c-algo-pca.c | 27 ++++++++++++++------------- include/linux/i2c-algo-pca.h | 1 + 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 73133b1..07ccbef 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; #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_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; - pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); - pca_outw(adap, I2C_PCA_IND, 0xA5); - pca_outw(adap, I2C_PCA_IND, 0x5A); + if (adap->chip == I2C_PCA_CHIP_9665) { + /* Ignore the reset function from the module, + * we can use the parallel bus reset. + */ + 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) 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; + pca_data->chip = I2C_PCA_CHIP_9665; } else { 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) @@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap) */ 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) { printk(KERN_WARNING "%s: I2C clock speed too high." " Using 1265.8kHz.\n", adap->name); diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h index 1364d62..a3c3ecd 100644 --- a/include/linux/i2c-algo-pca.h +++ b/include/linux/i2c-algo-pca.h @@ -62,6 +62,7 @@ struct i2c_algo_pca_data { * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000 * For PCA9665, use the frequency you want here. */ unsigned int i2c_clock; + unsigned int chip; }; int i2c_pca_add_bus(struct i2c_adapter *); -- 1.7.9.7