#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_2(pcf8574, pcf8574a);
+I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
/* Initial values */
#define PCF8574_INIT 255 /* All outputs on (input mode) */
/* Each client has this additional data */
struct pcf8574_data {
struct i2c_client client;
- struct semaphore update_lock;
- u8 read, write; /* Register values */
+ u8 write; /* Remember last written value */
};
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind);
static int pcf8574_detach_client(struct i2c_client *client);
static void pcf8574_init_client(struct i2c_client *client);
-static struct pcf8574_data *pcf8574_update_client(struct device *dev);
/* This is the driver that will be inserted */
static struct i2c_driver pcf8574_driver = {
- .owner = THIS_MODULE,
- .name = "pcf8574",
+ .driver = {
+ .name = "pcf8574",
+ },
.id = I2C_DRIVERID_PCF8574,
- .flags = I2C_DF_NOTIFY,
.attach_adapter = pcf8574_attach_adapter,
.detach_client = pcf8574_detach_client,
};
-static int pcf8574_id;
-
/* following are the sysfs callback functions */
-static ssize_t show_read(struct device *dev, char *buf)
+static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct pcf8574_data *data = pcf8574_update_client(dev);
- return sprintf(buf, "%u\n", data->read);
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%u\n", i2c_smbus_read_byte(client));
}
static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
-static ssize_t show_write(struct device *dev, char *buf)
+static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%u\n", data->write);
}
-static ssize_t set_write(struct device *dev, const char *buf,
+static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8574_data *data = i2c_get_clientdata(client);
- data->write = simple_strtoul(buf, NULL, 10);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ if (val > 0xff)
+ return -EINVAL;
+
+ data->write = val;
i2c_smbus_write_byte(client, data->write);
return count;
}
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+static struct attribute *pcf8574_attributes[] = {
+ &dev_attr_read.attr,
+ &dev_attr_write.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8574_attr_group = {
+ .attrs = pcf8574_attributes,
+};
+
/*
* Real code
*/
static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, pcf8574_detect);
+ return i2c_probe(adapter, &addr_data, pcf8574_detect);
}
-/* This function is called by i2c_detect */
-int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
+/* This function is called by i2c_probe */
+static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct pcf8574_data *data;
/* 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 = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
+ if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- memset(data, 0, sizeof(struct pcf8574_data));
new_client = &data->client;
i2c_set_clientdata(new_client, data);
/* Fill in the remaining client fields and put it into the global list */
strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
- new_client->id = pcf8574_id++;
- init_MUTEX(&data->update_lock);
-
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
pcf8574_init_client(new_client);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_read);
- device_create_file(&new_client->dev, &dev_attr_write);
+ err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
+ if (err)
+ goto exit_detach;
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
-
+ exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
{
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
kfree(i2c_get_clientdata(client));
return 0;
i2c_smbus_write_byte(client, data->write);
}
-static struct pcf8574_data *pcf8574_update_client(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct pcf8574_data *data = i2c_get_clientdata(client);
-
- down(&data->update_lock);
- dev_dbg(&client->dev, "Starting pcf8574 update\n");
- data->read = i2c_smbus_read_byte(client);
- up(&data->update_lock);
-
- return data;
-}
-
static int __init pcf8574_init(void)
{
return i2c_add_driver(&pcf8574_driver);