Skip to content

Commit

Permalink
i2c: Convert the pca9539 driver to a new-style i2c driver
Browse files Browse the repository at this point in the history
The new-style pca9539 driver implements the optional detect() callback
to cover the use cases of the legacy driver.

Warning: users will now have to use the force module parameter to get
the driver to attach to their device. That's not a bad thing as these
devices can't be detected anyway.

Note that this doesn't change the fact that this driver is deprecated
in favor of gpio/pca953x.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
  • Loading branch information
Jean Delvare authored and Jean Delvare committed Jul 16, 2008
1 parent 97addff commit 3d63430
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 77 deletions.
10 changes: 9 additions & 1 deletion Documentation/i2c/chips/pca9539
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ drivers/gpio/pca9539.c instead.
Supported chips:
* Philips PCA9539
Prefix: 'pca9539'
Addresses scanned: 0x74 - 0x77
Addresses scanned: none
Datasheet:
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf

Expand All @@ -23,6 +23,14 @@ The input sense can also be inverted.
The 16 lines are split between two bytes.


Detection
---------

The PCA9539 is difficult to detect and not commonly found in PC machines,
so you have to pass the I2C bus and address of the installed PCA9539
devices explicitly to the driver at load time via the force=... parameter.


Sysfs entries
-------------

Expand Down
109 changes: 33 additions & 76 deletions drivers/i2c/chips/pca9539.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>

/* Addresses to scan */
static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
/* Addresses to scan: none, device is not autodetected */
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };

/* Insmod parameters */
I2C_CLIENT_INSMOD_1(pca9539);
Expand All @@ -32,23 +32,6 @@ enum pca9539_cmd
PCA9539_DIRECTION_1 = 7,
};

static int pca9539_attach_adapter(struct i2c_adapter *adapter);
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind);
static int pca9539_detach_client(struct i2c_client *client);

/* This is the driver that will be inserted */
static struct i2c_driver pca9539_driver = {
.driver = {
.name = "pca9539",
},
.attach_adapter = pca9539_attach_adapter,
.detach_client = pca9539_detach_client,
};

struct pca9539_data {
struct i2c_client client;
};

/* following are the sysfs callback functions */
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
char *buf)
Expand Down Expand Up @@ -105,77 +88,51 @@ static struct attribute_group pca9539_defattr_group = {
.attrs = pca9539_attributes,
};

static int pca9539_attach_adapter(struct i2c_adapter *adapter)
/* Return 0 if detection is successful, -ENODEV otherwise */
static int pca9539_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
return i2c_probe(adapter, &addr_data, pca9539_detect);
}

/* This function is called by i2c_probe */
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *client;
struct pca9539_data *data;
int err = 0;
struct i2c_adapter *adapter = client->adapter;

if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto exit;

/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet. */
if (!(data = kzalloc(sizeof(struct pca9539_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}

client = &data->client;
i2c_set_clientdata(client, data);
client->addr = address;
client->adapter = adapter;
client->driver = &pca9539_driver;

if (kind < 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(client, 7) < 0) ||
(i2c_smbus_read_byte_data(client, 8) >= 0))
goto exit_kfree;
}

strlcpy(client->name, "pca9539", I2C_NAME_SIZE);

/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(client)))
goto exit_kfree;
return -ENODEV;

/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj,
&pca9539_defattr_group);
if (err)
goto exit_detach;
strlcpy(info->type, "pca9539", I2C_NAME_SIZE);

return 0;

exit_detach:
i2c_detach_client(client);
exit_kfree:
kfree(data);
exit:
return err;
}

static int pca9539_detach_client(struct i2c_client *client)
static int pca9539_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
/* Register sysfs hooks */
return sysfs_create_group(&client->dev.kobj,
&pca9539_defattr_group);
}

static int pca9539_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);

if ((err = i2c_detach_client(client)))
return err;

kfree(i2c_get_clientdata(client));
return 0;
}

static const struct i2c_device_id pca9539_id[] = {
{ "pca9539", 0 },
{ }
};

static struct i2c_driver pca9539_driver = {
.driver = {
.name = "pca9539",
},
.probe = pca9539_probe,
.remove = pca9539_remove,
.id_table = pca9539_id,

.detect = pca9539_detect,
.address_data = &addr_data,
};

static int __init pca9539_init(void)
{
return i2c_add_driver(&pca9539_driver);
Expand Down

0 comments on commit 3d63430

Please sign in to comment.