Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Thomas Kavanagh and committed by
Wolfram Sang
a76e7c68 0c25aefa

+15 -13
+14 -13
drivers/i2c/algos/i2c-algo-pca.c
··· 46 46 #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) 47 47 #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) 48 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; 54 - pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); 55 - pca_outw(adap, I2C_PCA_IND, 0xA5); 56 - pca_outw(adap, I2C_PCA_IND, 0x5A); 52 + if (adap->chip == I2C_PCA_CHIP_9665) { 53 + /* Ignore the reset function from the module, 54 + * we can use the parallel bus reset. 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 /* ··· 383 378 pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); 384 379 if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { 385 380 printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); 386 - return I2C_PCA_CHIP_9665; 381 + pca_data->chip = I2C_PCA_CHIP_9665; 387 382 } else { 388 383 printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); 389 - return I2C_PCA_CHIP_9564; 384 + pca_data->chip = I2C_PCA_CHIP_9564; 390 385 } 386 + return pca_data->chip; 391 387 } 392 388 393 389 static int pca_init(struct i2c_adapter *adap) ··· 461 455 * maximum clock rate for each mode 462 456 */ 463 457 int raise_fall_time; 464 - 465 - /* Ignore the reset function from the module, 466 - * we can use the parallel bus reset 467 - */ 468 - pca_data->reset_chip = pca9665_reset; 469 458 470 459 if (pca_data->i2c_clock > 1265800) { 471 460 printk(KERN_WARNING "%s: I2C clock speed too high."
+1
include/linux/i2c-algo-pca.h
··· 62 62 * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000 63 63 * For PCA9665, use the frequency you want here. */ 64 64 unsigned int i2c_clock; 65 + unsigned int chip; 65 66 }; 66 67 67 68 int i2c_pca_add_bus(struct i2c_adapter *);