diff options
Diffstat (limited to 'drivers/i2c/chips')
-rw-r--r-- | drivers/i2c/chips/max6875.c | 120 |
1 files changed, 49 insertions, 71 deletions
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 5a0285d8b6f9..033d9d81ec8a 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c | |||
@@ -53,7 +53,7 @@ I2C_CLIENT_INSMOD_1(max6875); | |||
53 | 53 | ||
54 | /* Each client has this additional data */ | 54 | /* Each client has this additional data */ |
55 | struct max6875_data { | 55 | struct max6875_data { |
56 | struct i2c_client client; | 56 | struct i2c_client *fake_client; |
57 | struct mutex update_lock; | 57 | struct mutex update_lock; |
58 | 58 | ||
59 | u32 valid; | 59 | u32 valid; |
@@ -61,19 +61,6 @@ struct max6875_data { | |||
61 | unsigned long last_updated[USER_EEPROM_SLICES]; | 61 | unsigned long last_updated[USER_EEPROM_SLICES]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static int max6875_attach_adapter(struct i2c_adapter *adapter); | ||
65 | static int max6875_detect(struct i2c_adapter *adapter, int address, int kind); | ||
66 | static int max6875_detach_client(struct i2c_client *client); | ||
67 | |||
68 | /* This is the driver that will be inserted */ | ||
69 | static struct i2c_driver max6875_driver = { | ||
70 | .driver = { | ||
71 | .name = "max6875", | ||
72 | }, | ||
73 | .attach_adapter = max6875_attach_adapter, | ||
74 | .detach_client = max6875_detach_client, | ||
75 | }; | ||
76 | |||
77 | static void max6875_update_slice(struct i2c_client *client, int slice) | 64 | static void max6875_update_slice(struct i2c_client *client, int slice) |
78 | { | 65 | { |
79 | struct max6875_data *data = i2c_get_clientdata(client); | 66 | struct max6875_data *data = i2c_get_clientdata(client); |
@@ -159,96 +146,87 @@ static struct bin_attribute user_eeprom_attr = { | |||
159 | .read = max6875_read, | 146 | .read = max6875_read, |
160 | }; | 147 | }; |
161 | 148 | ||
162 | static int max6875_attach_adapter(struct i2c_adapter *adapter) | 149 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
150 | static int max6875_detect(struct i2c_client *client, int kind, | ||
151 | struct i2c_board_info *info) | ||
163 | { | 152 | { |
164 | return i2c_probe(adapter, &addr_data, max6875_detect); | 153 | struct i2c_adapter *adapter = client->adapter; |
165 | } | ||
166 | |||
167 | /* This function is called by i2c_probe */ | ||
168 | static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) | ||
169 | { | ||
170 | struct i2c_client *real_client; | ||
171 | struct i2c_client *fake_client; | ||
172 | struct max6875_data *data; | ||
173 | int err; | ||
174 | 154 | ||
175 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | 155 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
176 | | I2C_FUNC_SMBUS_READ_BYTE)) | 156 | | I2C_FUNC_SMBUS_READ_BYTE)) |
177 | return 0; | 157 | return -ENODEV; |
178 | 158 | ||
179 | /* Only check even addresses */ | 159 | /* Only check even addresses */ |
180 | if (address & 1) | 160 | if (client->addr & 1) |
181 | return 0; | 161 | return -ENODEV; |
162 | |||
163 | strlcpy(info->type, "max6875", I2C_NAME_SIZE); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int max6875_probe(struct i2c_client *client, | ||
169 | const struct i2c_device_id *id) | ||
170 | { | ||
171 | struct max6875_data *data; | ||
172 | int err; | ||
182 | 173 | ||
183 | if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) | 174 | if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) |
184 | return -ENOMEM; | 175 | return -ENOMEM; |
185 | 176 | ||
186 | /* A fake client is created on the odd address */ | 177 | /* A fake client is created on the odd address */ |
187 | if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { | 178 | data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); |
179 | if (!data->fake_client) { | ||
188 | err = -ENOMEM; | 180 | err = -ENOMEM; |
189 | goto exit_kfree1; | 181 | goto exit_kfree; |
190 | } | 182 | } |
191 | 183 | ||
192 | /* Init real i2c_client */ | 184 | /* Init real i2c_client */ |
193 | real_client = &data->client; | 185 | i2c_set_clientdata(client, data); |
194 | i2c_set_clientdata(real_client, data); | ||
195 | real_client->addr = address; | ||
196 | real_client->adapter = adapter; | ||
197 | real_client->driver = &max6875_driver; | ||
198 | strlcpy(real_client->name, "max6875", I2C_NAME_SIZE); | ||
199 | mutex_init(&data->update_lock); | 186 | mutex_init(&data->update_lock); |
200 | 187 | ||
201 | /* Init fake client data */ | 188 | err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); |
202 | i2c_set_clientdata(fake_client, NULL); | ||
203 | fake_client->addr = address | 1; | ||
204 | fake_client->adapter = adapter; | ||
205 | fake_client->driver = &max6875_driver; | ||
206 | strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE); | ||
207 | |||
208 | if ((err = i2c_attach_client(real_client)) != 0) | ||
209 | goto exit_kfree2; | ||
210 | |||
211 | if ((err = i2c_attach_client(fake_client)) != 0) | ||
212 | goto exit_detach1; | ||
213 | |||
214 | err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr); | ||
215 | if (err) | 189 | if (err) |
216 | goto exit_detach2; | 190 | goto exit_remove_fake; |
217 | 191 | ||
218 | return 0; | 192 | return 0; |
219 | 193 | ||
220 | exit_detach2: | 194 | exit_remove_fake: |
221 | i2c_detach_client(fake_client); | 195 | i2c_unregister_device(data->fake_client); |
222 | exit_detach1: | 196 | exit_kfree: |
223 | i2c_detach_client(real_client); | ||
224 | exit_kfree2: | ||
225 | kfree(fake_client); | ||
226 | exit_kfree1: | ||
227 | kfree(data); | 197 | kfree(data); |
228 | return err; | 198 | return err; |
229 | } | 199 | } |
230 | 200 | ||
231 | /* Will be called for both the real client and the fake client */ | 201 | static int max6875_remove(struct i2c_client *client) |
232 | static int max6875_detach_client(struct i2c_client *client) | ||
233 | { | 202 | { |
234 | int err; | ||
235 | struct max6875_data *data = i2c_get_clientdata(client); | 203 | struct max6875_data *data = i2c_get_clientdata(client); |
236 | 204 | ||
237 | /* data is NULL for the fake client */ | 205 | i2c_unregister_device(data->fake_client); |
238 | if (data) | ||
239 | sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); | ||
240 | 206 | ||
241 | err = i2c_detach_client(client); | 207 | sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); |
242 | if (err) | 208 | kfree(data); |
243 | return err; | ||
244 | 209 | ||
245 | if (data) /* real client */ | ||
246 | kfree(data); | ||
247 | else /* fake client */ | ||
248 | kfree(client); | ||
249 | return 0; | 210 | return 0; |
250 | } | 211 | } |
251 | 212 | ||
213 | static const struct i2c_device_id max6875_id[] = { | ||
214 | { "max6875", 0 }, | ||
215 | { } | ||
216 | }; | ||
217 | |||
218 | static struct i2c_driver max6875_driver = { | ||
219 | .driver = { | ||
220 | .name = "max6875", | ||
221 | }, | ||
222 | .probe = max6875_probe, | ||
223 | .remove = max6875_remove, | ||
224 | .id_table = max6875_id, | ||
225 | |||
226 | .detect = max6875_detect, | ||
227 | .address_data = &addr_data, | ||
228 | }; | ||
229 | |||
252 | static int __init max6875_init(void) | 230 | static int __init max6875_init(void) |
253 | { | 231 | { |
254 | return i2c_add_driver(&max6875_driver); | 232 | return i2c_add_driver(&max6875_driver); |