aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/ds1621.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/ds1621.c')
-rw-r--r--drivers/hwmon/ds1621.c161
1 files changed, 78 insertions, 83 deletions
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index d5ac422d73b2..1212d6b7f316 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -27,6 +27,7 @@
27#include <linux/jiffies.h> 27#include <linux/jiffies.h>
28#include <linux/i2c.h> 28#include <linux/i2c.h>
29#include <linux/hwmon.h> 29#include <linux/hwmon.h>
30#include <linux/hwmon-sysfs.h>
30#include <linux/err.h> 31#include <linux/err.h>
31#include <linux/mutex.h> 32#include <linux/mutex.h>
32#include <linux/sysfs.h> 33#include <linux/sysfs.h>
@@ -52,9 +53,11 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
52#define DS1621_REG_CONFIG_DONE 0x80 53#define DS1621_REG_CONFIG_DONE 0x80
53 54
54/* The DS1621 registers */ 55/* The DS1621 registers */
55#define DS1621_REG_TEMP 0xAA /* word, RO */ 56static const u8 DS1621_REG_TEMP[3] = {
56#define DS1621_REG_TEMP_MIN 0xA2 /* word, RW */ 57 0xAA, /* input, word, RO */
57#define DS1621_REG_TEMP_MAX 0xA1 /* word, RW */ 58 0xA2, /* min, word, RW */
59 0xA1, /* max, word, RW */
60};
58#define DS1621_REG_CONF 0xAC /* byte, RW */ 61#define DS1621_REG_CONF 0xAC /* byte, RW */
59#define DS1621_COM_START 0xEE /* no data */ 62#define DS1621_COM_START 0xEE /* no data */
60#define DS1621_COM_STOP 0x22 /* no data */ 63#define DS1621_COM_STOP 0x22 /* no data */
@@ -63,10 +66,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
63#define DS1621_ALARM_TEMP_HIGH 0x40 66#define DS1621_ALARM_TEMP_HIGH 0x40
64#define DS1621_ALARM_TEMP_LOW 0x20 67#define DS1621_ALARM_TEMP_LOW 0x20
65 68
66/* Conversions. Rounding and limit checking is only done on the TO_REG 69/* Conversions */
67 variants. Note that you should be a bit careful with which arguments
68 these macros are called: arguments may be evaluated more than once.
69 Fixing this is just not worth it. */
70#define ALARMS_FROM_REG(val) ((val) & \ 70#define ALARMS_FROM_REG(val) ((val) & \
71 (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) 71 (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
72 72
@@ -78,7 +78,7 @@ struct ds1621_data {
78 char valid; /* !=0 if following fields are valid */ 78 char valid; /* !=0 if following fields are valid */
79 unsigned long last_updated; /* In jiffies */ 79 unsigned long last_updated; /* In jiffies */
80 80
81 u16 temp, temp_min, temp_max; /* Register values, word */ 81 u16 temp[3]; /* Register values, word */
82 u8 conf; /* Register encoding, combined */ 82 u8 conf; /* Register encoding, combined */
83}; 83};
84 84
@@ -101,7 +101,7 @@ static struct i2c_driver ds1621_driver = {
101 101
102/* All registers are word-sized, except for the configuration register. 102/* All registers are word-sized, except for the configuration register.
103 DS1621 uses a high-byte first convention, which is exactly opposite to 103 DS1621 uses a high-byte first convention, which is exactly opposite to
104 the usual practice. */ 104 the SMBus standard. */
105static int ds1621_read_value(struct i2c_client *client, u8 reg) 105static int ds1621_read_value(struct i2c_client *client, u8 reg)
106{ 106{
107 if (reg == DS1621_REG_CONF) 107 if (reg == DS1621_REG_CONF)
@@ -110,9 +110,6 @@ static int ds1621_read_value(struct i2c_client *client, u8 reg)
110 return swab16(i2c_smbus_read_word_data(client, reg)); 110 return swab16(i2c_smbus_read_word_data(client, reg));
111} 111}
112 112
113/* All registers are word-sized, except for the configuration register.
114 DS1621 uses a high-byte first convention, which is exactly opposite to
115 the usual practice. */
116static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) 113static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
117{ 114{
118 if (reg == DS1621_REG_CONF) 115 if (reg == DS1621_REG_CONF)
@@ -139,50 +136,61 @@ static void ds1621_init_client(struct i2c_client *client)
139 i2c_smbus_write_byte(client, DS1621_COM_START); 136 i2c_smbus_write_byte(client, DS1621_COM_START);
140} 137}
141 138
142#define show(value) \ 139static ssize_t show_temp(struct device *dev, struct device_attribute *da,
143static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ 140 char *buf)
144{ \ 141{
145 struct ds1621_data *data = ds1621_update_client(dev); \ 142 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
146 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ 143 struct ds1621_data *data = ds1621_update_client(dev);
144 return sprintf(buf, "%d\n",
145 LM75_TEMP_FROM_REG(data->temp[attr->index]));
147} 146}
148 147
149show(temp); 148static ssize_t set_temp(struct device *dev, struct device_attribute *da,
150show(temp_min); 149 const char *buf, size_t count)
151show(temp_max); 150{
152 151 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
153#define set_temp(suffix, value, reg) \ 152 struct i2c_client *client = to_i2c_client(dev);
154static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ 153 struct ds1621_data *data = ds1621_update_client(dev);
155 size_t count) \ 154 u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
156{ \
157 struct i2c_client *client = to_i2c_client(dev); \
158 struct ds1621_data *data = ds1621_update_client(dev); \
159 u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \
160 \
161 mutex_lock(&data->update_lock); \
162 data->value = val; \
163 ds1621_write_value(client, reg, data->value); \
164 mutex_unlock(&data->update_lock); \
165 return count; \
166}
167 155
168set_temp(min, temp_min, DS1621_REG_TEMP_MIN); 156 mutex_lock(&data->update_lock);
169set_temp(max, temp_max, DS1621_REG_TEMP_MAX); 157 data->temp[attr->index] = val;
158 ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
159 data->temp[attr->index]);
160 mutex_unlock(&data->update_lock);
161 return count;
162}
170 163
171static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) 164static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
165 char *buf)
172{ 166{
173 struct ds1621_data *data = ds1621_update_client(dev); 167 struct ds1621_data *data = ds1621_update_client(dev);
174 return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); 168 return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
175} 169}
176 170
171static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
172 char *buf)
173{
174 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
175 struct ds1621_data *data = ds1621_update_client(dev);
176 return sprintf(buf, "%d\n", !!(data->conf & attr->index));
177}
178
177static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 179static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
178static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL); 180static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
179static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min); 181static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
180static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); 182static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
183static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
184 DS1621_ALARM_TEMP_LOW);
185static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
186 DS1621_ALARM_TEMP_HIGH);
181 187
182static struct attribute *ds1621_attributes[] = { 188static struct attribute *ds1621_attributes[] = {
183 &dev_attr_temp1_input.attr, 189 &sensor_dev_attr_temp1_input.dev_attr.attr,
184 &dev_attr_temp1_min.attr, 190 &sensor_dev_attr_temp1_min.dev_attr.attr,
185 &dev_attr_temp1_max.attr, 191 &sensor_dev_attr_temp1_max.dev_attr.attr,
192 &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
193 &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
186 &dev_attr_alarms.attr, 194 &dev_attr_alarms.attr,
187 NULL 195 NULL
188}; 196};
@@ -204,9 +212,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
204 int kind) 212 int kind)
205{ 213{
206 int conf, temp; 214 int conf, temp;
207 struct i2c_client *new_client; 215 struct i2c_client *client;
208 struct ds1621_data *data; 216 struct ds1621_data *data;
209 int err = 0; 217 int i, err = 0;
210 218
211 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA 219 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
212 | I2C_FUNC_SMBUS_WORD_DATA 220 | I2C_FUNC_SMBUS_WORD_DATA
@@ -221,55 +229,44 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
221 goto exit; 229 goto exit;
222 } 230 }
223 231
224 new_client = &data->client; 232 client = &data->client;
225 i2c_set_clientdata(new_client, data); 233 i2c_set_clientdata(client, data);
226 new_client->addr = address; 234 client->addr = address;
227 new_client->adapter = adapter; 235 client->adapter = adapter;
228 new_client->driver = &ds1621_driver; 236 client->driver = &ds1621_driver;
229 new_client->flags = 0;
230
231 237
232 /* Now, we do the remaining detection. It is lousy. */ 238 /* Now, we do the remaining detection. It is lousy. */
233 if (kind < 0) { 239 if (kind < 0) {
234 /* The NVB bit should be low if no EEPROM write has been 240 /* The NVB bit should be low if no EEPROM write has been
235 requested during the latest 10ms, which is highly 241 requested during the latest 10ms, which is highly
236 improbable in our case. */ 242 improbable in our case. */
237 conf = ds1621_read_value(new_client, DS1621_REG_CONF); 243 conf = ds1621_read_value(client, DS1621_REG_CONF);
238 if (conf & DS1621_REG_CONFIG_NVB) 244 if (conf & DS1621_REG_CONFIG_NVB)
239 goto exit_free; 245 goto exit_free;
240 /* The 7 lowest bits of a temperature should always be 0. */ 246 /* The 7 lowest bits of a temperature should always be 0. */
241 temp = ds1621_read_value(new_client, DS1621_REG_TEMP); 247 for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
242 if (temp & 0x007f) 248 temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
243 goto exit_free; 249 if (temp & 0x007f)
244 temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN); 250 goto exit_free;
245 if (temp & 0x007f) 251 }
246 goto exit_free;
247 temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
248 if (temp & 0x007f)
249 goto exit_free;
250 } 252 }
251 253
252 /* Determine the chip type - only one kind supported! */
253 if (kind <= 0)
254 kind = ds1621;
255
256 /* Fill in remaining client fields and put it into the global list */ 254 /* Fill in remaining client fields and put it into the global list */
257 strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE); 255 strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
258 data->valid = 0;
259 mutex_init(&data->update_lock); 256 mutex_init(&data->update_lock);
260 257
261 /* Tell the I2C layer a new client has arrived */ 258 /* Tell the I2C layer a new client has arrived */
262 if ((err = i2c_attach_client(new_client))) 259 if ((err = i2c_attach_client(client)))
263 goto exit_free; 260 goto exit_free;
264 261
265 /* Initialize the DS1621 chip */ 262 /* Initialize the DS1621 chip */
266 ds1621_init_client(new_client); 263 ds1621_init_client(client);
267 264
268 /* Register sysfs hooks */ 265 /* Register sysfs hooks */
269 if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group))) 266 if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
270 goto exit_detach; 267 goto exit_detach;
271 268
272 data->class_dev = hwmon_device_register(&new_client->dev); 269 data->class_dev = hwmon_device_register(&client->dev);
273 if (IS_ERR(data->class_dev)) { 270 if (IS_ERR(data->class_dev)) {
274 err = PTR_ERR(data->class_dev); 271 err = PTR_ERR(data->class_dev);
275 goto exit_remove_files; 272 goto exit_remove_files;
@@ -278,9 +275,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
278 return 0; 275 return 0;
279 276
280 exit_remove_files: 277 exit_remove_files:
281 sysfs_remove_group(&new_client->dev.kobj, &ds1621_group); 278 sysfs_remove_group(&client->dev.kobj, &ds1621_group);
282 exit_detach: 279 exit_detach:
283 i2c_detach_client(new_client); 280 i2c_detach_client(client);
284 exit_free: 281 exit_free:
285 kfree(data); 282 kfree(data);
286 exit: 283 exit:
@@ -314,23 +311,21 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
314 311
315 if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 312 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
316 || !data->valid) { 313 || !data->valid) {
314 int i;
317 315
318 dev_dbg(&client->dev, "Starting ds1621 update\n"); 316 dev_dbg(&client->dev, "Starting ds1621 update\n");
319 317
320 data->conf = ds1621_read_value(client, DS1621_REG_CONF); 318 data->conf = ds1621_read_value(client, DS1621_REG_CONF);
321 319
322 data->temp = ds1621_read_value(client, DS1621_REG_TEMP); 320 for (i = 0; i < ARRAY_SIZE(data->temp); i++)
323 321 data->temp[i] = ds1621_read_value(client,
324 data->temp_min = ds1621_read_value(client, 322 DS1621_REG_TEMP[i]);
325 DS1621_REG_TEMP_MIN);
326 data->temp_max = ds1621_read_value(client,
327 DS1621_REG_TEMP_MAX);
328 323
329 /* reset alarms if necessary */ 324 /* reset alarms if necessary */
330 new_conf = data->conf; 325 new_conf = data->conf;
331 if (data->temp > data->temp_min) 326 if (data->temp[0] > data->temp[1]) /* input > min */
332 new_conf &= ~DS1621_ALARM_TEMP_LOW; 327 new_conf &= ~DS1621_ALARM_TEMP_LOW;
333 if (data->temp < data->temp_max) 328 if (data->temp[0] < data->temp[2]) /* input < max */
334 new_conf &= ~DS1621_ALARM_TEMP_HIGH; 329 new_conf &= ~DS1621_ALARM_TEMP_HIGH;
335 if (data->conf != new_conf) 330 if (data->conf != new_conf)
336 ds1621_write_value(client, DS1621_REG_CONF, 331 ds1621_write_value(client, DS1621_REG_CONF,