Blame view
drivers/hwmon/lm78.c
27.1 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
9b03079fc hwmon: (lm78) Fix... |
2 3 4 |
* lm78.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> |
7c81c60f3 Update Jean Delva... |
5 |
* Copyright (c) 2007, 2011 Jean Delvare <jdelvare@suse.de> |
9b03079fc hwmon: (lm78) Fix... |
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
* * 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 |
21 |
|
ce47da742 hwmon: (lm78) Use... |
22 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 |
#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> |
943b0830c [PATCH] I2C hwmon... |
28 |
#include <linux/hwmon.h> |
19f673edd [PATCH] hwmon: hw... |
29 |
#include <linux/hwmon-vid.h> |
247dde4cd hwmon/lm78: Use d... |
30 |
#include <linux/hwmon-sysfs.h> |
943b0830c [PATCH] I2C hwmon... |
31 |
#include <linux/err.h> |
9a61bf630 [PATCH] hwmon: Se... |
32 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
90534c5c5 hwmon: (lm78) Mak... |
34 35 36 37 38 |
#ifdef CONFIG_ISA #include <linux/platform_device.h> #include <linux/ioport.h> #include <linux/io.h> #endif |
c40769fee hwmon/lm78: No lo... |
39 |
|
1da177e4c Linux-2.6.12-rc2 |
40 |
/* Addresses to scan */ |
25e9c86d5 hwmon: normal_i2c... |
41 42 |
static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; |
e5e9f44c2 i2c: Drop I2C_CLI... |
43 |
enum chips { lm78, lm79 }; |
1da177e4c Linux-2.6.12-rc2 |
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
/* Many LM78 constants specified below */ /* Length of ISA address segment */ #define LM78_EXTENT 8 /* Where are the ISA address/data registers relative to the base address */ #define LM78_ADDR_REG_OFFSET 5 #define LM78_DATA_REG_OFFSET 6 /* The LM78 registers */ #define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) #define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) #define LM78_REG_IN(nr) (0x20 + (nr)) #define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) #define LM78_REG_FAN(nr) (0x28 + (nr)) #define LM78_REG_TEMP 0x27 #define LM78_REG_TEMP_OVER 0x39 #define LM78_REG_TEMP_HYST 0x3a #define LM78_REG_ALARM1 0x41 #define LM78_REG_ALARM2 0x42 #define LM78_REG_VID_FANDIV 0x47 #define LM78_REG_CONFIG 0x40 #define LM78_REG_CHIPID 0x49 #define LM78_REG_I2C_ADDR 0x48 |
9b03079fc hwmon: (lm78) Fix... |
74 75 76 77 |
/* * Conversions. Rounding and limit checking is only done on the TO_REG * variants. */ |
1da177e4c Linux-2.6.12-rc2 |
78 |
|
9b03079fc hwmon: (lm78) Fix... |
79 80 81 82 |
/* * IN: mV (0V to 4.08V) * REG: 16mV/bit */ |
1da177e4c Linux-2.6.12-rc2 |
83 84 |
static inline u8 IN_TO_REG(unsigned long val) { |
2a844c148 hwmon: Replace SE... |
85 |
unsigned long nval = clamp_val(val, 0, 4080); |
1da177e4c Linux-2.6.12-rc2 |
86 87 88 89 90 91 92 93 |
return (nval + 8) / 16; } #define IN_FROM_REG(val) ((val) * 16) static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm <= 0) return 255; |
3806b45ba hwmon: Prevent so... |
94 95 |
if (rpm > 1350000) return 1; |
2a844c148 hwmon: Replace SE... |
96 |
return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); |
1da177e4c Linux-2.6.12-rc2 |
97 98 99 100 |
} static inline int FAN_FROM_REG(u8 val, int div) { |
9b03079fc hwmon: (lm78) Fix... |
101 |
return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div); |
1da177e4c Linux-2.6.12-rc2 |
102 |
} |
9b03079fc hwmon: (lm78) Fix... |
103 104 105 106 |
/* * TEMP: mC (-128C to +127C) * REG: 1C/bit, two's complement */ |
1074d683a hwmon: (lm78) Fix... |
107 |
static inline s8 TEMP_TO_REG(long val) |
1da177e4c Linux-2.6.12-rc2 |
108 |
{ |
2a844c148 hwmon: Replace SE... |
109 |
int nval = clamp_val(val, -128000, 127000) ; |
9b03079fc hwmon: (lm78) Fix... |
110 |
return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000; |
1da177e4c Linux-2.6.12-rc2 |
111 112 113 114 115 116 |
} static inline int TEMP_FROM_REG(s8 val) { return val * 1000; } |
1da177e4c Linux-2.6.12-rc2 |
117 |
#define DIV_FROM_REG(val) (1 << (val)) |
1da177e4c Linux-2.6.12-rc2 |
118 |
struct lm78_data { |
0c6e97317 hwmon: (lm78) Con... |
119 |
struct i2c_client *client; |
9a61bf630 [PATCH] hwmon: Se... |
120 |
struct mutex lock; |
1da177e4c Linux-2.6.12-rc2 |
121 |
enum chips type; |
6e1b5029d hwmon: (lm78) Sto... |
122 123 124 |
/* For ISA device only */ const char *name; int isa_addr; |
9a61bf630 [PATCH] hwmon: Se... |
125 |
struct mutex update_lock; |
1da177e4c Linux-2.6.12-rc2 |
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ u8 in[7]; /* Register value */ u8 in_max[7]; /* Register value */ u8 in_min[7]; /* Register value */ u8 fan[3]; /* Register value */ u8 fan_min[3]; /* Register value */ s8 temp; /* Register value */ s8 temp_over; /* Register value */ s8 temp_hyst; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u16 alarms; /* Register encoding, combined */ }; |
c59cc301e hwmon/lm78: Be le... |
141 142 |
static int lm78_read_value(struct lm78_data *data, u8 reg); static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value); |
1da177e4c Linux-2.6.12-rc2 |
143 |
static struct lm78_data *lm78_update_device(struct device *dev); |
c59cc301e hwmon/lm78: Be le... |
144 |
static void lm78_init_device(struct lm78_data *data); |
1da177e4c Linux-2.6.12-rc2 |
145 |
|
1da177e4c Linux-2.6.12-rc2 |
146 |
/* 7 Voltages */ |
247dde4cd hwmon/lm78: Use d... |
147 148 |
static ssize_t show_in(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
149 |
{ |
247dde4cd hwmon/lm78: Use d... |
150 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
1da177e4c Linux-2.6.12-rc2 |
151 |
struct lm78_data *data = lm78_update_device(dev); |
247dde4cd hwmon/lm78: Use d... |
152 153 |
return sprintf(buf, "%d ", IN_FROM_REG(data->in[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
154 |
} |
247dde4cd hwmon/lm78: Use d... |
155 156 |
static ssize_t show_in_min(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
157 |
{ |
247dde4cd hwmon/lm78: Use d... |
158 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
1da177e4c Linux-2.6.12-rc2 |
159 |
struct lm78_data *data = lm78_update_device(dev); |
247dde4cd hwmon/lm78: Use d... |
160 161 |
return sprintf(buf, "%d ", IN_FROM_REG(data->in_min[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
162 |
} |
247dde4cd hwmon/lm78: Use d... |
163 164 |
static ssize_t show_in_max(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
165 |
{ |
247dde4cd hwmon/lm78: Use d... |
166 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
1da177e4c Linux-2.6.12-rc2 |
167 |
struct lm78_data *data = lm78_update_device(dev); |
247dde4cd hwmon/lm78: Use d... |
168 169 |
return sprintf(buf, "%d ", IN_FROM_REG(data->in_max[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
170 |
} |
247dde4cd hwmon/lm78: Use d... |
171 172 |
static ssize_t set_in_min(struct device *dev, struct device_attribute *da, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
173 |
{ |
247dde4cd hwmon/lm78: Use d... |
174 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
c40769fee hwmon/lm78: No lo... |
175 |
struct lm78_data *data = dev_get_drvdata(dev); |
247dde4cd hwmon/lm78: Use d... |
176 |
int nr = attr->index; |
9b03079fc hwmon: (lm78) Fix... |
177 178 179 180 181 182 |
unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
183 |
|
9a61bf630 [PATCH] hwmon: Se... |
184 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
185 |
data->in_min[nr] = IN_TO_REG(val); |
c59cc301e hwmon/lm78: Be le... |
186 |
lm78_write_value(data, LM78_REG_IN_MIN(nr), data->in_min[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
187 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
188 189 |
return count; } |
247dde4cd hwmon/lm78: Use d... |
190 191 |
static ssize_t set_in_max(struct device *dev, struct device_attribute *da, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
192 |
{ |
247dde4cd hwmon/lm78: Use d... |
193 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
c40769fee hwmon/lm78: No lo... |
194 |
struct lm78_data *data = dev_get_drvdata(dev); |
247dde4cd hwmon/lm78: Use d... |
195 |
int nr = attr->index; |
9b03079fc hwmon: (lm78) Fix... |
196 197 198 199 200 201 |
unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
202 |
|
9a61bf630 [PATCH] hwmon: Se... |
203 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
204 |
data->in_max[nr] = IN_TO_REG(val); |
c59cc301e hwmon/lm78: Be le... |
205 |
lm78_write_value(data, LM78_REG_IN_MAX(nr), data->in_max[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
206 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
207 208 |
return count; } |
9b03079fc hwmon: (lm78) Fix... |
209 |
|
1da177e4c Linux-2.6.12-rc2 |
210 |
#define show_in_offset(offset) \ |
247dde4cd hwmon/lm78: Use d... |
211 212 213 214 215 216 |
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in, NULL, offset); \ static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ show_in_min, set_in_min, offset); \ static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ show_in_max, set_in_max, offset); |
1da177e4c Linux-2.6.12-rc2 |
217 218 219 220 221 222 223 224 225 226 |
show_in_offset(0); show_in_offset(1); show_in_offset(2); show_in_offset(3); show_in_offset(4); show_in_offset(5); show_in_offset(6); /* Temperature */ |
247dde4cd hwmon/lm78: Use d... |
227 228 |
static ssize_t show_temp(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
229 230 231 232 233 |
{ struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d ", TEMP_FROM_REG(data->temp)); } |
247dde4cd hwmon/lm78: Use d... |
234 235 |
static ssize_t show_temp_over(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
236 237 238 239 240 |
{ struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d ", TEMP_FROM_REG(data->temp_over)); } |
247dde4cd hwmon/lm78: Use d... |
241 242 |
static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
243 |
{ |
c40769fee hwmon/lm78: No lo... |
244 |
struct lm78_data *data = dev_get_drvdata(dev); |
9b03079fc hwmon: (lm78) Fix... |
245 246 247 248 249 250 |
long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
251 |
|
9a61bf630 [PATCH] hwmon: Se... |
252 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
253 |
data->temp_over = TEMP_TO_REG(val); |
c59cc301e hwmon/lm78: Be le... |
254 |
lm78_write_value(data, LM78_REG_TEMP_OVER, data->temp_over); |
9a61bf630 [PATCH] hwmon: Se... |
255 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
256 257 |
return count; } |
247dde4cd hwmon/lm78: Use d... |
258 259 |
static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
260 261 262 263 264 |
{ struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d ", TEMP_FROM_REG(data->temp_hyst)); } |
247dde4cd hwmon/lm78: Use d... |
265 266 |
static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
267 |
{ |
c40769fee hwmon/lm78: No lo... |
268 |
struct lm78_data *data = dev_get_drvdata(dev); |
9b03079fc hwmon: (lm78) Fix... |
269 270 271 272 273 274 |
long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
275 |
|
9a61bf630 [PATCH] hwmon: Se... |
276 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
277 |
data->temp_hyst = TEMP_TO_REG(val); |
c59cc301e hwmon/lm78: Be le... |
278 |
lm78_write_value(data, LM78_REG_TEMP_HYST, data->temp_hyst); |
9a61bf630 [PATCH] hwmon: Se... |
279 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
280 281 282 283 284 285 286 287 288 289 |
return count; } static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_over, set_temp_over); static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_hyst, set_temp_hyst); /* 3 Fans */ |
247dde4cd hwmon/lm78: Use d... |
290 291 |
static ssize_t show_fan(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
292 |
{ |
247dde4cd hwmon/lm78: Use d... |
293 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
1da177e4c Linux-2.6.12-rc2 |
294 |
struct lm78_data *data = lm78_update_device(dev); |
247dde4cd hwmon/lm78: Use d... |
295 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
296 297 |
return sprintf(buf, "%d ", FAN_FROM_REG(data->fan[nr], |
9b03079fc hwmon: (lm78) Fix... |
298 |
DIV_FROM_REG(data->fan_div[nr]))); |
1da177e4c Linux-2.6.12-rc2 |
299 |
} |
247dde4cd hwmon/lm78: Use d... |
300 301 |
static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
302 |
{ |
247dde4cd hwmon/lm78: Use d... |
303 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
1da177e4c Linux-2.6.12-rc2 |
304 |
struct lm78_data *data = lm78_update_device(dev); |
247dde4cd hwmon/lm78: Use d... |
305 |
int nr = attr->index; |
9b03079fc hwmon: (lm78) Fix... |
306 307 308 |
return sprintf(buf, "%d ", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); |
1da177e4c Linux-2.6.12-rc2 |
309 |
} |
247dde4cd hwmon/lm78: Use d... |
310 311 |
static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
312 |
{ |
247dde4cd hwmon/lm78: Use d... |
313 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
c40769fee hwmon/lm78: No lo... |
314 |
struct lm78_data *data = dev_get_drvdata(dev); |
247dde4cd hwmon/lm78: Use d... |
315 |
int nr = attr->index; |
9b03079fc hwmon: (lm78) Fix... |
316 317 318 319 320 321 |
unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
322 |
|
9a61bf630 [PATCH] hwmon: Se... |
323 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
324 |
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); |
c59cc301e hwmon/lm78: Be le... |
325 |
lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
326 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
327 328 |
return count; } |
247dde4cd hwmon/lm78: Use d... |
329 330 |
static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
331 |
{ |
247dde4cd hwmon/lm78: Use d... |
332 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
1da177e4c Linux-2.6.12-rc2 |
333 |
struct lm78_data *data = lm78_update_device(dev); |
247dde4cd hwmon/lm78: Use d... |
334 335 |
return sprintf(buf, "%d ", DIV_FROM_REG(data->fan_div[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
336 |
} |
9b03079fc hwmon: (lm78) Fix... |
337 338 339 340 341 342 |
/* * Note: we save and restore the fan minimum here, because its value is * determined in part by the fan divisor. This follows the principle of * least surprise; the user doesn't expect the fan minimum to change just * because the divisor changed. */ |
247dde4cd hwmon/lm78: Use d... |
343 344 |
static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
345 |
{ |
247dde4cd hwmon/lm78: Use d... |
346 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
c40769fee hwmon/lm78: No lo... |
347 |
struct lm78_data *data = dev_get_drvdata(dev); |
247dde4cd hwmon/lm78: Use d... |
348 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
349 350 |
unsigned long min; u8 reg; |
9b03079fc hwmon: (lm78) Fix... |
351 352 353 354 355 356 |
unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
357 |
|
9a61bf630 [PATCH] hwmon: Se... |
358 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
359 360 361 362 |
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); switch (val) { |
9b03079fc hwmon: (lm78) Fix... |
363 364 365 366 367 368 369 370 371 372 373 374 |
case 1: data->fan_div[nr] = 0; break; case 2: data->fan_div[nr] = 1; break; case 4: data->fan_div[nr] = 2; break; case 8: data->fan_div[nr] = 3; break; |
1da177e4c Linux-2.6.12-rc2 |
375 |
default: |
b55f37572 hwmon: Fix checkp... |
376 377 378 379 |
dev_err(dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8! ", val); |
9a61bf630 [PATCH] hwmon: Se... |
380 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
381 382 |
return -EINVAL; } |
c59cc301e hwmon/lm78: Be le... |
383 |
reg = lm78_read_value(data, LM78_REG_VID_FANDIV); |
1da177e4c Linux-2.6.12-rc2 |
384 385 386 387 388 389 390 391 |
switch (nr) { case 0: reg = (reg & 0xcf) | (data->fan_div[nr] << 4); break; case 1: reg = (reg & 0x3f) | (data->fan_div[nr] << 6); break; } |
c59cc301e hwmon/lm78: Be le... |
392 |
lm78_write_value(data, LM78_REG_VID_FANDIV, reg); |
1da177e4c Linux-2.6.12-rc2 |
393 394 395 |
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); |
c59cc301e hwmon/lm78: Be le... |
396 |
lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
397 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
398 399 400 |
return count; } |
247dde4cd hwmon/lm78: Use d... |
401 402 403 404 405 |
#define show_fan_offset(offset) \ static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ show_fan, NULL, offset - 1); \ static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_min, set_fan_min, offset - 1); |
1da177e4c Linux-2.6.12-rc2 |
406 407 408 409 410 411 |
show_fan_offset(1); show_fan_offset(2); show_fan_offset(3); /* Fan 3 divisor is locked in H/W */ |
247dde4cd hwmon/lm78: Use d... |
412 413 414 415 416 |
static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div, set_fan_div, 0); static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div, set_fan_div, 1); static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2); |
1da177e4c Linux-2.6.12-rc2 |
417 418 |
/* VID */ |
247dde4cd hwmon/lm78: Use d... |
419 420 |
static ssize_t show_vid(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
421 422 |
{ struct lm78_data *data = lm78_update_device(dev); |
d0d3cd696 [PATCH] hwmon: Fi... |
423 424 |
return sprintf(buf, "%d ", vid_from_reg(data->vid, 82)); |
1da177e4c Linux-2.6.12-rc2 |
425 426 427 428 |
} static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* Alarms */ |
247dde4cd hwmon/lm78: Use d... |
429 430 |
static ssize_t show_alarms(struct device *dev, struct device_attribute *da, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
431 432 433 434 435 436 |
{ struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%u ", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
428a7039c hwmon: (lm78) Add... |
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
static ssize_t show_alarm(struct device *dev, struct device_attribute *da, char *buf) { struct lm78_data *data = lm78_update_device(dev); int nr = to_sensor_dev_attr(da)->index; return sprintf(buf, "%u ", (data->alarms >> nr) & 1); } static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); |
8eb406100 hwmon: (lm78) Con... |
456 |
static struct attribute *lm78_attrs[] = { |
247dde4cd hwmon/lm78: Use d... |
457 458 459 |
&sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
460 |
&sensor_dev_attr_in0_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
461 462 463 |
&sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in1_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
464 |
&sensor_dev_attr_in1_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
465 466 467 |
&sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, &sensor_dev_attr_in2_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
468 |
&sensor_dev_attr_in2_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
469 470 471 |
&sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in3_min.dev_attr.attr, &sensor_dev_attr_in3_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
472 |
&sensor_dev_attr_in3_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
473 474 475 |
&sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
476 |
&sensor_dev_attr_in4_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
477 478 479 |
&sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in5_min.dev_attr.attr, &sensor_dev_attr_in5_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
480 |
&sensor_dev_attr_in5_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
481 482 483 |
&sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in6_min.dev_attr.attr, &sensor_dev_attr_in6_max.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
484 |
&sensor_dev_attr_in6_alarm.dev_attr.attr, |
c1685f61b hwmon: Fix unchec... |
485 486 487 |
&dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_max_hyst.attr, |
428a7039c hwmon: (lm78) Add... |
488 |
&sensor_dev_attr_temp1_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
489 490 491 |
&sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
492 |
&sensor_dev_attr_fan1_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
493 494 495 |
&sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
496 |
&sensor_dev_attr_fan2_alarm.dev_attr.attr, |
247dde4cd hwmon/lm78: Use d... |
497 498 499 |
&sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, |
428a7039c hwmon: (lm78) Add... |
500 |
&sensor_dev_attr_fan3_alarm.dev_attr.attr, |
c1685f61b hwmon: Fix unchec... |
501 502 503 504 505 |
&dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, NULL }; |
8eb406100 hwmon: (lm78) Con... |
506 |
ATTRIBUTE_GROUPS(lm78); |
c1685f61b hwmon: Fix unchec... |
507 |
|
90534c5c5 hwmon: (lm78) Mak... |
508 509 510 511 512 513 514 515 516 |
/* * ISA related code */ #ifdef CONFIG_ISA /* ISA device, if found */ static struct platform_device *pdev; static unsigned short isa_address = 0x290; |
90534c5c5 hwmon: (lm78) Mak... |
517 518 519 520 |
static struct lm78_data *lm78_data_if_isa(void) { return pdev ? platform_get_drvdata(pdev) : NULL; } |
18c73f904 hwmon: (lm78) Det... |
521 522 523 |
/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */ static int lm78_alias_detect(struct i2c_client *client, u8 chipid) { |
0c6e97317 hwmon: (lm78) Con... |
524 |
struct lm78_data *isa; |
18c73f904 hwmon: (lm78) Det... |
525 526 527 528 |
int i; if (!pdev) /* No ISA chip */ return 0; |
18c73f904 hwmon: (lm78) Det... |
529 530 531 532 533 534 |
isa = platform_get_drvdata(pdev); if (lm78_read_value(isa, LM78_REG_I2C_ADDR) != client->addr) return 0; /* Address doesn't match */ if ((lm78_read_value(isa, LM78_REG_CHIPID) & 0xfe) != (chipid & 0xfe)) return 0; /* Chip type doesn't match */ |
9b03079fc hwmon: (lm78) Fix... |
535 536 537 538 |
/* * We compare all the limit registers, the config register and the * interrupt mask registers */ |
18c73f904 hwmon: (lm78) Det... |
539 |
for (i = 0x2b; i <= 0x3d; i++) { |
0c6e97317 hwmon: (lm78) Con... |
540 541 |
if (lm78_read_value(isa, i) != i2c_smbus_read_byte_data(client, i)) |
18c73f904 hwmon: (lm78) Det... |
542 543 544 |
return 0; } if (lm78_read_value(isa, LM78_REG_CONFIG) != |
0c6e97317 hwmon: (lm78) Con... |
545 |
i2c_smbus_read_byte_data(client, LM78_REG_CONFIG)) |
18c73f904 hwmon: (lm78) Det... |
546 547 |
return 0; for (i = 0x43; i <= 0x46; i++) { |
0c6e97317 hwmon: (lm78) Con... |
548 549 |
if (lm78_read_value(isa, i) != i2c_smbus_read_byte_data(client, i)) |
18c73f904 hwmon: (lm78) Det... |
550 551 552 553 554 |
return 0; } return 1; } |
90534c5c5 hwmon: (lm78) Mak... |
555 556 557 558 559 560 561 562 563 564 565 566 |
#else /* !CONFIG_ISA */ static int lm78_alias_detect(struct i2c_client *client, u8 chipid) { return 0; } static struct lm78_data *lm78_data_if_isa(void) { return NULL; } #endif /* CONFIG_ISA */ |
18c73f904 hwmon: (lm78) Det... |
567 |
|
310ec7921 i2c: Drop the kin... |
568 |
static int lm78_i2c_detect(struct i2c_client *client, |
0c6e97317 hwmon: (lm78) Con... |
569 |
struct i2c_board_info *info) |
1da177e4c Linux-2.6.12-rc2 |
570 |
{ |
0c6e97317 hwmon: (lm78) Con... |
571 |
int i; |
90534c5c5 hwmon: (lm78) Mak... |
572 |
struct lm78_data *isa = lm78_data_if_isa(); |
0c6e97317 hwmon: (lm78) Con... |
573 574 575 |
const char *client_name; struct i2c_adapter *adapter = client->adapter; int address = client->addr; |
1da177e4c Linux-2.6.12-rc2 |
576 |
|
0c6e97317 hwmon: (lm78) Con... |
577 578 |
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
579 |
|
9b03079fc hwmon: (lm78) Fix... |
580 581 582 583 584 |
/* * We block updates of the ISA device to minimize the risk of * concurrent access to the same LM78 chip through different * interfaces. */ |
0c6e97317 hwmon: (lm78) Con... |
585 586 |
if (isa) mutex_lock(&isa->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
587 |
|
52df6440a hwmon: Clean up d... |
588 589 590 591 592 593 594 595 |
if ((i2c_smbus_read_byte_data(client, LM78_REG_CONFIG) & 0x80) || i2c_smbus_read_byte_data(client, LM78_REG_I2C_ADDR) != address) goto err_nodev; /* Explicitly prevent the misdetection of Winbond chips */ i = i2c_smbus_read_byte_data(client, 0x4f); if (i == 0xa3 || i == 0x5c) goto err_nodev; |
1da177e4c Linux-2.6.12-rc2 |
596 597 |
/* Determine the chip type. */ |
52df6440a hwmon: Clean up d... |
598 599 600 601 602 603 604 605 606 607 |
i = i2c_smbus_read_byte_data(client, LM78_REG_CHIPID); if (i == 0x00 || i == 0x20 /* LM78 */ || i == 0x40) /* LM78-J */ client_name = "lm78"; else if ((i & 0xfe) == 0xc0) client_name = "lm79"; else goto err_nodev; if (lm78_alias_detect(client, i)) { |
b55f37572 hwmon: Fix checkp... |
608 609 610 611 |
dev_dbg(&adapter->dev, "Device at 0x%02x appears to be the same as ISA device ", address); |
52df6440a hwmon: Clean up d... |
612 |
goto err_nodev; |
1da177e4c Linux-2.6.12-rc2 |
613 |
} |
0c6e97317 hwmon: (lm78) Con... |
614 615 |
if (isa) mutex_unlock(&isa->update_lock); |
0c6e97317 hwmon: (lm78) Con... |
616 |
strlcpy(info->type, client_name, I2C_NAME_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
617 |
|
0c6e97317 hwmon: (lm78) Con... |
618 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
619 |
|
0c6e97317 hwmon: (lm78) Con... |
620 621 622 623 624 625 626 627 628 |
err_nodev: if (isa) mutex_unlock(&isa->update_lock); return -ENODEV; } static int lm78_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { |
8eb406100 hwmon: (lm78) Con... |
629 630 |
struct device *dev = &client->dev; struct device *hwmon_dev; |
0c6e97317 hwmon: (lm78) Con... |
631 |
struct lm78_data *data; |
0c6e97317 hwmon: (lm78) Con... |
632 |
|
8eb406100 hwmon: (lm78) Con... |
633 |
data = devm_kzalloc(dev, sizeof(struct lm78_data), GFP_KERNEL); |
0c6e97317 hwmon: (lm78) Con... |
634 635 |
if (!data) return -ENOMEM; |
0c6e97317 hwmon: (lm78) Con... |
636 637 |
data->client = client; data->type = id->driver_data; |
1da177e4c Linux-2.6.12-rc2 |
638 639 |
/* Initialize the LM78 chip */ |
c59cc301e hwmon/lm78: Be le... |
640 |
lm78_init_device(data); |
1da177e4c Linux-2.6.12-rc2 |
641 |
|
8eb406100 hwmon: (lm78) Con... |
642 643 644 |
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, lm78_groups); return PTR_ERR_OR_ZERO(hwmon_dev); |
c40769fee hwmon/lm78: No lo... |
645 |
} |
ed4cebdf9 hwmon: (lm78) Avo... |
646 647 648 649 650 651 |
static const struct i2c_device_id lm78_i2c_id[] = { { "lm78", lm78 }, { "lm79", lm79 }, { } }; MODULE_DEVICE_TABLE(i2c, lm78_i2c_id); |
6e1b5029d hwmon: (lm78) Sto... |
652 |
|
ed4cebdf9 hwmon: (lm78) Avo... |
653 654 655 656 657 658 |
static struct i2c_driver lm78_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "lm78", }, .probe = lm78_i2c_probe, |
ed4cebdf9 hwmon: (lm78) Avo... |
659 660 661 662 |
.id_table = lm78_i2c_id, .detect = lm78_i2c_detect, .address_list = normal_i2c, }; |
1da177e4c Linux-2.6.12-rc2 |
663 |
|
9b03079fc hwmon: (lm78) Fix... |
664 665 666 667 668 669 670 |
/* * The SMBus locks itself, but ISA access must be locked explicitly! * We don't want to lock the whole ISA bus, so we lock each client * separately. * We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, * would slow down the LM78 access and should not be necessary. */ |
c59cc301e hwmon/lm78: Be le... |
671 |
static int lm78_read_value(struct lm78_data *data, u8 reg) |
1da177e4c Linux-2.6.12-rc2 |
672 |
{ |
0c6e97317 hwmon: (lm78) Con... |
673 |
struct i2c_client *client = data->client; |
c59cc301e hwmon/lm78: Be le... |
674 |
|
90534c5c5 hwmon: (lm78) Mak... |
675 |
#ifdef CONFIG_ISA |
0c6e97317 hwmon: (lm78) Con... |
676 |
if (!client) { /* ISA device */ |
c59cc301e hwmon/lm78: Be le... |
677 |
int res; |
9a61bf630 [PATCH] hwmon: Se... |
678 |
mutex_lock(&data->lock); |
6e1b5029d hwmon: (lm78) Sto... |
679 680 |
outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); res = inb_p(data->isa_addr + LM78_DATA_REG_OFFSET); |
9a61bf630 [PATCH] hwmon: Se... |
681 |
mutex_unlock(&data->lock); |
1da177e4c Linux-2.6.12-rc2 |
682 683 |
return res; } else |
90534c5c5 hwmon: (lm78) Mak... |
684 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
685 686 |
return i2c_smbus_read_byte_data(client, reg); } |
c59cc301e hwmon/lm78: Be le... |
687 |
static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) |
1da177e4c Linux-2.6.12-rc2 |
688 |
{ |
0c6e97317 hwmon: (lm78) Con... |
689 |
struct i2c_client *client = data->client; |
c59cc301e hwmon/lm78: Be le... |
690 |
|
90534c5c5 hwmon: (lm78) Mak... |
691 |
#ifdef CONFIG_ISA |
0c6e97317 hwmon: (lm78) Con... |
692 |
if (!client) { /* ISA device */ |
9a61bf630 [PATCH] hwmon: Se... |
693 |
mutex_lock(&data->lock); |
6e1b5029d hwmon: (lm78) Sto... |
694 695 |
outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); outb_p(value, data->isa_addr + LM78_DATA_REG_OFFSET); |
9a61bf630 [PATCH] hwmon: Se... |
696 |
mutex_unlock(&data->lock); |
1da177e4c Linux-2.6.12-rc2 |
697 698 |
return 0; } else |
90534c5c5 hwmon: (lm78) Mak... |
699 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
700 701 |
return i2c_smbus_write_byte_data(client, reg, value); } |
c59cc301e hwmon/lm78: Be le... |
702 |
static void lm78_init_device(struct lm78_data *data) |
1da177e4c Linux-2.6.12-rc2 |
703 |
{ |
c40769fee hwmon/lm78: No lo... |
704 705 |
u8 config; int i; |
1da177e4c Linux-2.6.12-rc2 |
706 707 |
/* Start monitoring */ |
c59cc301e hwmon/lm78: Be le... |
708 |
config = lm78_read_value(data, LM78_REG_CONFIG); |
c40769fee hwmon/lm78: No lo... |
709 |
if ((config & 0x09) != 0x01) |
c59cc301e hwmon/lm78: Be le... |
710 |
lm78_write_value(data, LM78_REG_CONFIG, |
1da177e4c Linux-2.6.12-rc2 |
711 |
(config & 0xf7) | 0x01); |
c40769fee hwmon/lm78: No lo... |
712 713 714 |
/* A few vars need to be filled upon startup */ for (i = 0; i < 3; i++) { |
c59cc301e hwmon/lm78: Be le... |
715 |
data->fan_min[i] = lm78_read_value(data, |
c40769fee hwmon/lm78: No lo... |
716 717 718 719 |
LM78_REG_FAN_MIN(i)); } mutex_init(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
720 721 722 723 |
} static struct lm78_data *lm78_update_device(struct device *dev) { |
c40769fee hwmon/lm78: No lo... |
724 |
struct lm78_data *data = dev_get_drvdata(dev); |
1da177e4c Linux-2.6.12-rc2 |
725 |
int i; |
9a61bf630 [PATCH] hwmon: Se... |
726 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
727 728 729 |
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { |
c40769fee hwmon/lm78: No lo... |
730 731 |
dev_dbg(dev, "Starting lm78 update "); |
1da177e4c Linux-2.6.12-rc2 |
732 733 734 |
for (i = 0; i <= 6; i++) { data->in[i] = |
c59cc301e hwmon/lm78: Be le... |
735 |
lm78_read_value(data, LM78_REG_IN(i)); |
1da177e4c Linux-2.6.12-rc2 |
736 |
data->in_min[i] = |
c59cc301e hwmon/lm78: Be le... |
737 |
lm78_read_value(data, LM78_REG_IN_MIN(i)); |
1da177e4c Linux-2.6.12-rc2 |
738 |
data->in_max[i] = |
c59cc301e hwmon/lm78: Be le... |
739 |
lm78_read_value(data, LM78_REG_IN_MAX(i)); |
1da177e4c Linux-2.6.12-rc2 |
740 741 742 |
} for (i = 0; i < 3; i++) { data->fan[i] = |
c59cc301e hwmon/lm78: Be le... |
743 |
lm78_read_value(data, LM78_REG_FAN(i)); |
1da177e4c Linux-2.6.12-rc2 |
744 |
data->fan_min[i] = |
c59cc301e hwmon/lm78: Be le... |
745 |
lm78_read_value(data, LM78_REG_FAN_MIN(i)); |
1da177e4c Linux-2.6.12-rc2 |
746 |
} |
c59cc301e hwmon/lm78: Be le... |
747 |
data->temp = lm78_read_value(data, LM78_REG_TEMP); |
1da177e4c Linux-2.6.12-rc2 |
748 |
data->temp_over = |
c59cc301e hwmon/lm78: Be le... |
749 |
lm78_read_value(data, LM78_REG_TEMP_OVER); |
1da177e4c Linux-2.6.12-rc2 |
750 |
data->temp_hyst = |
c59cc301e hwmon/lm78: Be le... |
751 752 |
lm78_read_value(data, LM78_REG_TEMP_HYST); i = lm78_read_value(data, LM78_REG_VID_FANDIV); |
1da177e4c Linux-2.6.12-rc2 |
753 754 755 |
data->vid = i & 0x0f; if (data->type == lm79) data->vid |= |
c59cc301e hwmon/lm78: Be le... |
756 |
(lm78_read_value(data, LM78_REG_CHIPID) & |
1da177e4c Linux-2.6.12-rc2 |
757 758 759 760 761 |
0x01) << 4; else data->vid |= 0x10; data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = i >> 6; |
c59cc301e hwmon/lm78: Be le... |
762 763 |
data->alarms = lm78_read_value(data, LM78_REG_ALARM1) + (lm78_read_value(data, LM78_REG_ALARM2) << 8); |
1da177e4c Linux-2.6.12-rc2 |
764 765 766 767 768 |
data->last_updated = jiffies; data->valid = 1; data->fan_div[2] = 1; } |
9a61bf630 [PATCH] hwmon: Se... |
769 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
770 771 772 |
return data; } |
90534c5c5 hwmon: (lm78) Mak... |
773 |
#ifdef CONFIG_ISA |
6c931ae1c hwmon: remove use... |
774 |
static int lm78_isa_probe(struct platform_device *pdev) |
ed4cebdf9 hwmon: (lm78) Avo... |
775 |
{ |
8eb406100 hwmon: (lm78) Con... |
776 777 |
struct device *dev = &pdev->dev; struct device *hwmon_dev; |
ed4cebdf9 hwmon: (lm78) Avo... |
778 779 780 781 782 |
struct lm78_data *data; struct resource *res; /* Reserve the ISA region */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
8eb406100 hwmon: (lm78) Con... |
783 |
if (!devm_request_region(dev, res->start + LM78_ADDR_REG_OFFSET, |
7b7bb90ca hwmon: (lm78) Con... |
784 785 |
2, "lm78")) return -EBUSY; |
8eb406100 hwmon: (lm78) Con... |
786 |
data = devm_kzalloc(dev, sizeof(struct lm78_data), GFP_KERNEL); |
7b7bb90ca hwmon: (lm78) Con... |
787 788 |
if (!data) return -ENOMEM; |
ed4cebdf9 hwmon: (lm78) Avo... |
789 |
|
ed4cebdf9 hwmon: (lm78) Avo... |
790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
mutex_init(&data->lock); data->isa_addr = res->start; platform_set_drvdata(pdev, data); if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) { data->type = lm79; data->name = "lm79"; } else { data->type = lm78; data->name = "lm78"; } /* Initialize the LM78 chip */ lm78_init_device(data); |
8eb406100 hwmon: (lm78) Con... |
804 805 806 |
hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name, data, lm78_groups); return PTR_ERR_OR_ZERO(hwmon_dev); |
ed4cebdf9 hwmon: (lm78) Avo... |
807 808 809 810 |
} static struct platform_driver lm78_isa_driver = { .driver = { |
ed4cebdf9 hwmon: (lm78) Avo... |
811 812 813 |
.name = "lm78", }, .probe = lm78_isa_probe, |
ed4cebdf9 hwmon: (lm78) Avo... |
814 |
}; |
c40769fee hwmon/lm78: No lo... |
815 816 817 818 |
/* return 1 if a supported chip is found, 0 otherwise */ static int __init lm78_isa_found(unsigned short address) { int val, save, found = 0; |
197027e6e hwmon: (lm78) Req... |
819 |
int port; |
9b03079fc hwmon: (lm78) Fix... |
820 821 |
/* * Some boards declare base+0 to base+7 as a PNP device, some base+4 |
197027e6e hwmon: (lm78) Req... |
822 |
* to base+7 and some base+5 to base+6. So we better request each port |
9b03079fc hwmon: (lm78) Fix... |
823 824 |
* individually for the probing phase. */ |
197027e6e hwmon: (lm78) Req... |
825 826 |
for (port = address; port < address + LM78_EXTENT; port++) { if (!request_region(port, 1, "lm78")) { |
ce47da742 hwmon: (lm78) Use... |
827 828 |
pr_debug("Failed to request port 0x%x ", port); |
197027e6e hwmon: (lm78) Req... |
829 830 |
goto release; } |
47c15532d hwmon: (lm78) Fix... |
831 |
} |
c40769fee hwmon/lm78: No lo... |
832 833 |
#define REALLY_SLOW_IO |
9b03079fc hwmon: (lm78) Fix... |
834 835 836 837 |
/* * We need the timeouts for at least some LM78-like * chips. But only if we read 'undefined' registers. */ |
c40769fee hwmon/lm78: No lo... |
838 839 840 841 842 843 |
val = inb_p(address + 1); if (inb_p(address + 2) != val || inb_p(address + 3) != val || inb_p(address + 7) != val) goto release; #undef REALLY_SLOW_IO |
9b03079fc hwmon: (lm78) Fix... |
844 845 846 847 |
/* * We should be able to change the 7 LSB of the address port. The * MSB (busy flag) should be clear initially, set after the write. */ |
c40769fee hwmon/lm78: No lo... |
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 |
save = inb_p(address + LM78_ADDR_REG_OFFSET); if (save & 0x80) goto release; val = ~save & 0x7f; outb_p(val, address + LM78_ADDR_REG_OFFSET); if (inb_p(address + LM78_ADDR_REG_OFFSET) != (val | 0x80)) { outb_p(save, address + LM78_ADDR_REG_OFFSET); goto release; } /* We found a device, now see if it could be an LM78 */ outb_p(LM78_REG_CONFIG, address + LM78_ADDR_REG_OFFSET); val = inb_p(address + LM78_DATA_REG_OFFSET); if (val & 0x80) goto release; outb_p(LM78_REG_I2C_ADDR, address + LM78_ADDR_REG_OFFSET); val = inb_p(address + LM78_DATA_REG_OFFSET); if (val < 0x03 || val > 0x77) /* Not a valid I2C address */ goto release; /* The busy flag should be clear again */ if (inb_p(address + LM78_ADDR_REG_OFFSET) & 0x80) goto release; /* Explicitly prevent the misdetection of Winbond chips */ outb_p(0x4f, address + LM78_ADDR_REG_OFFSET); val = inb_p(address + LM78_DATA_REG_OFFSET); if (val == 0xa3 || val == 0x5c) goto release; /* Explicitly prevent the misdetection of ITE chips */ outb_p(0x58, address + LM78_ADDR_REG_OFFSET); val = inb_p(address + LM78_DATA_REG_OFFSET); if (val == 0x90) goto release; /* Determine the chip type */ outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET); val = inb_p(address + LM78_DATA_REG_OFFSET); |
acf346a31 hwmon: fix lm78 d... |
887 |
if (val == 0x00 || val == 0x20 /* LM78 */ |
c40769fee hwmon/lm78: No lo... |
888 889 890 891 892 |
|| val == 0x40 /* LM78-J */ || (val & 0xfe) == 0xc0) /* LM79 */ found = 1; if (found) |
ce47da742 hwmon: (lm78) Use... |
893 894 |
pr_info("Found an %s chip at %#x ", |
c40769fee hwmon/lm78: No lo... |
895 896 897 |
val & 0x80 ? "LM79" : "LM78", (int)address); release: |
197027e6e hwmon: (lm78) Req... |
898 899 |
for (port--; port >= address; port--) release_region(port, 1); |
c40769fee hwmon/lm78: No lo... |
900 901 902 903 904 905 906 |
return found; } static int __init lm78_isa_device_add(unsigned short address) { struct resource res = { .start = address, |
15bde2f1a hwmon: End of I/O... |
907 |
.end = address + LM78_EXTENT - 1, |
c40769fee hwmon/lm78: No lo... |
908 909 910 911 912 913 914 915 |
.name = "lm78", .flags = IORESOURCE_IO, }; int err; pdev = platform_device_alloc("lm78", address); if (!pdev) { err = -ENOMEM; |
ce47da742 hwmon: (lm78) Use... |
916 917 |
pr_err("Device allocation failed "); |
c40769fee hwmon/lm78: No lo... |
918 919 920 921 922 |
goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { |
ce47da742 hwmon: (lm78) Use... |
923 924 |
pr_err("Device resource addition failed (%d) ", err); |
c40769fee hwmon/lm78: No lo... |
925 926 927 928 929 |
goto exit_device_put; } err = platform_device_add(pdev); if (err) { |
ce47da742 hwmon: (lm78) Use... |
930 931 |
pr_err("Device addition failed (%d) ", err); |
c40769fee hwmon/lm78: No lo... |
932 933 934 935 936 937 938 939 940 941 942 |
goto exit_device_put; } return 0; exit_device_put: platform_device_put(pdev); exit: pdev = NULL; return err; } |
90534c5c5 hwmon: (lm78) Mak... |
943 |
static int __init lm78_isa_register(void) |
1da177e4c Linux-2.6.12-rc2 |
944 |
{ |
fde095090 [PATCH] I2C: Sepa... |
945 |
int res; |
c40769fee hwmon/lm78: No lo... |
946 947 948 |
if (lm78_isa_found(isa_address)) { res = platform_driver_register(&lm78_isa_driver); if (res) |
18c73f904 hwmon: (lm78) Det... |
949 |
goto exit; |
fde095090 [PATCH] I2C: Sepa... |
950 |
|
c40769fee hwmon/lm78: No lo... |
951 952 953 954 955 |
/* Sets global pdev as a side effect */ res = lm78_isa_device_add(isa_address); if (res) goto exit_unreg_isa_driver; } |
fde095090 [PATCH] I2C: Sepa... |
956 957 |
return 0; |
c40769fee hwmon/lm78: No lo... |
958 959 960 |
exit_unreg_isa_driver: platform_driver_unregister(&lm78_isa_driver); |
c40769fee hwmon/lm78: No lo... |
961 962 |
exit: return res; |
1da177e4c Linux-2.6.12-rc2 |
963 |
} |
90534c5c5 hwmon: (lm78) Mak... |
964 |
static void lm78_isa_unregister(void) |
1da177e4c Linux-2.6.12-rc2 |
965 |
{ |
c40769fee hwmon/lm78: No lo... |
966 967 968 969 |
if (pdev) { platform_device_unregister(pdev); platform_driver_unregister(&lm78_isa_driver); } |
90534c5c5 hwmon: (lm78) Mak... |
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 |
} #else /* !CONFIG_ISA */ static int __init lm78_isa_register(void) { return 0; } static void lm78_isa_unregister(void) { } #endif /* CONFIG_ISA */ static int __init sm_lm78_init(void) { int res; |
9b03079fc hwmon: (lm78) Fix... |
986 987 988 989 |
/* * We register the ISA device first, so that we can skip the * registration of an I2C interface to the same device. */ |
90534c5c5 hwmon: (lm78) Mak... |
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 |
res = lm78_isa_register(); if (res) goto exit; res = i2c_add_driver(&lm78_driver); if (res) goto exit_unreg_isa_device; return 0; exit_unreg_isa_device: lm78_isa_unregister(); exit: return res; } static void __exit sm_lm78_exit(void) { lm78_isa_unregister(); |
1da177e4c Linux-2.6.12-rc2 |
1009 1010 |
i2c_del_driver(&lm78_driver); } |
7c81c60f3 Update Jean Delva... |
1011 |
MODULE_AUTHOR("Frodo Looijaard, Jean Delvare <jdelvare@suse.de>"); |
27fe048eb [PATCH] hwmon: ki... |
1012 |
MODULE_DESCRIPTION("LM78/LM79 driver"); |
1da177e4c Linux-2.6.12-rc2 |
1013 1014 1015 1016 |
MODULE_LICENSE("GPL"); module_init(sm_lm78_init); module_exit(sm_lm78_exit); |