diff options
author | Jean Delvare <khali@linux-fr.org> | 2008-07-16 13:30:11 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-07-16 13:30:11 -0400 |
commit | 70313eabfc63ce6aa89b9fa3074129e5c521568a (patch) | |
tree | 362be8042de4fc25eac21908cdf3921824479997 /drivers/hwmon/ds1621.c | |
parent | 71163c7c36fa76bb5a72feca7fb685677444070a (diff) |
hwmon: (ds1621) Convert to a new-style i2c driver
The new-style ds1621 driver implements the optional detect() callback
to cover the use cases of the legacy driver.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/ds1621.c')
-rw-r--r-- | drivers/hwmon/ds1621.c | 99 |
1 files changed, 47 insertions, 52 deletions
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 5f300ffed657..7415381601c3 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c | |||
@@ -72,7 +72,6 @@ static const u8 DS1621_REG_TEMP[3] = { | |||
72 | 72 | ||
73 | /* Each client has this additional data */ | 73 | /* Each client has this additional data */ |
74 | struct ds1621_data { | 74 | struct ds1621_data { |
75 | struct i2c_client client; | ||
76 | struct device *hwmon_dev; | 75 | struct device *hwmon_dev; |
77 | struct mutex update_lock; | 76 | struct mutex update_lock; |
78 | char valid; /* !=0 if following fields are valid */ | 77 | char valid; /* !=0 if following fields are valid */ |
@@ -82,20 +81,32 @@ struct ds1621_data { | |||
82 | u8 conf; /* Register encoding, combined */ | 81 | u8 conf; /* Register encoding, combined */ |
83 | }; | 82 | }; |
84 | 83 | ||
85 | static int ds1621_attach_adapter(struct i2c_adapter *adapter); | 84 | static int ds1621_probe(struct i2c_client *client, |
86 | static int ds1621_detect(struct i2c_adapter *adapter, int address, | 85 | const struct i2c_device_id *id); |
87 | int kind); | 86 | static int ds1621_detect(struct i2c_client *client, int kind, |
87 | struct i2c_board_info *info); | ||
88 | static void ds1621_init_client(struct i2c_client *client); | 88 | static void ds1621_init_client(struct i2c_client *client); |
89 | static int ds1621_detach_client(struct i2c_client *client); | 89 | static int ds1621_remove(struct i2c_client *client); |
90 | static struct ds1621_data *ds1621_update_client(struct device *dev); | 90 | static struct ds1621_data *ds1621_update_client(struct device *dev); |
91 | 91 | ||
92 | static const struct i2c_device_id ds1621_id[] = { | ||
93 | { "ds1621", ds1621 }, | ||
94 | { "ds1625", ds1621 }, | ||
95 | { } | ||
96 | }; | ||
97 | MODULE_DEVICE_TABLE(i2c, ds1621_id); | ||
98 | |||
92 | /* This is the driver that will be inserted */ | 99 | /* This is the driver that will be inserted */ |
93 | static struct i2c_driver ds1621_driver = { | 100 | static struct i2c_driver ds1621_driver = { |
101 | .class = I2C_CLASS_HWMON, | ||
94 | .driver = { | 102 | .driver = { |
95 | .name = "ds1621", | 103 | .name = "ds1621", |
96 | }, | 104 | }, |
97 | .attach_adapter = ds1621_attach_adapter, | 105 | .probe = ds1621_probe, |
98 | .detach_client = ds1621_detach_client, | 106 | .remove = ds1621_remove, |
107 | .id_table = ds1621_id, | ||
108 | .detect = ds1621_detect, | ||
109 | .address_data = &addr_data, | ||
99 | }; | 110 | }; |
100 | 111 | ||
101 | /* All registers are word-sized, except for the configuration register. | 112 | /* All registers are word-sized, except for the configuration register. |
@@ -199,40 +210,18 @@ static const struct attribute_group ds1621_group = { | |||
199 | }; | 210 | }; |
200 | 211 | ||
201 | 212 | ||
202 | static int ds1621_attach_adapter(struct i2c_adapter *adapter) | 213 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
203 | { | 214 | static int ds1621_detect(struct i2c_client *client, int kind, |
204 | if (!(adapter->class & I2C_CLASS_HWMON)) | 215 | struct i2c_board_info *info) |
205 | return 0; | ||
206 | return i2c_probe(adapter, &addr_data, ds1621_detect); | ||
207 | } | ||
208 | |||
209 | /* This function is called by i2c_probe */ | ||
210 | static int ds1621_detect(struct i2c_adapter *adapter, int address, | ||
211 | int kind) | ||
212 | { | 216 | { |
217 | struct i2c_adapter *adapter = client->adapter; | ||
213 | int conf, temp; | 218 | int conf, temp; |
214 | struct i2c_client *client; | 219 | int i; |
215 | struct ds1621_data *data; | ||
216 | int i, err = 0; | ||
217 | 220 | ||
218 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | 221 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
219 | | I2C_FUNC_SMBUS_WORD_DATA | 222 | | I2C_FUNC_SMBUS_WORD_DATA |
220 | | I2C_FUNC_SMBUS_WRITE_BYTE)) | 223 | | I2C_FUNC_SMBUS_WRITE_BYTE)) |
221 | goto exit; | 224 | return -ENODEV; |
222 | |||
223 | /* OK. For now, we presume we have a valid client. We now create the | ||
224 | client structure, even though we cannot fill it completely yet. | ||
225 | But it allows us to access ds1621_{read,write}_value. */ | ||
226 | if (!(data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { | ||
227 | err = -ENOMEM; | ||
228 | goto exit; | ||
229 | } | ||
230 | |||
231 | client = &data->client; | ||
232 | i2c_set_clientdata(client, data); | ||
233 | client->addr = address; | ||
234 | client->adapter = adapter; | ||
235 | client->driver = &ds1621_driver; | ||
236 | 225 | ||
237 | /* Now, we do the remaining detection. It is lousy. */ | 226 | /* Now, we do the remaining detection. It is lousy. */ |
238 | if (kind < 0) { | 227 | if (kind < 0) { |
@@ -241,29 +230,41 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address, | |||
241 | improbable in our case. */ | 230 | improbable in our case. */ |
242 | conf = ds1621_read_value(client, DS1621_REG_CONF); | 231 | conf = ds1621_read_value(client, DS1621_REG_CONF); |
243 | if (conf & DS1621_REG_CONFIG_NVB) | 232 | if (conf & DS1621_REG_CONFIG_NVB) |
244 | goto exit_free; | 233 | return -ENODEV; |
245 | /* The 7 lowest bits of a temperature should always be 0. */ | 234 | /* The 7 lowest bits of a temperature should always be 0. */ |
246 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) { | 235 | for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) { |
247 | temp = ds1621_read_value(client, DS1621_REG_TEMP[i]); | 236 | temp = ds1621_read_value(client, DS1621_REG_TEMP[i]); |
248 | if (temp & 0x007f) | 237 | if (temp & 0x007f) |
249 | goto exit_free; | 238 | return -ENODEV; |
250 | } | 239 | } |
251 | } | 240 | } |
252 | 241 | ||
253 | /* Fill in remaining client fields and put it into the global list */ | 242 | strlcpy(info->type, "ds1621", I2C_NAME_SIZE); |
254 | strlcpy(client->name, "ds1621", I2C_NAME_SIZE); | ||
255 | mutex_init(&data->update_lock); | ||
256 | 243 | ||
257 | /* Tell the I2C layer a new client has arrived */ | 244 | return 0; |
258 | if ((err = i2c_attach_client(client))) | 245 | } |
259 | goto exit_free; | 246 | |
247 | static int ds1621_probe(struct i2c_client *client, | ||
248 | const struct i2c_device_id *id) | ||
249 | { | ||
250 | struct ds1621_data *data; | ||
251 | int err; | ||
252 | |||
253 | data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL); | ||
254 | if (!data) { | ||
255 | err = -ENOMEM; | ||
256 | goto exit; | ||
257 | } | ||
258 | |||
259 | i2c_set_clientdata(client, data); | ||
260 | mutex_init(&data->update_lock); | ||
260 | 261 | ||
261 | /* Initialize the DS1621 chip */ | 262 | /* Initialize the DS1621 chip */ |
262 | ds1621_init_client(client); | 263 | ds1621_init_client(client); |
263 | 264 | ||
264 | /* Register sysfs hooks */ | 265 | /* Register sysfs hooks */ |
265 | if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group))) | 266 | if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group))) |
266 | goto exit_detach; | 267 | goto exit_free; |
267 | 268 | ||
268 | data->hwmon_dev = hwmon_device_register(&client->dev); | 269 | data->hwmon_dev = hwmon_device_register(&client->dev); |
269 | if (IS_ERR(data->hwmon_dev)) { | 270 | if (IS_ERR(data->hwmon_dev)) { |
@@ -275,25 +276,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address, | |||
275 | 276 | ||
276 | exit_remove_files: | 277 | exit_remove_files: |
277 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); | 278 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); |
278 | exit_detach: | ||
279 | i2c_detach_client(client); | ||
280 | exit_free: | 279 | exit_free: |
281 | kfree(data); | 280 | kfree(data); |
282 | exit: | 281 | exit: |
283 | return err; | 282 | return err; |
284 | } | 283 | } |
285 | 284 | ||
286 | static int ds1621_detach_client(struct i2c_client *client) | 285 | static int ds1621_remove(struct i2c_client *client) |
287 | { | 286 | { |
288 | struct ds1621_data *data = i2c_get_clientdata(client); | 287 | struct ds1621_data *data = i2c_get_clientdata(client); |
289 | int err; | ||
290 | 288 | ||
291 | hwmon_device_unregister(data->hwmon_dev); | 289 | hwmon_device_unregister(data->hwmon_dev); |
292 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); | 290 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); |
293 | 291 | ||
294 | if ((err = i2c_detach_client(client))) | ||
295 | return err; | ||
296 | |||
297 | kfree(data); | 292 | kfree(data); |
298 | 293 | ||
299 | return 0; | 294 | return 0; |