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