--- linux/drivers/i2c/chips/pca9539.c 2005-10-01 00:17:35.000000000 +0300 +++ se95/drivers/i2c/chips/pca9539.c 2005-12-31 19:18:15.000000000 +0200 @@ -3,6 +3,13 @@ Copyright (C) 2005 Ben Gardner + Similar chips added: + pca9538 - 8-bit I/O port + pca9554(a) - 8-bit I/O port + pca9555(a) - 16-bit I/O port - FIXME + pcf8574(a) - 8-bit I/O port - FIXME + Copyright (C) 2005 Tonu Samuel + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. @@ -15,11 +22,28 @@ #include /* Addresses to scan */ -static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END}; +static unsigned short normal_i2c[] = { + /* pca9554 (without A) addresses */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + /* pca9554A addresses */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + /* pca9538 addresses */ + 0x70, 0x71, 0x72, 0x73, + /* pca9539 addresses*/ + 0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END}; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(pca9539); +enum pca9538_cmd +{ + PCA9538_INPUT = 0, + PCA9538_OUTPUT = 1, + PCA9538_INVERT = 2, + PCA9538_DIRECTION = 3, +}; + + enum pca9539_cmd { PCA9539_INPUT_0 = 0, @@ -47,6 +71,7 @@ struct pca9539_data { struct i2c_client client; + int is_pca9538; }; /* following are the sysfs callback functions */ @@ -80,15 +105,30 @@ static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \ pca9539_store, cmd_idx) +PCA9539_ENTRY_RO(input, PCA9538_INPUT); PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0); PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1); + +PCA9539_ENTRY_RW(output, PCA9538_OUTPUT); PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0); PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1); + +PCA9539_ENTRY_RW(invert, PCA9538_INVERT); PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0); PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1); + +PCA9539_ENTRY_RW(direction, PCA9538_DIRECTION); PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0); PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1); +static struct attribute *pca9538_attributes[] = { + &sensor_dev_attr_input.dev_attr.attr, + &sensor_dev_attr_output.dev_attr.attr, + &sensor_dev_attr_invert.dev_attr.attr, + &sensor_dev_attr_direction.dev_attr.attr, + NULL +}; + static struct attribute *pca9539_attributes[] = { &sensor_dev_attr_input0.dev_attr.attr, &sensor_dev_attr_input1.dev_attr.attr, @@ -101,6 +141,10 @@ NULL }; +static struct attribute_group pca9538_defattr_group = { + .attrs = pca9538_attributes, +}; + static struct attribute_group pca9539_defattr_group = { .attrs = pca9539_attributes, }; @@ -136,19 +180,36 @@ new_client->flags = 0; /* Detection: the pca9539 only has 8 registers (0-7). - A read of 7 should succeed, but a read of 8 should fail. */ - if ((i2c_smbus_read_byte_data(new_client, 7) < 0) || - (i2c_smbus_read_byte_data(new_client, 8) >= 0)) + A read of 7 should succeed, but a read of 8 should fail. + If reading 4 fails but 0..3 works, it should be pca9538, + 8-bit younger brother of pca9539 */ + + /* Trying for pca9539 */ + if ((i2c_smbus_read_byte_data(new_client, 7) >= 0) && + (i2c_smbus_read_byte_data(new_client, 8) < 0)) + strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE); + /* Trying for pca9538, pca9554(a) */ + else if ((i2c_smbus_read_byte_data(new_client, 3) >= 0) && + (i2c_smbus_read_byte_data(new_client, 4) < 0)) { + if(address<=0x27) + strlcpy(new_client->name, "pca9554", I2C_NAME_SIZE); + else if(address>=0x48 && address<=0x4f) + strlcpy(new_client->name, "pca9554A", I2C_NAME_SIZE); + else + strlcpy(new_client->name, "pca9538", I2C_NAME_SIZE); + data->is_pca9538=1; + } else goto exit_kfree; - strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE); - /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto exit_kfree; /* Register sysfs hooks (don't care about failure) */ - sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group); + if(data->is_pca9538) + sysfs_create_group(&new_client->dev.kobj, &pca9538_defattr_group); + else + sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group); return 0;