diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/hwmon/ds1621.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/hwmon/ds1621.c')
-rw-r--r-- | drivers/hwmon/ds1621.c | 129 |
1 files changed, 78 insertions, 51 deletions
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 1c568736baf..e11363467a8 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c | |||
@@ -1,25 +1,25 @@ | |||
1 | /* | 1 | /* |
2 | * ds1621.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | ds1621.c - Part of lm_sensors, Linux kernel modules for hardware |
3 | * monitoring | 3 | monitoring |
4 | * Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23 | 4 | Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23 |
5 | * based on lm75.c by Frodo Looijaard <frodol@dds.nl> | 5 | based on lm75.c by Frodo Looijaard <frodol@dds.nl> |
6 | * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with | 6 | Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with |
7 | * the help of Jean Delvare <khali@linux-fr.org> | 7 | the help of Jean Delvare <khali@linux-fr.org> |
8 | * | 8 | |
9 | * This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or | 11 | the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. | 12 | (at your option) any later version. |
13 | * | 13 | |
14 | * This program is distributed in the hope that it will be useful, | 14 | This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. | 17 | GNU General Public License for more details. |
18 | * | 18 | |
19 | * You should have received a copy of the GNU General Public License | 19 | You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
@@ -67,7 +67,7 @@ static const u8 DS1621_REG_TEMP[3] = { | |||
67 | 67 | ||
68 | /* Conversions */ | 68 | /* Conversions */ |
69 | #define ALARMS_FROM_REG(val) ((val) & \ | 69 | #define ALARMS_FROM_REG(val) ((val) & \ |
70 | (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) | 70 | (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) |
71 | 71 | ||
72 | /* Each client has this additional data */ | 72 | /* Each client has this additional data */ |
73 | struct ds1621_data { | 73 | struct ds1621_data { |
@@ -80,6 +80,24 @@ struct ds1621_data { | |||
80 | u8 conf; /* Register encoding, combined */ | 80 | u8 conf; /* Register encoding, combined */ |
81 | }; | 81 | }; |
82 | 82 | ||
83 | /* Temperature registers are word-sized. | ||
84 | DS1621 uses a high-byte first convention, which is exactly opposite to | ||
85 | the SMBus standard. */ | ||
86 | static int ds1621_read_temp(struct i2c_client *client, u8 reg) | ||
87 | { | ||
88 | int ret; | ||
89 | |||
90 | ret = i2c_smbus_read_word_data(client, reg); | ||
91 | if (ret < 0) | ||
92 | return ret; | ||
93 | return swab16(ret); | ||
94 | } | ||
95 | |||
96 | static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value) | ||
97 | { | ||
98 | return i2c_smbus_write_word_data(client, reg, swab16(value)); | ||
99 | } | ||
100 | |||
83 | static void ds1621_init_client(struct i2c_client *client) | 101 | static void ds1621_init_client(struct i2c_client *client) |
84 | { | 102 | { |
85 | u8 conf, new_conf; | 103 | u8 conf, new_conf; |
@@ -93,10 +111,10 @@ static void ds1621_init_client(struct i2c_client *client) | |||
93 | new_conf &= ~DS1621_REG_CONFIG_POLARITY; | 111 | new_conf &= ~DS1621_REG_CONFIG_POLARITY; |
94 | else if (polarity == 1) | 112 | else if (polarity == 1) |
95 | new_conf |= DS1621_REG_CONFIG_POLARITY; | 113 | new_conf |= DS1621_REG_CONFIG_POLARITY; |
96 | 114 | ||
97 | if (conf != new_conf) | 115 | if (conf != new_conf) |
98 | i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); | 116 | i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); |
99 | 117 | ||
100 | /* start conversion */ | 118 | /* start conversion */ |
101 | i2c_smbus_write_byte(client, DS1621_COM_START); | 119 | i2c_smbus_write_byte(client, DS1621_COM_START); |
102 | } | 120 | } |
@@ -118,7 +136,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev) | |||
118 | data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); | 136 | data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); |
119 | 137 | ||
120 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) | 138 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) |
121 | data->temp[i] = i2c_smbus_read_word_swapped(client, | 139 | data->temp[i] = ds1621_read_temp(client, |
122 | DS1621_REG_TEMP[i]); | 140 | DS1621_REG_TEMP[i]); |
123 | 141 | ||
124 | /* reset alarms if necessary */ | 142 | /* reset alarms if necessary */ |
@@ -155,17 +173,12 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, | |||
155 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | 173 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
156 | struct i2c_client *client = to_i2c_client(dev); | 174 | struct i2c_client *client = to_i2c_client(dev); |
157 | struct ds1621_data *data = i2c_get_clientdata(client); | 175 | struct ds1621_data *data = i2c_get_clientdata(client); |
158 | long val; | 176 | u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); |
159 | int err; | ||
160 | |||
161 | err = kstrtol(buf, 10, &val); | ||
162 | if (err) | ||
163 | return err; | ||
164 | 177 | ||
165 | mutex_lock(&data->update_lock); | 178 | mutex_lock(&data->update_lock); |
166 | data->temp[attr->index] = LM75_TEMP_TO_REG(val); | 179 | data->temp[attr->index] = val; |
167 | i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index], | 180 | ds1621_write_temp(client, DS1621_REG_TEMP[attr->index], |
168 | data->temp[attr->index]); | 181 | data->temp[attr->index]); |
169 | mutex_unlock(&data->update_lock); | 182 | mutex_unlock(&data->update_lock); |
170 | return count; | 183 | return count; |
171 | } | 184 | } |
@@ -217,17 +230,14 @@ static int ds1621_detect(struct i2c_client *client, | |||
217 | int conf, temp; | 230 | int conf, temp; |
218 | int i; | 231 | int i; |
219 | 232 | ||
220 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | 233 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
221 | | I2C_FUNC_SMBUS_WORD_DATA | 234 | | I2C_FUNC_SMBUS_WORD_DATA |
222 | | I2C_FUNC_SMBUS_WRITE_BYTE)) | 235 | | I2C_FUNC_SMBUS_WRITE_BYTE)) |
223 | return -ENODEV; | 236 | return -ENODEV; |
224 | 237 | ||
225 | /* | 238 | /* Now, we do the remaining detection. It is lousy. */ |
226 | * Now, we do the remaining detection. It is lousy. | 239 | /* The NVB bit should be low if no EEPROM write has been requested |
227 | * | 240 | during the latest 10ms, which is highly improbable in our case. */ |
228 | * The NVB bit should be low if no EEPROM write has been requested | ||
229 | * during the latest 10ms, which is highly improbable in our case. | ||
230 | */ | ||
231 | conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); | 241 | conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); |
232 | if (conf < 0 || conf & DS1621_REG_CONFIG_NVB) | 242 | if (conf < 0 || conf & DS1621_REG_CONFIG_NVB) |
233 | return -ENODEV; | 243 | return -ENODEV; |
@@ -249,10 +259,11 @@ static int ds1621_probe(struct i2c_client *client, | |||
249 | struct ds1621_data *data; | 259 | struct ds1621_data *data; |
250 | int err; | 260 | int err; |
251 | 261 | ||
252 | data = devm_kzalloc(&client->dev, sizeof(struct ds1621_data), | 262 | data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL); |
253 | GFP_KERNEL); | 263 | if (!data) { |
254 | if (!data) | 264 | err = -ENOMEM; |
255 | return -ENOMEM; | 265 | goto exit; |
266 | } | ||
256 | 267 | ||
257 | i2c_set_clientdata(client, data); | 268 | i2c_set_clientdata(client, data); |
258 | mutex_init(&data->update_lock); | 269 | mutex_init(&data->update_lock); |
@@ -261,9 +272,8 @@ static int ds1621_probe(struct i2c_client *client, | |||
261 | ds1621_init_client(client); | 272 | ds1621_init_client(client); |
262 | 273 | ||
263 | /* Register sysfs hooks */ | 274 | /* Register sysfs hooks */ |
264 | err = sysfs_create_group(&client->dev.kobj, &ds1621_group); | 275 | if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group))) |
265 | if (err) | 276 | goto exit_free; |
266 | return err; | ||
267 | 277 | ||
268 | data->hwmon_dev = hwmon_device_register(&client->dev); | 278 | data->hwmon_dev = hwmon_device_register(&client->dev); |
269 | if (IS_ERR(data->hwmon_dev)) { | 279 | if (IS_ERR(data->hwmon_dev)) { |
@@ -273,8 +283,11 @@ static int ds1621_probe(struct i2c_client *client, | |||
273 | 283 | ||
274 | return 0; | 284 | return 0; |
275 | 285 | ||
276 | exit_remove_files: | 286 | exit_remove_files: |
277 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); | 287 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); |
288 | exit_free: | ||
289 | kfree(data); | ||
290 | exit: | ||
278 | return err; | 291 | return err; |
279 | } | 292 | } |
280 | 293 | ||
@@ -285,6 +298,8 @@ static int ds1621_remove(struct i2c_client *client) | |||
285 | hwmon_device_unregister(data->hwmon_dev); | 298 | hwmon_device_unregister(data->hwmon_dev); |
286 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); | 299 | sysfs_remove_group(&client->dev.kobj, &ds1621_group); |
287 | 300 | ||
301 | kfree(data); | ||
302 | |||
288 | return 0; | 303 | return 0; |
289 | } | 304 | } |
290 | 305 | ||
@@ -308,8 +323,20 @@ static struct i2c_driver ds1621_driver = { | |||
308 | .address_list = normal_i2c, | 323 | .address_list = normal_i2c, |
309 | }; | 324 | }; |
310 | 325 | ||
311 | module_i2c_driver(ds1621_driver); | 326 | static int __init ds1621_init(void) |
327 | { | ||
328 | return i2c_add_driver(&ds1621_driver); | ||
329 | } | ||
330 | |||
331 | static void __exit ds1621_exit(void) | ||
332 | { | ||
333 | i2c_del_driver(&ds1621_driver); | ||
334 | } | ||
335 | |||
312 | 336 | ||
313 | MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>"); | 337 | MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>"); |
314 | MODULE_DESCRIPTION("DS1621 driver"); | 338 | MODULE_DESCRIPTION("DS1621 driver"); |
315 | MODULE_LICENSE("GPL"); | 339 | MODULE_LICENSE("GPL"); |
340 | |||
341 | module_init(ds1621_init); | ||
342 | module_exit(ds1621_exit); | ||