diff options
-rw-r--r-- | Documentation/i2c/chips/pcf8575 | 9 | ||||
-rw-r--r-- | drivers/i2c/chips/pcf8575.c | 96 |
2 files changed, 43 insertions, 62 deletions
diff --git a/Documentation/i2c/chips/pcf8575 b/Documentation/i2c/chips/pcf8575 index 25f5698a61cf..40b268eb276f 100644 --- a/Documentation/i2c/chips/pcf8575 +++ b/Documentation/i2c/chips/pcf8575 | |||
@@ -40,12 +40,9 @@ Detection | |||
40 | --------- | 40 | --------- |
41 | 41 | ||
42 | There is no method known to detect whether a chip on a given I2C address is | 42 | There is no method known to detect whether a chip on a given I2C address is |
43 | a PCF8575 or whether it is any other I2C device. So there are two alternatives | 43 | a PCF8575 or whether it is any other I2C device, so you have to pass the I2C |
44 | to let the driver find the installed PCF8575 devices: | 44 | bus and address of the installed PCF8575 devices explicitly to the driver at |
45 | - Load this driver after any other I2C driver for I2C devices with addresses | 45 | load time via the force=... parameter. |
46 | in the range 0x20 .. 0x27. | ||
47 | - Pass the I2C bus and address of the installed PCF8575 devices explicitly to | ||
48 | the driver at load time via the probe=... or force=... parameters. | ||
49 | 46 | ||
50 | /sys interface | 47 | /sys interface |
51 | -------------- | 48 | -------------- |
diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c index 3ea08ac0bfa3..07fd7cb3c57d 100644 --- a/drivers/i2c/chips/pcf8575.c +++ b/drivers/i2c/chips/pcf8575.c | |||
@@ -32,11 +32,8 @@ | |||
32 | #include <linux/slab.h> /* kzalloc() */ | 32 | #include <linux/slab.h> /* kzalloc() */ |
33 | #include <linux/sysfs.h> /* sysfs_create_group() */ | 33 | #include <linux/sysfs.h> /* sysfs_create_group() */ |
34 | 34 | ||
35 | /* Addresses to scan */ | 35 | /* Addresses to scan: none, device can't be detected */ |
36 | static const unsigned short normal_i2c[] = { | 36 | static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; |
37 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
38 | I2C_CLIENT_END | ||
39 | }; | ||
40 | 37 | ||
41 | /* Insmod parameters */ | 38 | /* Insmod parameters */ |
42 | I2C_CLIENT_INSMOD; | 39 | I2C_CLIENT_INSMOD; |
@@ -44,24 +41,9 @@ I2C_CLIENT_INSMOD; | |||
44 | 41 | ||
45 | /* Each client has this additional data */ | 42 | /* Each client has this additional data */ |
46 | struct pcf8575_data { | 43 | struct pcf8575_data { |
47 | struct i2c_client client; | ||
48 | int write; /* last written value, or error code */ | 44 | int write; /* last written value, or error code */ |
49 | }; | 45 | }; |
50 | 46 | ||
51 | static int pcf8575_attach_adapter(struct i2c_adapter *adapter); | ||
52 | static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind); | ||
53 | static int pcf8575_detach_client(struct i2c_client *client); | ||
54 | |||
55 | /* This is the driver that will be inserted */ | ||
56 | static struct i2c_driver pcf8575_driver = { | ||
57 | .driver = { | ||
58 | .owner = THIS_MODULE, | ||
59 | .name = "pcf8575", | ||
60 | }, | ||
61 | .attach_adapter = pcf8575_attach_adapter, | ||
62 | .detach_client = pcf8575_detach_client, | ||
63 | }; | ||
64 | |||
65 | /* following are the sysfs callback functions */ | 47 | /* following are the sysfs callback functions */ |
66 | static ssize_t show_read(struct device *dev, struct device_attribute *attr, | 48 | static ssize_t show_read(struct device *dev, struct device_attribute *attr, |
67 | char *buf) | 49 | char *buf) |
@@ -126,75 +108,77 @@ static const struct attribute_group pcf8575_attr_group = { | |||
126 | * Real code | 108 | * Real code |
127 | */ | 109 | */ |
128 | 110 | ||
129 | static int pcf8575_attach_adapter(struct i2c_adapter *adapter) | 111 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
112 | static int pcf8575_detect(struct i2c_client *client, int kind, | ||
113 | struct i2c_board_info *info) | ||
130 | { | 114 | { |
131 | return i2c_probe(adapter, &addr_data, pcf8575_detect); | 115 | struct i2c_adapter *adapter = client->adapter; |
116 | |||
117 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | ||
118 | return -ENODEV; | ||
119 | |||
120 | /* This is the place to detect whether the chip at the specified | ||
121 | address really is a PCF8575 chip. However, there is no method known | ||
122 | to detect whether an I2C chip is a PCF8575 or any other I2C chip. */ | ||
123 | |||
124 | strlcpy(info->type, "pcf8575", I2C_NAME_SIZE); | ||
125 | |||
126 | return 0; | ||
132 | } | 127 | } |
133 | 128 | ||
134 | /* This function is called by i2c_probe */ | 129 | static int pcf8575_probe(struct i2c_client *client, |
135 | static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind) | 130 | const struct i2c_device_id *id) |
136 | { | 131 | { |
137 | struct i2c_client *client; | ||
138 | struct pcf8575_data *data; | 132 | struct pcf8575_data *data; |
139 | int err = 0; | 133 | int err; |
140 | |||
141 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | ||
142 | goto exit; | ||
143 | 134 | ||
144 | /* OK. For now, we presume we have a valid client. We now create the | ||
145 | client structure, even though we cannot fill it completely yet. */ | ||
146 | data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL); | 135 | data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL); |
147 | if (!data) { | 136 | if (!data) { |
148 | err = -ENOMEM; | 137 | err = -ENOMEM; |
149 | goto exit; | 138 | goto exit; |
150 | } | 139 | } |
151 | 140 | ||
152 | client = &data->client; | ||
153 | i2c_set_clientdata(client, data); | 141 | i2c_set_clientdata(client, data); |
154 | client->addr = address; | ||
155 | client->adapter = adapter; | ||
156 | client->driver = &pcf8575_driver; | ||
157 | strlcpy(client->name, "pcf8575", I2C_NAME_SIZE); | ||
158 | data->write = -EAGAIN; | 142 | data->write = -EAGAIN; |
159 | 143 | ||
160 | /* This is the place to detect whether the chip at the specified | ||
161 | address really is a PCF8575 chip. However, there is no method known | ||
162 | to detect whether an I2C chip is a PCF8575 or any other I2C chip. */ | ||
163 | |||
164 | /* Tell the I2C layer a new client has arrived */ | ||
165 | err = i2c_attach_client(client); | ||
166 | if (err) | ||
167 | goto exit_free; | ||
168 | |||
169 | /* Register sysfs hooks */ | 144 | /* Register sysfs hooks */ |
170 | err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group); | 145 | err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group); |
171 | if (err) | 146 | if (err) |
172 | goto exit_detach; | 147 | goto exit_free; |
173 | 148 | ||
174 | return 0; | 149 | return 0; |
175 | 150 | ||
176 | exit_detach: | ||
177 | i2c_detach_client(client); | ||
178 | exit_free: | 151 | exit_free: |
179 | kfree(data); | 152 | kfree(data); |
180 | exit: | 153 | exit: |
181 | return err; | 154 | return err; |
182 | } | 155 | } |
183 | 156 | ||
184 | static int pcf8575_detach_client(struct i2c_client *client) | 157 | static int pcf8575_remove(struct i2c_client *client) |
185 | { | 158 | { |
186 | int err; | ||
187 | |||
188 | sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group); | 159 | sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group); |
189 | |||
190 | err = i2c_detach_client(client); | ||
191 | if (err) | ||
192 | return err; | ||
193 | |||
194 | kfree(i2c_get_clientdata(client)); | 160 | kfree(i2c_get_clientdata(client)); |
195 | return 0; | 161 | return 0; |
196 | } | 162 | } |
197 | 163 | ||
164 | static const struct i2c_device_id pcf8575_id[] = { | ||
165 | { "pcf8575", 0 }, | ||
166 | { } | ||
167 | }; | ||
168 | |||
169 | static struct i2c_driver pcf8575_driver = { | ||
170 | .driver = { | ||
171 | .owner = THIS_MODULE, | ||
172 | .name = "pcf8575", | ||
173 | }, | ||
174 | .probe = pcf8575_probe, | ||
175 | .remove = pcf8575_remove, | ||
176 | .id_table = pcf8575_id, | ||
177 | |||
178 | .detect = pcf8575_detect, | ||
179 | .address_data = &addr_data, | ||
180 | }; | ||
181 | |||
198 | static int __init pcf8575_init(void) | 182 | static int __init pcf8575_init(void) |
199 | { | 183 | { |
200 | return i2c_add_driver(&pcf8575_driver); | 184 | return i2c_add_driver(&pcf8575_driver); |