Blame view
drivers/hwmon/lm92.c
9.4 KB
c942fddf8 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 3 |
/* * lm92 - Hardware monitoring driver |
7c81c60f3 Update Jean Delva... |
4 |
* Copyright (C) 2005-2008 Jean Delvare <jdelvare@suse.de> |
1da177e4c Linux-2.6.12-rc2 |
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
* * Based on the lm90 driver, with some ideas taken from the lm_sensors * lm92 driver as well. * * The LM92 is a sensor chip made by National Semiconductor. It reports * its own temperature with a 0.0625 deg resolution and a 0.33 deg * accuracy. Complete datasheet can be obtained from National's website * at: * http://www.national.com/pf/LM/LM92.html * * This driver also supports the MAX6635 sensor chip made by Maxim. * This chip is compatible with the LM92, but has a lesser accuracy * (1.0 deg). Complete datasheet can be obtained from Maxim's website * at: * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 * * Since the LM92 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and * concern all supported chipsets, unless mentioned otherwise. * * Support could easily be added for the National Semiconductor LM76 * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible * with the LM92. |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 32 33 |
*/ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> |
943b0830c [PATCH] I2C hwmon... |
34 |
#include <linux/hwmon.h> |
6cb59e915 hwmon: (lm92) Add... |
35 |
#include <linux/hwmon-sysfs.h> |
943b0830c [PATCH] I2C hwmon... |
36 |
#include <linux/err.h> |
9a61bf630 [PATCH] hwmon: Se... |
37 |
#include <linux/mutex.h> |
dcd8f3923 hwmon: Add missin... |
38 |
#include <linux/jiffies.h> |
1da177e4c Linux-2.6.12-rc2 |
39 |
|
a318afd89 hwmon: (lm92) Fix... |
40 41 42 43 |
/* * The LM92 and MAX6635 have 2 two-state pins for address selection, * resulting in 4 possible addresses. */ |
25e9c86d5 hwmon: normal_i2c... |
44 45 |
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; |
10ecacd79 hwmon: (lm92) Add... |
46 |
enum chips { lm92, max6635 }; |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 53 54 55 |
/* The LM92 registers */ #define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ #define LM92_REG_TEMP 0x00 /* 16-bit, RO */ #define LM92_REG_TEMP_HYST 0x02 /* 16-bit, RW */ #define LM92_REG_TEMP_CRIT 0x03 /* 16-bit, RW */ #define LM92_REG_TEMP_LOW 0x04 /* 16-bit, RW */ #define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ #define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ |
a318afd89 hwmon: (lm92) Fix... |
56 57 58 59 60 61 62 |
/* * The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, * left-justified in 16-bit registers. No rounding is done, with such * a resolution it's just not worth it. Note that the MAX6635 doesn't * make use of the 4 lower bits for limits (i.e. effective resolution * for limits is 1 degree Celsius). */ |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 |
static inline int TEMP_FROM_REG(s16 reg) { return reg / 8 * 625 / 10; } |
5b9630891 hwmon: (lm92) Pre... |
67 |
static inline s16 TEMP_TO_REG(long val) |
1da177e4c Linux-2.6.12-rc2 |
68 |
{ |
5b9630891 hwmon: (lm92) Pre... |
69 |
val = clamp_val(val, -60000, 160000); |
1da177e4c Linux-2.6.12-rc2 |
70 71 72 73 74 75 76 77 |
return val * 10 / 625 * 8; } /* Alarm flags are stored in the 3 LSB of the temperature register */ static inline u8 ALARMS_FROM_REG(s16 reg) { return reg & 0x0007; } |
b8fe58e95 hwmon: (lm92) Dro... |
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
enum temp_index { t_input, t_crit, t_min, t_max, t_hyst, t_num_regs }; static const u8 regs[t_num_regs] = { [t_input] = LM92_REG_TEMP, [t_crit] = LM92_REG_TEMP_CRIT, [t_min] = LM92_REG_TEMP_LOW, [t_max] = LM92_REG_TEMP_HIGH, [t_hyst] = LM92_REG_TEMP_HYST, }; |
1da177e4c Linux-2.6.12-rc2 |
94 95 |
/* Client data (each client gets its own) */ struct lm92_data { |
030004b1e hwmon: (lm92) Con... |
96 |
struct i2c_client *client; |
9a61bf630 [PATCH] hwmon: Se... |
97 |
struct mutex update_lock; |
1da177e4c Linux-2.6.12-rc2 |
98 99 100 101 |
char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ /* registers values */ |
b8fe58e95 hwmon: (lm92) Dro... |
102 |
s16 temp[t_num_regs]; /* index with enum temp_index */ |
1da177e4c Linux-2.6.12-rc2 |
103 |
}; |
1da177e4c Linux-2.6.12-rc2 |
104 105 106 107 108 109 |
/* * Sysfs attributes and callback functions */ static struct lm92_data *lm92_update_device(struct device *dev) { |
030004b1e hwmon: (lm92) Con... |
110 111 |
struct lm92_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; |
b8fe58e95 hwmon: (lm92) Dro... |
112 |
int i; |
1da177e4c Linux-2.6.12-rc2 |
113 |
|
9a61bf630 [PATCH] hwmon: Se... |
114 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
115 |
|
0665a1d62 hwmon: (lm92) Fix... |
116 117 |
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { |
1da177e4c Linux-2.6.12-rc2 |
118 119 |
dev_dbg(&client->dev, "Updating lm92 data "); |
b8fe58e95 hwmon: (lm92) Dro... |
120 121 122 123 |
for (i = 0; i < t_num_regs; i++) { data->temp[i] = i2c_smbus_read_word_swapped(client, regs[i]); } |
1da177e4c Linux-2.6.12-rc2 |
124 125 126 |
data->last_updated = jiffies; data->valid = 1; } |
9a61bf630 [PATCH] hwmon: Se... |
127 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
128 129 130 |
return data; } |
185c993f0 hwmon: (lm92) Use... |
131 |
static ssize_t temp_show(struct device *dev, struct device_attribute *devattr, |
b8fe58e95 hwmon: (lm92) Dro... |
132 133 134 135 136 137 138 |
char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d ", TEMP_FROM_REG(data->temp[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
139 |
} |
1da177e4c Linux-2.6.12-rc2 |
140 |
|
185c993f0 hwmon: (lm92) Use... |
141 142 143 |
static ssize_t temp_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
144 |
{ |
b8fe58e95 hwmon: (lm92) Dro... |
145 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
030004b1e hwmon: (lm92) Con... |
146 147 |
struct lm92_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; |
b8fe58e95 hwmon: (lm92) Dro... |
148 149 150 |
int nr = attr->index; long val; int err; |
0665a1d62 hwmon: (lm92) Fix... |
151 |
|
b8fe58e95 hwmon: (lm92) Dro... |
152 153 154 155 156 157 158 159 160 |
err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->temp[nr] = TEMP_TO_REG(val); i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]); mutex_unlock(&data->update_lock); return count; |
1da177e4c Linux-2.6.12-rc2 |
161 |
} |
b8fe58e95 hwmon: (lm92) Dro... |
162 |
|
185c993f0 hwmon: (lm92) Use... |
163 |
static ssize_t temp_hyst_show(struct device *dev, |
b8fe58e95 hwmon: (lm92) Dro... |
164 |
struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
165 |
{ |
b8fe58e95 hwmon: (lm92) Dro... |
166 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
167 |
struct lm92_data *data = lm92_update_device(dev); |
0665a1d62 hwmon: (lm92) Fix... |
168 |
|
b8fe58e95 hwmon: (lm92) Dro... |
169 170 171 |
return sprintf(buf, "%d ", TEMP_FROM_REG(data->temp[attr->index]) - TEMP_FROM_REG(data->temp[t_hyst])); |
1da177e4c Linux-2.6.12-rc2 |
172 |
} |
b8fe58e95 hwmon: (lm92) Dro... |
173 |
|
3dba95dfd hwmon: (lm92) use... |
174 175 |
static ssize_t temp1_min_hyst_show(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
176 177 |
{ struct lm92_data *data = lm92_update_device(dev); |
0665a1d62 hwmon: (lm92) Fix... |
178 |
|
b8fe58e95 hwmon: (lm92) Dro... |
179 180 181 |
return sprintf(buf, "%d ", TEMP_FROM_REG(data->temp[t_min]) + TEMP_FROM_REG(data->temp[t_hyst])); |
1da177e4c Linux-2.6.12-rc2 |
182 |
} |
185c993f0 hwmon: (lm92) Use... |
183 184 185 |
static ssize_t temp_hyst_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
186 |
{ |
b8fe58e95 hwmon: (lm92) Dro... |
187 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
030004b1e hwmon: (lm92) Con... |
188 189 |
struct lm92_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; |
a318afd89 hwmon: (lm92) Fix... |
190 191 192 193 194 195 |
long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
196 |
|
5b9630891 hwmon: (lm92) Pre... |
197 |
val = clamp_val(val, -120000, 220000); |
9a61bf630 [PATCH] hwmon: Se... |
198 |
mutex_lock(&data->update_lock); |
0665a1d62 hwmon: (lm92) Fix... |
199 |
data->temp[t_hyst] = |
5b9630891 hwmon: (lm92) Pre... |
200 |
TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val); |
90f4102ce hwmon: Use i2c_sm... |
201 |
i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, |
5b9630891 hwmon: (lm92) Pre... |
202 |
data->temp[t_hyst]); |
9a61bf630 [PATCH] hwmon: Se... |
203 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
204 205 |
return count; } |
3dba95dfd hwmon: (lm92) use... |
206 |
static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, |
a318afd89 hwmon: (lm92) Fix... |
207 |
char *buf) |
1da177e4c Linux-2.6.12-rc2 |
208 209 |
{ struct lm92_data *data = lm92_update_device(dev); |
0665a1d62 hwmon: (lm92) Fix... |
210 |
|
b8fe58e95 hwmon: (lm92) Dro... |
211 212 |
return sprintf(buf, "%d ", ALARMS_FROM_REG(data->temp[t_input])); |
1da177e4c Linux-2.6.12-rc2 |
213 |
} |
185c993f0 hwmon: (lm92) Use... |
214 |
static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, |
6cb59e915 hwmon: (lm92) Add... |
215 216 217 218 |
char *buf) { int bitnr = to_sensor_dev_attr(attr)->index; struct lm92_data *data = lm92_update_device(dev); |
b8fe58e95 hwmon: (lm92) Dro... |
219 220 |
return sprintf(buf, "%d ", (data->temp[t_input] >> bitnr) & 1); |
6cb59e915 hwmon: (lm92) Add... |
221 |
} |
185c993f0 hwmon: (lm92) Use... |
222 223 224 225 |
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, t_input); static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, t_crit); static SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, temp_hyst, t_crit); static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, t_min); |
3dba95dfd hwmon: (lm92) use... |
226 |
static DEVICE_ATTR_RO(temp1_min_hyst); |
185c993f0 hwmon: (lm92) Use... |
227 228 |
static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, t_max); static SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, temp_hyst, t_max); |
3dba95dfd hwmon: (lm92) use... |
229 |
static DEVICE_ATTR_RO(alarms); |
185c993f0 hwmon: (lm92) Use... |
230 231 232 |
static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 2); static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 0); static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 1); |
1da177e4c Linux-2.6.12-rc2 |
233 |
|
1da177e4c Linux-2.6.12-rc2 |
234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
/* * Detection and registration */ static void lm92_init_client(struct i2c_client *client) { u8 config; /* Start the conversions if needed */ config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); if (config & 0x01) i2c_smbus_write_byte_data(client, LM92_REG_CONFIG, config & 0xFE); } |
030004b1e hwmon: (lm92) Con... |
248 |
static struct attribute *lm92_attrs[] = { |
b8fe58e95 hwmon: (lm92) Dro... |
249 250 251 252 |
&sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, |
0501a3816 hwmon: Fix unchec... |
253 |
&dev_attr_temp1_min_hyst.attr, |
b8fe58e95 hwmon: (lm92) Dro... |
254 255 |
&sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, |
0501a3816 hwmon: Fix unchec... |
256 |
&dev_attr_alarms.attr, |
6cb59e915 hwmon: (lm92) Add... |
257 258 259 |
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, |
0501a3816 hwmon: Fix unchec... |
260 261 |
NULL }; |
030004b1e hwmon: (lm92) Con... |
262 |
ATTRIBUTE_GROUPS(lm92); |
0501a3816 hwmon: Fix unchec... |
263 |
|
910e8dcf1 hwmon: (lm92) Con... |
264 |
/* Return 0 if detection is successful, -ENODEV otherwise */ |
310ec7921 i2c: Drop the kin... |
265 |
static int lm92_detect(struct i2c_client *new_client, |
910e8dcf1 hwmon: (lm92) Con... |
266 |
struct i2c_board_info *info) |
1da177e4c Linux-2.6.12-rc2 |
267 |
{ |
910e8dcf1 hwmon: (lm92) Con... |
268 |
struct i2c_adapter *adapter = new_client->adapter; |
52df6440a hwmon: Clean up d... |
269 270 |
u8 config; u16 man_id; |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 |
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) |
910e8dcf1 hwmon: (lm92) Con... |
274 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
275 |
|
52df6440a hwmon: Clean up d... |
276 277 278 279 280 281 |
config = i2c_smbus_read_byte_data(new_client, LM92_REG_CONFIG); man_id = i2c_smbus_read_word_data(new_client, LM92_REG_MAN_ID); if ((config & 0xe0) == 0x00 && man_id == 0x0180) pr_info("lm92: Found National Semiconductor LM92 chip "); |
52df6440a hwmon: Clean up d... |
282 283 |
else return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
284 |
|
910e8dcf1 hwmon: (lm92) Con... |
285 286 287 288 |
strlcpy(info->type, "lm92", I2C_NAME_SIZE); return 0; } |
674870385 hwmon: use simple... |
289 |
static int lm92_probe(struct i2c_client *new_client) |
910e8dcf1 hwmon: (lm92) Con... |
290 |
{ |
030004b1e hwmon: (lm92) Con... |
291 |
struct device *hwmon_dev; |
910e8dcf1 hwmon: (lm92) Con... |
292 |
struct lm92_data *data; |
910e8dcf1 hwmon: (lm92) Con... |
293 |
|
705375cc4 hwmon: (lm92) Con... |
294 295 296 297 |
data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data), GFP_KERNEL); if (!data) return -ENOMEM; |
910e8dcf1 hwmon: (lm92) Con... |
298 |
|
030004b1e hwmon: (lm92) Con... |
299 |
data->client = new_client; |
9a61bf630 [PATCH] hwmon: Se... |
300 |
mutex_init(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
301 |
|
1da177e4c Linux-2.6.12-rc2 |
302 303 |
/* Initialize the chipset */ lm92_init_client(new_client); |
030004b1e hwmon: (lm92) Con... |
304 305 306 307 |
hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, new_client->name, data, lm92_groups); return PTR_ERR_OR_ZERO(hwmon_dev); |
1da177e4c Linux-2.6.12-rc2 |
308 |
} |
1da177e4c Linux-2.6.12-rc2 |
309 310 311 |
/* * Module and driver stuff */ |
910e8dcf1 hwmon: (lm92) Con... |
312 |
static const struct i2c_device_id lm92_id[] = { |
10ecacd79 hwmon: (lm92) Add... |
313 314 |
{ "lm92", lm92 }, { "max6635", max6635 }, |
910e8dcf1 hwmon: (lm92) Con... |
315 316 317 |
{ } }; MODULE_DEVICE_TABLE(i2c, lm92_id); |
1da177e4c Linux-2.6.12-rc2 |
318 |
static struct i2c_driver lm92_driver = { |
910e8dcf1 hwmon: (lm92) Con... |
319 |
.class = I2C_CLASS_HWMON, |
cdaf79349 [PATCH] i2c: Drop... |
320 |
.driver = { |
cdaf79349 [PATCH] i2c: Drop... |
321 322 |
.name = "lm92", }, |
674870385 hwmon: use simple... |
323 |
.probe_new = lm92_probe, |
910e8dcf1 hwmon: (lm92) Con... |
324 325 |
.id_table = lm92_id, .detect = lm92_detect, |
c3813d6af i2c: Get rid of s... |
326 |
.address_list = normal_i2c, |
1da177e4c Linux-2.6.12-rc2 |
327 |
}; |
f0967eea8 hwmon: convert dr... |
328 |
module_i2c_driver(lm92_driver); |
1da177e4c Linux-2.6.12-rc2 |
329 |
|
7c81c60f3 Update Jean Delva... |
330 |
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); |
1da177e4c Linux-2.6.12-rc2 |
331 332 |
MODULE_DESCRIPTION("LM92/MAX6635 driver"); MODULE_LICENSE("GPL"); |