Blame view
drivers/hwmon/lm63.c
22 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* * lm63.c - driver for the National Semiconductor LM63 temperature sensor * with integrated fan control |
d5957be2f hwmon: (lm63) Con... |
4 |
* Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org> |
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 28 29 30 31 32 33 34 35 36 37 38 |
* Based on the lm90 driver. * * The LM63 is a sensor chip made by National Semiconductor. It measures * two temperatures (its own and one external one) and the speed of one * fan, those speed it can additionally control. Complete datasheet can be * obtained from National's website at: * http://www.national.com/pf/LM/LM63.html * * The LM63 is basically an LM86 with fan speed monitoring and control * capabilities added. It misses some of the LM86 features though: * - No low limit for local temperature. * - No critical limit for local temperature. * - Critical limit for remote temperature can be changed only once. We * will consider that the critical limit is read-only. * * The datasheet isn't very clear about what the tachometer reading is. * I had a explanation from National Semiconductor though. The two lower * bits of the read value have to be masked out. The value is still 16 bit * in width. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
1da177e4c Linux-2.6.12-rc2 |
39 40 41 42 43 |
#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> |
10c08f810 [PATCH] I2C: rena... |
44 |
#include <linux/hwmon-sysfs.h> |
943b0830c [PATCH] I2C hwmon... |
45 46 |
#include <linux/hwmon.h> #include <linux/err.h> |
9a61bf630 [PATCH] hwmon: Se... |
47 |
#include <linux/mutex.h> |
0e39e01c9 hwmon: Fix unchec... |
48 |
#include <linux/sysfs.h> |
210961c43 hwmon: (lm63) Add... |
49 |
#include <linux/types.h> |
1da177e4c Linux-2.6.12-rc2 |
50 51 52 53 54 |
/* * Addresses to scan * Address is fully defined internally and cannot be changed. */ |
10f2ed31a hwmon: (lm63) Add... |
55 |
static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; |
1da177e4c Linux-2.6.12-rc2 |
56 57 |
/* |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
* The LM63 registers */ #define LM63_REG_CONFIG1 0x03 #define LM63_REG_CONFIG2 0xBF #define LM63_REG_CONFIG_FAN 0x4A #define LM63_REG_TACH_COUNT_MSB 0x47 #define LM63_REG_TACH_COUNT_LSB 0x46 #define LM63_REG_TACH_LIMIT_MSB 0x49 #define LM63_REG_TACH_LIMIT_LSB 0x48 #define LM63_REG_PWM_VALUE 0x4C #define LM63_REG_PWM_FREQ 0x4D #define LM63_REG_LOCAL_TEMP 0x00 #define LM63_REG_LOCAL_HIGH 0x05 #define LM63_REG_REMOTE_TEMP_MSB 0x01 #define LM63_REG_REMOTE_TEMP_LSB 0x10 #define LM63_REG_REMOTE_OFFSET_MSB 0x11 #define LM63_REG_REMOTE_OFFSET_LSB 0x12 #define LM63_REG_REMOTE_HIGH_MSB 0x07 #define LM63_REG_REMOTE_HIGH_LSB 0x13 #define LM63_REG_REMOTE_LOW_MSB 0x08 #define LM63_REG_REMOTE_LOW_LSB 0x14 #define LM63_REG_REMOTE_TCRIT 0x19 #define LM63_REG_REMOTE_TCRIT_HYST 0x21 #define LM63_REG_ALERT_STATUS 0x02 #define LM63_REG_ALERT_MASK 0x16 #define LM63_REG_MAN_ID 0xFE #define LM63_REG_CHIP_ID 0xFF |
210961c43 hwmon: (lm63) Add... |
92 |
#define LM96163_REG_CONFIG_ENHANCED 0x45 |
1da177e4c Linux-2.6.12-rc2 |
93 94 95 96 |
/* * Conversions and various macros * For tachometer counts, the LM63 uses 16-bit values. * For local temperature and high limit, remote critical limit and hysteresis |
44bbe87e9 [PATCH] Spelling ... |
97 |
* value, it uses signed 8-bit values with LSB = 1 degree Celsius. |
1da177e4c Linux-2.6.12-rc2 |
98 |
* For remote temperature, low and high limits, it uses signed 11-bit values |
44bbe87e9 [PATCH] Spelling ... |
99 |
* with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. |
2778fb13b hwmon: (lm63) Con... |
100 101 102 |
* For LM64 the actual remote diode temperature is 16 degree Celsius higher * than the register reading. Remote temperature setpoints have to be * adapted accordingly. |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
*/ #define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ 5400000 / (reg)) #define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFC : \ (5400000 / (val)) & 0xFFFC) #define TEMP8_FROM_REG(reg) ((reg) * 1000) #define TEMP8_TO_REG(val) ((val) <= -128000 ? -128 : \ (val) >= 127000 ? 127 : \ (val) < 0 ? ((val) - 500) / 1000 : \ ((val) + 500) / 1000) #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) #define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ (val) >= 127875 ? 0x7FE0 : \ (val) < 0 ? ((val) - 62) / 125 * 32 : \ ((val) + 62) / 125 * 32) #define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ (val) >= 127000 ? 127 : \ ((val) + 500) / 1000) /* * Functions declaration */ |
d5957be2f hwmon: (lm63) Con... |
126 127 128 |
static int lm63_probe(struct i2c_client *client, const struct i2c_device_id *id); static int lm63_remove(struct i2c_client *client); |
1da177e4c Linux-2.6.12-rc2 |
129 130 |
static struct lm63_data *lm63_update_device(struct device *dev); |
310ec7921 i2c: Drop the kin... |
131 |
static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info); |
1da177e4c Linux-2.6.12-rc2 |
132 |
static void lm63_init_client(struct i2c_client *client); |
210961c43 hwmon: (lm63) Add... |
133 |
enum chips { lm63, lm64, lm96163 }; |
10f2ed31a hwmon: (lm63) Add... |
134 |
|
1da177e4c Linux-2.6.12-rc2 |
135 136 137 |
/* * Driver data (common to all clients) */ |
d5957be2f hwmon: (lm63) Con... |
138 |
static const struct i2c_device_id lm63_id[] = { |
10f2ed31a hwmon: (lm63) Add... |
139 140 |
{ "lm63", lm63 }, { "lm64", lm64 }, |
210961c43 hwmon: (lm63) Add... |
141 |
{ "lm96163", lm96163 }, |
d5957be2f hwmon: (lm63) Con... |
142 143 144 |
{ } }; MODULE_DEVICE_TABLE(i2c, lm63_id); |
1da177e4c Linux-2.6.12-rc2 |
145 |
static struct i2c_driver lm63_driver = { |
d5957be2f hwmon: (lm63) Con... |
146 |
.class = I2C_CLASS_HWMON, |
cdaf79349 [PATCH] i2c: Drop... |
147 |
.driver = { |
cdaf79349 [PATCH] i2c: Drop... |
148 149 |
.name = "lm63", }, |
d5957be2f hwmon: (lm63) Con... |
150 151 152 153 |
.probe = lm63_probe, .remove = lm63_remove, .id_table = lm63_id, .detect = lm63_detect, |
c3813d6af i2c: Get rid of s... |
154 |
.address_list = normal_i2c, |
1da177e4c Linux-2.6.12-rc2 |
155 156 157 158 159 160 161 |
}; /* * Client data (each client gets its own) */ struct lm63_data { |
1beeffe43 hwmon: Convert fr... |
162 |
struct device *hwmon_dev; |
9a61bf630 [PATCH] hwmon: Se... |
163 |
struct mutex update_lock; |
1da177e4c Linux-2.6.12-rc2 |
164 165 |
char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ |
2778fb13b hwmon: (lm63) Con... |
166 167 |
int kind; int temp2_offset; |
1da177e4c Linux-2.6.12-rc2 |
168 169 170 |
/* registers values */ u8 config, config_fan; |
bc51ae115 [PATCH] I2C: lm63... |
171 172 |
u16 fan[2]; /* 0: input 1: low limit */ |
1da177e4c Linux-2.6.12-rc2 |
173 174 |
u8 pwm1_freq; u8 pwm1_value; |
bc51ae115 [PATCH] I2C: lm63... |
175 176 177 |
s8 temp8[3]; /* 0: local input 1: local high limit 2: remote critical limit */ |
786375f72 hwmon: (lm63) Add... |
178 |
s16 temp11[4]; /* 0: remote input |
bc51ae115 [PATCH] I2C: lm63... |
179 |
1: remote low limit |
786375f72 hwmon: (lm63) Add... |
180 181 |
2: remote high limit 3: remote offset */ |
1da177e4c Linux-2.6.12-rc2 |
182 183 |
u8 temp2_crit_hyst; u8 alarms; |
210961c43 hwmon: (lm63) Add... |
184 |
bool pwm_highres; |
1da177e4c Linux-2.6.12-rc2 |
185 186 187 188 189 |
}; /* * Sysfs callback functions and files */ |
bc51ae115 [PATCH] I2C: lm63... |
190 191 192 193 194 195 196 |
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d ", FAN_FROM_REG(data->fan[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
197 |
} |
1da177e4c Linux-2.6.12-rc2 |
198 |
|
bc51ae115 [PATCH] I2C: lm63... |
199 200 |
static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
201 202 203 |
{ struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); |
662bda283 hwmon: (lm63) Fix... |
204 205 206 207 208 209 |
unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
210 |
|
9a61bf630 [PATCH] hwmon: Se... |
211 |
mutex_lock(&data->update_lock); |
bc51ae115 [PATCH] I2C: lm63... |
212 |
data->fan[1] = FAN_TO_REG(val); |
1da177e4c Linux-2.6.12-rc2 |
213 |
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, |
bc51ae115 [PATCH] I2C: lm63... |
214 |
data->fan[1] & 0xFF); |
1da177e4c Linux-2.6.12-rc2 |
215 |
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, |
bc51ae115 [PATCH] I2C: lm63... |
216 |
data->fan[1] >> 8); |
9a61bf630 [PATCH] hwmon: Se... |
217 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
218 219 |
return count; } |
bc51ae115 [PATCH] I2C: lm63... |
220 221 |
static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
222 223 |
{ struct lm63_data *data = lm63_update_device(dev); |
210961c43 hwmon: (lm63) Add... |
224 225 226 227 228 229 |
int pwm; if (data->pwm_highres) pwm = data->pwm1_value; else pwm = data->pwm1_value >= 2 * data->pwm1_freq ? |
1da177e4c Linux-2.6.12-rc2 |
230 |
255 : (data->pwm1_value * 255 + data->pwm1_freq) / |
210961c43 hwmon: (lm63) Add... |
231 232 233 234 |
(2 * data->pwm1_freq); return sprintf(buf, "%d ", pwm); |
1da177e4c Linux-2.6.12-rc2 |
235 |
} |
bc51ae115 [PATCH] I2C: lm63... |
236 237 |
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
238 239 240 241 |
{ struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); unsigned long val; |
662bda283 hwmon: (lm63) Fix... |
242 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
243 244 |
if (!(data->config_fan & 0x20)) /* register is read-only */ return -EPERM; |
662bda283 hwmon: (lm63) Fix... |
245 246 247 |
err = kstrtoul(buf, 10, &val); if (err) return err; |
210961c43 hwmon: (lm63) Add... |
248 |
val = SENSORS_LIMIT(val, 0, 255); |
9a61bf630 [PATCH] hwmon: Se... |
249 |
mutex_lock(&data->update_lock); |
210961c43 hwmon: (lm63) Add... |
250 |
data->pwm1_value = data->pwm_highres ? val : |
1da177e4c Linux-2.6.12-rc2 |
251 252 |
(val * data->pwm1_freq * 2 + 127) / 255; i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); |
9a61bf630 [PATCH] hwmon: Se... |
253 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
254 255 |
return count; } |
662bda283 hwmon: (lm63) Fix... |
256 257 |
static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
258 259 260 261 262 |
{ struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d ", data->config_fan & 0x20 ? 1 : 2); } |
2778fb13b hwmon: (lm63) Con... |
263 264 265 266 267 268 269 270 271 |
/* * There are 8bit registers for both local(temp1) and remote(temp2) sensor. * For remote sensor registers temp2_offset has to be considered, * for local sensor it must not. * So we need separate 8bit accessors for local and remote sensor. */ static ssize_t show_local_temp8(struct device *dev, struct device_attribute *devattr, char *buf) |
bc51ae115 [PATCH] I2C: lm63... |
272 273 274 275 276 |
{ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d ", TEMP8_FROM_REG(data->temp8[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
277 |
} |
bc51ae115 [PATCH] I2C: lm63... |
278 |
|
2778fb13b hwmon: (lm63) Con... |
279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
static ssize_t show_remote_temp8(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d ", TEMP8_FROM_REG(data->temp8[attr->index]) + data->temp2_offset); } static ssize_t set_local_temp8(struct device *dev, struct device_attribute *dummy, const char *buf, size_t count) |
bc51ae115 [PATCH] I2C: lm63... |
293 294 295 |
{ struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); |
662bda283 hwmon: (lm63) Fix... |
296 297 298 299 300 301 |
long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; |
bc51ae115 [PATCH] I2C: lm63... |
302 |
|
9a61bf630 [PATCH] hwmon: Se... |
303 |
mutex_lock(&data->update_lock); |
bc51ae115 [PATCH] I2C: lm63... |
304 305 |
data->temp8[1] = TEMP8_TO_REG(val); i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); |
9a61bf630 [PATCH] hwmon: Se... |
306 |
mutex_unlock(&data->update_lock); |
bc51ae115 [PATCH] I2C: lm63... |
307 |
return count; |
1da177e4c Linux-2.6.12-rc2 |
308 |
} |
bc51ae115 [PATCH] I2C: lm63... |
309 310 311 312 313 314 |
static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); |
2778fb13b hwmon: (lm63) Con... |
315 316 317 |
return sprintf(buf, "%d ", TEMP11_FROM_REG(data->temp11[attr->index]) + data->temp2_offset); |
1da177e4c Linux-2.6.12-rc2 |
318 |
} |
bc51ae115 [PATCH] I2C: lm63... |
319 320 321 322 |
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { |
786375f72 hwmon: (lm63) Add... |
323 |
static const u8 reg[6] = { |
bc51ae115 [PATCH] I2C: lm63... |
324 325 326 327 |
LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB, |
786375f72 hwmon: (lm63) Add... |
328 329 |
LM63_REG_REMOTE_OFFSET_MSB, LM63_REG_REMOTE_OFFSET_LSB, |
bc51ae115 [PATCH] I2C: lm63... |
330 331 332 333 334 |
}; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); |
662bda283 hwmon: (lm63) Fix... |
335 336 |
long val; int err; |
bc51ae115 [PATCH] I2C: lm63... |
337 |
int nr = attr->index; |
662bda283 hwmon: (lm63) Fix... |
338 339 340 |
err = kstrtol(buf, 10, &val); if (err) return err; |
9a61bf630 [PATCH] hwmon: Se... |
341 |
mutex_lock(&data->update_lock); |
2778fb13b hwmon: (lm63) Con... |
342 |
data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); |
bc51ae115 [PATCH] I2C: lm63... |
343 344 345 346 |
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], data->temp11[nr] >> 8); i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], data->temp11[nr] & 0xff); |
9a61bf630 [PATCH] hwmon: Se... |
347 |
mutex_unlock(&data->update_lock); |
bc51ae115 [PATCH] I2C: lm63... |
348 |
return count; |
1da177e4c Linux-2.6.12-rc2 |
349 |
} |
1da177e4c Linux-2.6.12-rc2 |
350 |
|
662bda283 hwmon: (lm63) Fix... |
351 352 353 354 355 356 |
/* * Hysteresis register holds a relative value, while we want to present * an absolute to user-space */ static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
357 358 |
{ struct lm63_data *data = lm63_update_device(dev); |
bc51ae115 [PATCH] I2C: lm63... |
359 360 |
return sprintf(buf, "%d ", TEMP8_FROM_REG(data->temp8[2]) |
2778fb13b hwmon: (lm63) Con... |
361 |
+ data->temp2_offset |
1da177e4c Linux-2.6.12-rc2 |
362 363 |
- TEMP8_FROM_REG(data->temp2_crit_hyst)); } |
662bda283 hwmon: (lm63) Fix... |
364 365 366 367 368 369 |
/* * And now the other way around, user-space provides an absolute * hysteresis value and we have to store a relative one */ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, |
bc51ae115 [PATCH] I2C: lm63... |
370 |
const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
371 372 373 |
{ struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); |
662bda283 hwmon: (lm63) Fix... |
374 375 |
long val; int err; |
1da177e4c Linux-2.6.12-rc2 |
376 |
long hyst; |
662bda283 hwmon: (lm63) Fix... |
377 378 379 |
err = kstrtol(buf, 10, &val); if (err) return err; |
9a61bf630 [PATCH] hwmon: Se... |
380 |
mutex_lock(&data->update_lock); |
2778fb13b hwmon: (lm63) Con... |
381 |
hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val; |
1da177e4c Linux-2.6.12-rc2 |
382 383 |
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, HYST_TO_REG(hyst)); |
9a61bf630 [PATCH] hwmon: Se... |
384 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
385 386 |
return count; } |
bc51ae115 [PATCH] I2C: lm63... |
387 388 |
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
389 390 391 392 393 |
{ struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%u ", data->alarms); } |
2d45771e6 hwmon: Add indivi... |
394 395 396 397 398 399 400 401 402 403 |
static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); int bitnr = attr->index; return sprintf(buf, "%u ", (data->alarms >> bitnr) & 1); } |
bc51ae115 [PATCH] I2C: lm63... |
404 405 406 |
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, set_fan, 1); |
1da177e4c Linux-2.6.12-rc2 |
407 408 409 |
static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); |
2778fb13b hwmon: (lm63) Con... |
410 411 412 |
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, set_local_temp8, 1); |
1da177e4c Linux-2.6.12-rc2 |
413 |
|
bc51ae115 [PATCH] I2C: lm63... |
414 415 416 417 418 |
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 1); static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 2); |
786375f72 hwmon: (lm63) Add... |
419 420 |
static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 3); |
2778fb13b hwmon: (lm63) Con... |
421 422 423 424 425 426 |
/* * On LM63, temp2_crit can be set only once, which should be job * of the bootloader. */ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, NULL, 2); |
1da177e4c Linux-2.6.12-rc2 |
427 428 |
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); |
2d45771e6 hwmon: Add indivi... |
429 430 431 |
/* Individual alarm files */ static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); |
7817a39e6 hwmon: Fault file... |
432 |
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); |
2d45771e6 hwmon: Add indivi... |
433 434 435 436 |
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); /* Raw alarm file for compatibility */ |
1da177e4c Linux-2.6.12-rc2 |
437 |
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
0e39e01c9 hwmon: Fix unchec... |
438 439 440 441 442 443 444 445 |
static struct attribute *lm63_attributes[] = { &dev_attr_pwm1.attr, &dev_attr_pwm1_enable.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, |
786375f72 hwmon: (lm63) Add... |
446 |
&sensor_dev_attr_temp2_offset.dev_attr.attr, |
0e39e01c9 hwmon: Fix unchec... |
447 448 449 450 |
&sensor_dev_attr_temp2_crit.dev_attr.attr, &dev_attr_temp2_crit_hyst.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, |
7817a39e6 hwmon: Fault file... |
451 |
&sensor_dev_attr_temp2_fault.dev_attr.attr, |
0e39e01c9 hwmon: Fix unchec... |
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 |
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, &dev_attr_alarms.attr, NULL }; static const struct attribute_group lm63_group = { .attrs = lm63_attributes, }; static struct attribute *lm63_attributes_fan1[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, NULL }; static const struct attribute_group lm63_group_fan1 = { .attrs = lm63_attributes_fan1, }; |
1da177e4c Linux-2.6.12-rc2 |
474 475 476 |
/* * Real code */ |
d5957be2f hwmon: (lm63) Con... |
477 |
/* Return 0 if detection is successful, -ENODEV otherwise */ |
310ec7921 i2c: Drop the kin... |
478 |
static int lm63_detect(struct i2c_client *new_client, |
d5957be2f hwmon: (lm63) Con... |
479 |
struct i2c_board_info *info) |
1da177e4c Linux-2.6.12-rc2 |
480 |
{ |
d5957be2f hwmon: (lm63) Con... |
481 |
struct i2c_adapter *adapter = new_client->adapter; |
52df6440a hwmon: Clean up d... |
482 483 |
u8 man_id, chip_id, reg_config1, reg_config2; u8 reg_alert_status, reg_alert_mask; |
10f2ed31a hwmon: (lm63) Add... |
484 |
int address = new_client->addr; |
1da177e4c Linux-2.6.12-rc2 |
485 486 |
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
d5957be2f hwmon: (lm63) Con... |
487 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
488 |
|
52df6440a hwmon: Clean up d... |
489 490 491 492 493 494 495 496 497 498 499 500 501 |
man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID); chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID); reg_config1 = i2c_smbus_read_byte_data(new_client, LM63_REG_CONFIG1); reg_config2 = i2c_smbus_read_byte_data(new_client, LM63_REG_CONFIG2); reg_alert_status = i2c_smbus_read_byte_data(new_client, LM63_REG_ALERT_STATUS); reg_alert_mask = i2c_smbus_read_byte_data(new_client, LM63_REG_ALERT_MASK); if (man_id != 0x01 /* National Semiconductor */ |
52df6440a hwmon: Clean up d... |
502 503 504 505 506 507 508 509 510 |
|| (reg_config1 & 0x18) != 0x00 || (reg_config2 & 0xF8) != 0x00 || (reg_alert_status & 0x20) != 0x00 || (reg_alert_mask & 0xA4) != 0xA4) { dev_dbg(&adapter->dev, "Unsupported chip (man_id=0x%02X, chip_id=0x%02X) ", man_id, chip_id); return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
511 |
} |
10f2ed31a hwmon: (lm63) Add... |
512 513 514 515 |
if (chip_id == 0x41 && address == 0x4c) strlcpy(info->type, "lm63", I2C_NAME_SIZE); else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e)) strlcpy(info->type, "lm64", I2C_NAME_SIZE); |
210961c43 hwmon: (lm63) Add... |
516 517 |
else if (chip_id == 0x49 && address == 0x4c) strlcpy(info->type, "lm96163", I2C_NAME_SIZE); |
10f2ed31a hwmon: (lm63) Add... |
518 519 |
else return -ENODEV; |
d5957be2f hwmon: (lm63) Con... |
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
return 0; } static int lm63_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { struct lm63_data *data; int err; data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL); if (!data) { err = -ENOMEM; goto exit; } i2c_set_clientdata(new_client, data); |
1da177e4c Linux-2.6.12-rc2 |
537 |
data->valid = 0; |
9a61bf630 [PATCH] hwmon: Se... |
538 |
mutex_init(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
539 |
|
2778fb13b hwmon: (lm63) Con... |
540 541 542 543 544 545 |
/* Set the device type */ data->kind = id->driver_data; if (data->kind == lm64) data->temp2_offset = 16000; /* Initialize chip */ |
1da177e4c Linux-2.6.12-rc2 |
546 547 548 |
lm63_init_client(new_client); /* Register sysfs hooks */ |
662bda283 hwmon: (lm63) Fix... |
549 550 |
err = sysfs_create_group(&new_client->dev.kobj, &lm63_group); if (err) |
d5957be2f hwmon: (lm63) Con... |
551 |
goto exit_free; |
0e39e01c9 hwmon: Fix unchec... |
552 |
if (data->config & 0x04) { /* tachometer enabled */ |
662bda283 hwmon: (lm63) Fix... |
553 554 555 |
err = sysfs_create_group(&new_client->dev.kobj, &lm63_group_fan1); if (err) |
0e39e01c9 hwmon: Fix unchec... |
556 |
goto exit_remove_files; |
943b0830c [PATCH] I2C hwmon... |
557 |
} |
1beeffe43 hwmon: Convert fr... |
558 559 560 |
data->hwmon_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); |
0e39e01c9 hwmon: Fix unchec... |
561 |
goto exit_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
562 |
} |
1da177e4c Linux-2.6.12-rc2 |
563 564 |
return 0; |
0e39e01c9 hwmon: Fix unchec... |
565 566 567 |
exit_remove_files: sysfs_remove_group(&new_client->dev.kobj, &lm63_group); sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1); |
1da177e4c Linux-2.6.12-rc2 |
568 569 570 571 572 |
exit_free: kfree(data); exit: return err; } |
662bda283 hwmon: (lm63) Fix... |
573 574 575 576 |
/* * Ideally we shouldn't have to initialize anything, since the BIOS * should have taken care of everything */ |
1da177e4c Linux-2.6.12-rc2 |
577 578 579 580 581 582 583 584 585 586 |
static void lm63_init_client(struct i2c_client *client) { struct lm63_data *data = i2c_get_clientdata(client); data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); data->config_fan = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG_FAN); /* Start converting if needed */ if (data->config & 0x40) { /* standby */ |
898eb71cb Add missing newli... |
587 588 |
dev_dbg(&client->dev, "Switching to operational mode "); |
1da177e4c Linux-2.6.12-rc2 |
589 590 591 592 593 594 595 596 597 |
data->config &= 0xA7; i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, data->config); } /* We may need pwm1_freq before ever updating the client data */ data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); if (data->pwm1_freq == 0) data->pwm1_freq = 1; |
210961c43 hwmon: (lm63) Add... |
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
/* * For LM96163, check if high resolution PWM is enabled. * Also, check if unsigned temperature format is enabled * and display a warning message if it is. */ if (data->kind == lm96163) { u8 config_enhanced = i2c_smbus_read_byte_data(client, LM96163_REG_CONFIG_ENHANCED); if ((config_enhanced & 0x10) && !(data->config_fan & 0x08) && data->pwm1_freq == 8) data->pwm_highres = true; if (config_enhanced & 0x08) dev_warn(&client->dev, "Unsigned format for High and Crit setpoints enabled but not supported by driver "); } |
1da177e4c Linux-2.6.12-rc2 |
615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
/* Show some debug info about the LM63 configuration */ dev_dbg(&client->dev, "Alert/tach pin configured for %s ", (data->config & 0x04) ? "tachometer input" : "alert output"); dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz ", (data->config_fan & 0x08) ? "1.4" : "360", ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); dev_dbg(&client->dev, "PWM output active %s, %s mode ", (data->config_fan & 0x10) ? "low" : "high", (data->config_fan & 0x20) ? "manual" : "auto"); } |
d5957be2f hwmon: (lm63) Con... |
629 |
static int lm63_remove(struct i2c_client *client) |
1da177e4c Linux-2.6.12-rc2 |
630 |
{ |
943b0830c [PATCH] I2C hwmon... |
631 |
struct lm63_data *data = i2c_get_clientdata(client); |
1da177e4c Linux-2.6.12-rc2 |
632 |
|
1beeffe43 hwmon: Convert fr... |
633 |
hwmon_device_unregister(data->hwmon_dev); |
0e39e01c9 hwmon: Fix unchec... |
634 635 |
sysfs_remove_group(&client->dev.kobj, &lm63_group); sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); |
943b0830c [PATCH] I2C hwmon... |
636 |
|
943b0830c [PATCH] I2C hwmon... |
637 |
kfree(data); |
1da177e4c Linux-2.6.12-rc2 |
638 639 640 641 642 643 644 |
return 0; } static struct lm63_data *lm63_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); |
9a61bf630 [PATCH] hwmon: Se... |
645 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
646 647 648 649 |
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (data->config & 0x04) { /* tachometer enabled */ /* order matters for fan1_input */ |
bc51ae115 [PATCH] I2C: lm63... |
650 651 652 653 654 655 656 657 |
data->fan[0] = i2c_smbus_read_byte_data(client, LM63_REG_TACH_COUNT_LSB) & 0xFC; data->fan[0] |= i2c_smbus_read_byte_data(client, LM63_REG_TACH_COUNT_MSB) << 8; data->fan[1] = (i2c_smbus_read_byte_data(client, LM63_REG_TACH_LIMIT_LSB) & 0xFC) | (i2c_smbus_read_byte_data(client, LM63_REG_TACH_LIMIT_MSB) << 8); |
1da177e4c Linux-2.6.12-rc2 |
658 659 660 661 662 663 664 665 |
} data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); if (data->pwm1_freq == 0) data->pwm1_freq = 1; data->pwm1_value = i2c_smbus_read_byte_data(client, LM63_REG_PWM_VALUE); |
bc51ae115 [PATCH] I2C: lm63... |
666 667 668 669 |
data->temp8[0] = i2c_smbus_read_byte_data(client, LM63_REG_LOCAL_TEMP); data->temp8[1] = i2c_smbus_read_byte_data(client, LM63_REG_LOCAL_HIGH); |
1da177e4c Linux-2.6.12-rc2 |
670 671 |
/* order matters for temp2_input */ |
bc51ae115 [PATCH] I2C: lm63... |
672 673 674 675 676 |
data->temp11[0] = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TEMP_MSB) << 8; data->temp11[0] |= i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TEMP_LSB); data->temp11[1] = (i2c_smbus_read_byte_data(client, |
1da177e4c Linux-2.6.12-rc2 |
677 678 679 |
LM63_REG_REMOTE_LOW_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_LOW_LSB); |
bc51ae115 [PATCH] I2C: lm63... |
680 681 682 683 |
data->temp11[2] = (i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_HIGH_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_HIGH_LSB); |
786375f72 hwmon: (lm63) Add... |
684 685 686 687 |
data->temp11[3] = (i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_OFFSET_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_OFFSET_LSB); |
bc51ae115 [PATCH] I2C: lm63... |
688 689 |
data->temp8[2] = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TCRIT); |
1da177e4c Linux-2.6.12-rc2 |
690 691 692 693 694 695 696 697 698 |
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST); data->alarms = i2c_smbus_read_byte_data(client, LM63_REG_ALERT_STATUS) & 0x7F; data->last_updated = jiffies; data->valid = 1; } |
9a61bf630 [PATCH] hwmon: Se... |
699 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 |
return data; } static int __init sensors_lm63_init(void) { return i2c_add_driver(&lm63_driver); } static void __exit sensors_lm63_exit(void) { i2c_del_driver(&lm63_driver); } MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("LM63 driver"); MODULE_LICENSE("GPL"); module_init(sensors_lm63_init); module_exit(sensors_lm63_exit); |