Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
420 | giacomo | 1 | /* |
2 | it87.c - Part of lm_sensors, Linux kernel modules for hardware |
||
3 | monitoring. |
||
4 | |||
5 | Supports: IT8705F Super I/O chip w/LPC interface |
||
6 | IT8712F Super I/O chip w/LPC interface & SMbus |
||
7 | Sis950 A clone of the IT8705F |
||
8 | |||
9 | Copyright (c) 2001 Chris Gauthron <chrisg@0-in.com> |
||
10 | Largely inspired by lm78.c of the same package |
||
11 | |||
12 | This program is free software; you can redistribute it and/or modify |
||
13 | it under the terms of the GNU General Public License as published by |
||
14 | the Free Software Foundation; either version 2 of the License, or |
||
15 | (at your option) any later version. |
||
16 | |||
17 | This program is distributed in the hope that it will be useful, |
||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
20 | GNU General Public License for more details. |
||
21 | |||
22 | You should have received a copy of the GNU General Public License |
||
23 | along with this program; if not, write to the Free Software |
||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
25 | */ |
||
26 | |||
27 | /* |
||
28 | djg@pdp8.net David Gesswein 7/18/01 |
||
29 | Modified to fix bug with not all alarms enabled. |
||
30 | Added ability to read battery voltage and select temperature sensor |
||
31 | type at module load time. |
||
32 | */ |
||
33 | |||
34 | #include <linux/module.h> |
||
35 | #include <linux/init.h> |
||
36 | #include <linux/slab.h> |
||
37 | #include <linux/i2c.h> |
||
38 | #include <linux/i2c-sensor.h> |
||
39 | #include <asm/io.h> |
||
40 | |||
41 | |||
42 | /* Addresses to scan */ |
||
43 | static unsigned short normal_i2c[] = { I2C_CLIENT_END }; |
||
44 | static unsigned short normal_i2c_range[] = { 0x20, 0x2f, I2C_CLIENT_END }; |
||
45 | static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; |
||
46 | static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; |
||
47 | |||
48 | /* Insmod parameters */ |
||
49 | SENSORS_INSMOD_4(it87, it8705, it8712, sis950); |
||
50 | |||
51 | |||
52 | /* Update battery voltage after every reading if true */ |
||
53 | static int update_vbat = 0; |
||
54 | |||
55 | |||
56 | /* Enable Temp1 as thermal resistor */ |
||
57 | /* Enable Temp2 as thermal diode */ |
||
58 | /* Enable Temp3 as thermal resistor */ |
||
59 | static int temp_type = 0x2a; |
||
60 | |||
61 | /* Many IT87 constants specified below */ |
||
62 | |||
63 | /* Length of ISA address segment */ |
||
64 | #define IT87_EXTENT 8 |
||
65 | |||
66 | /* Where are the ISA address/data registers relative to the base address */ |
||
67 | #define IT87_ADDR_REG_OFFSET 5 |
||
68 | #define IT87_DATA_REG_OFFSET 6 |
||
69 | |||
70 | /*----- The IT87 registers -----*/ |
||
71 | |||
72 | #define IT87_REG_CONFIG 0x00 |
||
73 | |||
74 | #define IT87_REG_ALARM1 0x01 |
||
75 | #define IT87_REG_ALARM2 0x02 |
||
76 | #define IT87_REG_ALARM3 0x03 |
||
77 | |||
78 | #define IT87_REG_VID 0x0a |
||
79 | #define IT87_REG_FAN_DIV 0x0b |
||
80 | |||
81 | /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ |
||
82 | |||
83 | #define IT87_REG_FAN(nr) (0x0d + (nr)) |
||
84 | #define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) |
||
85 | #define IT87_REG_FAN_CTRL 0x13 |
||
86 | |||
87 | #define IT87_REG_VIN(nr) (0x20 + (nr)) |
||
88 | #define IT87_REG_TEMP(nr) (0x29 + (nr)) |
||
89 | |||
90 | #define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) |
||
91 | #define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) |
||
92 | #define IT87_REG_TEMP_HIGH(nr) (0x40 + ((nr) * 2)) |
||
93 | #define IT87_REG_TEMP_LOW(nr) (0x41 + ((nr) * 2)) |
||
94 | |||
95 | #define IT87_REG_I2C_ADDR 0x48 |
||
96 | |||
97 | #define IT87_REG_VIN_ENABLE 0x50 |
||
98 | #define IT87_REG_TEMP_ENABLE 0x51 |
||
99 | |||
100 | #define IT87_REG_CHIPID 0x58 |
||
101 | |||
102 | #define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) |
||
103 | #define IN_FROM_REG(val) (((val) * 16) / 10) |
||
104 | |||
105 | static inline u8 FAN_TO_REG(long rpm, int div) |
||
106 | { |
||
107 | if (rpm == 0) |
||
108 | return 255; |
||
109 | rpm = SENSORS_LIMIT(rpm, 1, 1000000); |
||
110 | return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, |
||
111 | 254); |
||
112 | } |
||
113 | |||
114 | #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) |
||
115 | |||
116 | #define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ |
||
117 | ((val)+5)/10),0,255)) |
||
118 | #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) |
||
119 | |||
120 | #define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ |
||
121 | 205-(val)*5) |
||
122 | #define ALARMS_FROM_REG(val) (val) |
||
123 | |||
124 | static int log2(int val) |
||
125 | { |
||
126 | int answer = 0; |
||
127 | while ((val >>= 1)) |
||
128 | answer++; |
||
129 | return answer; |
||
130 | } |
||
131 | #define DIV_TO_REG(val) log2(val) |
||
132 | #define DIV_FROM_REG(val) (1 << (val)) |
||
133 | |||
134 | /* Initial limits. Use the config file to set better limits. */ |
||
135 | #define IT87_INIT_IN_0 170 |
||
136 | #define IT87_INIT_IN_1 250 |
||
137 | #define IT87_INIT_IN_2 (330 / 2) |
||
138 | #define IT87_INIT_IN_3 (((500) * 100)/168) |
||
139 | #define IT87_INIT_IN_4 (((1200) * 10)/38) |
||
140 | #define IT87_INIT_IN_5 (((1200) * 10)/72) |
||
141 | #define IT87_INIT_IN_6 (((500) * 10)/56) |
||
142 | #define IT87_INIT_IN_7 (((500) * 100)/168) |
||
143 | |||
144 | #define IT87_INIT_IN_PERCENTAGE 10 |
||
145 | |||
146 | #define IT87_INIT_IN_MIN_0 \ |
||
147 | (IT87_INIT_IN_0 - IT87_INIT_IN_0 * IT87_INIT_IN_PERCENTAGE / 100) |
||
148 | #define IT87_INIT_IN_MAX_0 \ |
||
149 | (IT87_INIT_IN_0 + IT87_INIT_IN_0 * IT87_INIT_IN_PERCENTAGE / 100) |
||
150 | #define IT87_INIT_IN_MIN_1 \ |
||
151 | (IT87_INIT_IN_1 - IT87_INIT_IN_1 * IT87_INIT_IN_PERCENTAGE / 100) |
||
152 | #define IT87_INIT_IN_MAX_1 \ |
||
153 | (IT87_INIT_IN_1 + IT87_INIT_IN_1 * IT87_INIT_IN_PERCENTAGE / 100) |
||
154 | #define IT87_INIT_IN_MIN_2 \ |
||
155 | (IT87_INIT_IN_2 - IT87_INIT_IN_2 * IT87_INIT_IN_PERCENTAGE / 100) |
||
156 | #define IT87_INIT_IN_MAX_2 \ |
||
157 | (IT87_INIT_IN_2 + IT87_INIT_IN_2 * IT87_INIT_IN_PERCENTAGE / 100) |
||
158 | #define IT87_INIT_IN_MIN_3 \ |
||
159 | (IT87_INIT_IN_3 - IT87_INIT_IN_3 * IT87_INIT_IN_PERCENTAGE / 100) |
||
160 | #define IT87_INIT_IN_MAX_3 \ |
||
161 | (IT87_INIT_IN_3 + IT87_INIT_IN_3 * IT87_INIT_IN_PERCENTAGE / 100) |
||
162 | #define IT87_INIT_IN_MIN_4 \ |
||
163 | (IT87_INIT_IN_4 - IT87_INIT_IN_4 * IT87_INIT_IN_PERCENTAGE / 100) |
||
164 | #define IT87_INIT_IN_MAX_4 \ |
||
165 | (IT87_INIT_IN_4 + IT87_INIT_IN_4 * IT87_INIT_IN_PERCENTAGE / 100) |
||
166 | #define IT87_INIT_IN_MIN_5 \ |
||
167 | (IT87_INIT_IN_5 - IT87_INIT_IN_5 * IT87_INIT_IN_PERCENTAGE / 100) |
||
168 | #define IT87_INIT_IN_MAX_5 \ |
||
169 | (IT87_INIT_IN_5 + IT87_INIT_IN_5 * IT87_INIT_IN_PERCENTAGE / 100) |
||
170 | #define IT87_INIT_IN_MIN_6 \ |
||
171 | (IT87_INIT_IN_6 - IT87_INIT_IN_6 * IT87_INIT_IN_PERCENTAGE / 100) |
||
172 | #define IT87_INIT_IN_MAX_6 \ |
||
173 | (IT87_INIT_IN_6 + IT87_INIT_IN_6 * IT87_INIT_IN_PERCENTAGE / 100) |
||
174 | #define IT87_INIT_IN_MIN_7 \ |
||
175 | (IT87_INIT_IN_7 - IT87_INIT_IN_7 * IT87_INIT_IN_PERCENTAGE / 100) |
||
176 | #define IT87_INIT_IN_MAX_7 \ |
||
177 | (IT87_INIT_IN_7 + IT87_INIT_IN_7 * IT87_INIT_IN_PERCENTAGE / 100) |
||
178 | |||
179 | #define IT87_INIT_FAN_MIN_1 3000 |
||
180 | #define IT87_INIT_FAN_MIN_2 3000 |
||
181 | #define IT87_INIT_FAN_MIN_3 3000 |
||
182 | |||
183 | #define IT87_INIT_TEMP_HIGH_1 600 |
||
184 | #define IT87_INIT_TEMP_LOW_1 200 |
||
185 | #define IT87_INIT_TEMP_HIGH_2 600 |
||
186 | #define IT87_INIT_TEMP_LOW_2 200 |
||
187 | #define IT87_INIT_TEMP_HIGH_3 600 |
||
188 | #define IT87_INIT_TEMP_LOW_3 200 |
||
189 | |||
190 | /* For each registered IT87, we need to keep some data in memory. That |
||
191 | data is pointed to by it87_list[NR]->data. The structure itself is |
||
192 | dynamically allocated, at the same time when a new it87 client is |
||
193 | allocated. */ |
||
194 | struct it87_data { |
||
195 | struct semaphore lock; |
||
196 | enum chips type; |
||
197 | |||
198 | struct semaphore update_lock; |
||
199 | char valid; /* !=0 if following fields are valid */ |
||
200 | unsigned long last_updated; /* In jiffies */ |
||
201 | |||
202 | u8 in[9]; /* Register value */ |
||
203 | u8 in_max[9]; /* Register value */ |
||
204 | u8 in_min[9]; /* Register value */ |
||
205 | u8 fan[3]; /* Register value */ |
||
206 | u8 fan_min[3]; /* Register value */ |
||
207 | u8 temp[3]; /* Register value */ |
||
208 | u8 temp_high[3]; /* Register value */ |
||
209 | u8 temp_low[3]; /* Register value */ |
||
210 | u8 sensor; /* Register value */ |
||
211 | u8 fan_div[3]; /* Register encoding, shifted right */ |
||
212 | u8 vid; /* Register encoding, combined */ |
||
213 | u32 alarms; /* Register encoding, combined */ |
||
214 | }; |
||
215 | |||
216 | |||
217 | static int it87_attach_adapter(struct i2c_adapter *adapter); |
||
218 | static int it87_detect(struct i2c_adapter *adapter, int address, int kind); |
||
219 | static int it87_detach_client(struct i2c_client *client); |
||
220 | |||
221 | static int it87_read_value(struct i2c_client *client, u8 register); |
||
222 | static int it87_write_value(struct i2c_client *client, u8 register, |
||
223 | u8 value); |
||
224 | static void it87_update_client(struct i2c_client *client); |
||
225 | static void it87_init_client(struct i2c_client *client, struct it87_data *data); |
||
226 | |||
227 | |||
228 | static struct i2c_driver it87_driver = { |
||
229 | .owner = THIS_MODULE, |
||
230 | .name = "IT87xx", |
||
231 | .id = I2C_DRIVERID_IT87, |
||
232 | .flags = I2C_DF_NOTIFY, |
||
233 | .attach_adapter = it87_attach_adapter, |
||
234 | .detach_client = it87_detach_client, |
||
235 | }; |
||
236 | |||
237 | static int it87_id = 0; |
||
238 | |||
239 | static ssize_t show_in(struct device *dev, char *buf, int nr) |
||
240 | { |
||
241 | struct i2c_client *client = to_i2c_client(dev); |
||
242 | struct it87_data *data = i2c_get_clientdata(client); |
||
243 | it87_update_client(client); |
||
244 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])*10 ); |
||
245 | } |
||
246 | |||
247 | static ssize_t show_in_min(struct device *dev, char *buf, int nr) |
||
248 | { |
||
249 | struct i2c_client *client = to_i2c_client(dev); |
||
250 | struct it87_data *data = i2c_get_clientdata(client); |
||
251 | it87_update_client(client); |
||
252 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])*10 ); |
||
253 | } |
||
254 | |||
255 | static ssize_t show_in_max(struct device *dev, char *buf, int nr) |
||
256 | { |
||
257 | struct i2c_client *client = to_i2c_client(dev); |
||
258 | struct it87_data *data = i2c_get_clientdata(client); |
||
259 | it87_update_client(client); |
||
260 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])*10 ); |
||
261 | } |
||
262 | |||
263 | static ssize_t set_in_min(struct device *dev, const char *buf, |
||
264 | size_t count, int nr) |
||
265 | { |
||
266 | struct i2c_client *client = to_i2c_client(dev); |
||
267 | struct it87_data *data = i2c_get_clientdata(client); |
||
268 | unsigned long val = simple_strtoul(buf, NULL, 10)/10; |
||
269 | data->in_min[nr] = IN_TO_REG(val); |
||
270 | it87_write_value(client, IT87_REG_VIN_MIN(nr), |
||
271 | data->in_min[nr]); |
||
272 | return count; |
||
273 | } |
||
274 | static ssize_t set_in_max(struct device *dev, const char *buf, |
||
275 | size_t count, int nr) |
||
276 | { |
||
277 | struct i2c_client *client = to_i2c_client(dev); |
||
278 | struct it87_data *data = i2c_get_clientdata(client); |
||
279 | unsigned long val = simple_strtoul(buf, NULL, 10)/10; |
||
280 | data->in_max[nr] = IN_TO_REG(val); |
||
281 | it87_write_value(client, IT87_REG_VIN_MAX(nr), |
||
282 | data->in_max[nr]); |
||
283 | return count; |
||
284 | } |
||
285 | |||
286 | #define show_in_offset(offset) \ |
||
287 | static ssize_t \ |
||
288 | show_in##offset (struct device *dev, char *buf) \ |
||
289 | { \ |
||
290 | return show_in(dev, buf, 0x##offset); \ |
||
291 | } \ |
||
292 | static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL) |
||
293 | |||
294 | #define limit_in_offset(offset) \ |
||
295 | static ssize_t \ |
||
296 | show_in##offset##_min (struct device *dev, char *buf) \ |
||
297 | { \ |
||
298 | return show_in_min(dev, buf, 0x##offset); \ |
||
299 | } \ |
||
300 | static ssize_t \ |
||
301 | show_in##offset##_max (struct device *dev, char *buf) \ |
||
302 | { \ |
||
303 | return show_in_max(dev, buf, 0x##offset); \ |
||
304 | } \ |
||
305 | static ssize_t set_in##offset##_min (struct device *dev, \ |
||
306 | const char *buf, size_t count) \ |
||
307 | { \ |
||
308 | return set_in_min(dev, buf, count, 0x##offset); \ |
||
309 | } \ |
||
310 | static ssize_t set_in##offset##_max (struct device *dev, \ |
||
311 | const char *buf, size_t count) \ |
||
312 | { \ |
||
313 | return set_in_max(dev, buf, count, 0x##offset); \ |
||
314 | } \ |
||
315 | static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, \ |
||
316 | show_in##offset##_min, set_in##offset##_min) \ |
||
317 | static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, \ |
||
318 | show_in##offset##_max, set_in##offset##_max) |
||
319 | |||
320 | show_in_offset(0); |
||
321 | limit_in_offset(0); |
||
322 | show_in_offset(1); |
||
323 | limit_in_offset(1); |
||
324 | show_in_offset(2); |
||
325 | limit_in_offset(2); |
||
326 | show_in_offset(3); |
||
327 | limit_in_offset(3); |
||
328 | show_in_offset(4); |
||
329 | limit_in_offset(4); |
||
330 | show_in_offset(5); |
||
331 | limit_in_offset(5); |
||
332 | show_in_offset(6); |
||
333 | limit_in_offset(6); |
||
334 | show_in_offset(7); |
||
335 | limit_in_offset(7); |
||
336 | show_in_offset(8); |
||
337 | |||
338 | /* 3 temperatures */ |
||
339 | static ssize_t show_temp(struct device *dev, char *buf, int nr) |
||
340 | { |
||
341 | struct i2c_client *client = to_i2c_client(dev); |
||
342 | struct it87_data *data = i2c_get_clientdata(client); |
||
343 | it87_update_client(client); |
||
344 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 ); |
||
345 | } |
||
346 | /* more like overshoot temperature */ |
||
347 | static ssize_t show_temp_max(struct device *dev, char *buf, int nr) |
||
348 | { |
||
349 | struct i2c_client *client = to_i2c_client(dev); |
||
350 | struct it87_data *data = i2c_get_clientdata(client); |
||
351 | it87_update_client(client); |
||
352 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100); |
||
353 | } |
||
354 | /* more like hysteresis temperature */ |
||
355 | static ssize_t show_temp_min(struct device *dev, char *buf, int nr) |
||
356 | { |
||
357 | struct i2c_client *client = to_i2c_client(dev); |
||
358 | struct it87_data *data = i2c_get_clientdata(client); |
||
359 | it87_update_client(client); |
||
360 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*100); |
||
361 | } |
||
362 | static ssize_t set_temp_max(struct device *dev, const char *buf, |
||
363 | size_t count, int nr) |
||
364 | { |
||
365 | struct i2c_client *client = to_i2c_client(dev); |
||
366 | struct it87_data *data = i2c_get_clientdata(client); |
||
367 | int val = simple_strtol(buf, NULL, 10)/100; |
||
368 | data->temp_high[nr] = TEMP_TO_REG(val); |
||
369 | it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); |
||
370 | return count; |
||
371 | } |
||
372 | static ssize_t set_temp_min(struct device *dev, const char *buf, |
||
373 | size_t count, int nr) |
||
374 | { |
||
375 | struct i2c_client *client = to_i2c_client(dev); |
||
376 | struct it87_data *data = i2c_get_clientdata(client); |
||
377 | int val = simple_strtol(buf, NULL, 10)/100; |
||
378 | data->temp_low[nr] = TEMP_TO_REG(val); |
||
379 | it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); |
||
380 | return count; |
||
381 | } |
||
382 | #define show_temp_offset(offset) \ |
||
383 | static ssize_t show_temp_##offset (struct device *dev, char *buf) \ |
||
384 | { \ |
||
385 | return show_temp(dev, buf, 0x##offset - 1); \ |
||
386 | } \ |
||
387 | static ssize_t \ |
||
388 | show_temp_##offset##_max (struct device *dev, char *buf) \ |
||
389 | { \ |
||
390 | return show_temp_max(dev, buf, 0x##offset - 1); \ |
||
391 | } \ |
||
392 | static ssize_t \ |
||
393 | show_temp_##offset##_min (struct device *dev, char *buf) \ |
||
394 | { \ |
||
395 | return show_temp_min(dev, buf, 0x##offset - 1); \ |
||
396 | } \ |
||
397 | static ssize_t set_temp_##offset##_max (struct device *dev, \ |
||
398 | const char *buf, size_t count) \ |
||
399 | { \ |
||
400 | return set_temp_max(dev, buf, count, 0x##offset - 1); \ |
||
401 | } \ |
||
402 | static ssize_t set_temp_##offset##_min (struct device *dev, \ |
||
403 | const char *buf, size_t count) \ |
||
404 | { \ |
||
405 | return set_temp_min(dev, buf, count, 0x##offset - 1); \ |
||
406 | } \ |
||
407 | static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_temp_##offset, NULL) \ |
||
408 | static DEVICE_ATTR(temp_max##offset, S_IRUGO | S_IWUSR, \ |
||
409 | show_temp_##offset##_max, set_temp_##offset##_max) \ |
||
410 | static DEVICE_ATTR(temp_min##offset, S_IRUGO | S_IWUSR, \ |
||
411 | show_temp_##offset##_min, set_temp_##offset##_min) |
||
412 | |||
413 | show_temp_offset(1); |
||
414 | show_temp_offset(2); |
||
415 | show_temp_offset(3); |
||
416 | |||
417 | /* more like overshoot temperature */ |
||
418 | static ssize_t show_sensor(struct device *dev, char *buf, int nr) |
||
419 | { |
||
420 | struct i2c_client *client = to_i2c_client(dev); |
||
421 | struct it87_data *data = i2c_get_clientdata(client); |
||
422 | it87_update_client(client); |
||
423 | if (data->sensor & (1 << nr)) |
||
424 | return sprintf(buf, "1\n"); |
||
425 | if (data->sensor & (8 << nr)) |
||
426 | return sprintf(buf, "2\n"); |
||
427 | return sprintf(buf, "0\n"); |
||
428 | } |
||
429 | static ssize_t set_sensor(struct device *dev, const char *buf, |
||
430 | size_t count, int nr) |
||
431 | { |
||
432 | struct i2c_client *client = to_i2c_client(dev); |
||
433 | struct it87_data *data = i2c_get_clientdata(client); |
||
434 | int val = simple_strtol(buf, NULL, 10); |
||
435 | |||
436 | data->sensor &= ~(1 << nr); |
||
437 | data->sensor &= ~(8 << nr); |
||
438 | if (val == 1) |
||
439 | data->sensor |= 1 << nr; |
||
440 | else if (val == 2) |
||
441 | data->sensor |= 8 << nr; |
||
442 | it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); |
||
443 | return count; |
||
444 | } |
||
445 | #define show_sensor_offset(offset) \ |
||
446 | static ssize_t show_sensor_##offset (struct device *dev, char *buf) \ |
||
447 | { \ |
||
448 | return show_sensor(dev, buf, 0x##offset - 1); \ |
||
449 | } \ |
||
450 | static ssize_t set_sensor_##offset (struct device *dev, \ |
||
451 | const char *buf, size_t count) \ |
||
452 | { \ |
||
453 | return set_sensor(dev, buf, count, 0x##offset - 1); \ |
||
454 | } \ |
||
455 | static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR, \ |
||
456 | show_sensor_##offset, set_sensor_##offset) |
||
457 | |||
458 | show_sensor_offset(1); |
||
459 | show_sensor_offset(2); |
||
460 | show_sensor_offset(3); |
||
461 | |||
462 | /* 3 Fans */ |
||
463 | static ssize_t show_fan(struct device *dev, char *buf, int nr) |
||
464 | { |
||
465 | struct i2c_client *client = to_i2c_client(dev); |
||
466 | struct it87_data *data = i2c_get_clientdata(client); |
||
467 | it87_update_client(client); |
||
468 | return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], |
||
469 | DIV_FROM_REG(data->fan_div[nr])) ); |
||
470 | } |
||
471 | static ssize_t show_fan_min(struct device *dev, char *buf, int nr) |
||
472 | { |
||
473 | struct i2c_client *client = to_i2c_client(dev); |
||
474 | struct it87_data *data = i2c_get_clientdata(client); |
||
475 | it87_update_client(client); |
||
476 | return sprintf(buf,"%d\n", |
||
477 | FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); |
||
478 | } |
||
479 | static ssize_t show_fan_div(struct device *dev, char *buf, int nr) |
||
480 | { |
||
481 | struct i2c_client *client = to_i2c_client(dev); |
||
482 | struct it87_data *data = i2c_get_clientdata(client); |
||
483 | it87_update_client(client); |
||
484 | return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) ); |
||
485 | } |
||
486 | static ssize_t set_fan_min(struct device *dev, const char *buf, |
||
487 | size_t count, int nr) |
||
488 | { |
||
489 | struct i2c_client *client = to_i2c_client(dev); |
||
490 | struct it87_data *data = i2c_get_clientdata(client); |
||
491 | int val = simple_strtol(buf, NULL, 10); |
||
492 | data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); |
||
493 | it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); |
||
494 | return count; |
||
495 | } |
||
496 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
||
497 | size_t count, int nr) |
||
498 | { |
||
499 | struct i2c_client *client = to_i2c_client(dev); |
||
500 | struct it87_data *data = i2c_get_clientdata(client); |
||
501 | int val = simple_strtol(buf, NULL, 10); |
||
502 | int i, min[3]; |
||
503 | u8 old = it87_read_value(client, IT87_REG_FAN_DIV); |
||
504 | |||
505 | for (i = 0; i < 3; i++) |
||
506 | min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); |
||
507 | |||
508 | switch (nr) { |
||
509 | case 0: |
||
510 | case 1: |
||
511 | data->fan_div[nr] = DIV_TO_REG(val); |
||
512 | break; |
||
513 | case 2: |
||
514 | if (val < 8) |
||
515 | data->fan_div[nr] = 1; |
||
516 | else |
||
517 | data->fan_div[nr] = 3; |
||
518 | } |
||
519 | val = old & 0x100; |
||
520 | val |= (data->fan_div[0] & 0x07); |
||
521 | val |= (data->fan_div[1] & 0x07) << 3; |
||
522 | if (data->fan_div[2] == 3) |
||
523 | val |= 0x1 << 6; |
||
524 | it87_write_value(client, IT87_REG_FAN_DIV, val); |
||
525 | |||
526 | for (i = 0; i < 3; i++) { |
||
527 | data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); |
||
528 | it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); |
||
529 | } |
||
530 | return count; |
||
531 | } |
||
532 | |||
533 | #define show_fan_offset(offset) \ |
||
534 | static ssize_t show_fan_##offset (struct device *dev, char *buf) \ |
||
535 | { \ |
||
536 | return show_fan(dev, buf, 0x##offset - 1); \ |
||
537 | } \ |
||
538 | static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ |
||
539 | { \ |
||
540 | return show_fan_min(dev, buf, 0x##offset - 1); \ |
||
541 | } \ |
||
542 | static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ |
||
543 | { \ |
||
544 | return show_fan_div(dev, buf, 0x##offset - 1); \ |
||
545 | } \ |
||
546 | static ssize_t set_fan_##offset##_min (struct device *dev, \ |
||
547 | const char *buf, size_t count) \ |
||
548 | { \ |
||
549 | return set_fan_min(dev, buf, count, 0x##offset - 1); \ |
||
550 | } \ |
||
551 | static ssize_t set_fan_##offset##_div (struct device *dev, \ |
||
552 | const char *buf, size_t count) \ |
||
553 | { \ |
||
554 | return set_fan_div(dev, buf, count, 0x##offset - 1); \ |
||
555 | } \ |
||
556 | static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \ |
||
557 | static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, \ |
||
558 | show_fan_##offset##_min, set_fan_##offset##_min) \ |
||
559 | static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, \ |
||
560 | show_fan_##offset##_div, set_fan_##offset##_div) |
||
561 | |||
562 | show_fan_offset(1); |
||
563 | show_fan_offset(2); |
||
564 | show_fan_offset(3); |
||
565 | |||
566 | /* Alarm */ |
||
567 | static ssize_t show_alarm(struct device *dev, char *buf) |
||
568 | { |
||
569 | struct i2c_client *client = to_i2c_client(dev); |
||
570 | struct it87_data *data = i2c_get_clientdata(client); |
||
571 | it87_update_client(client); |
||
572 | return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); |
||
573 | } |
||
574 | static DEVICE_ATTR(alarm, S_IRUGO | S_IWUSR, show_alarm, NULL); |
||
575 | |||
576 | /* This function is called when: |
||
577 | * it87_driver is inserted (when this module is loaded), for each |
||
578 | available adapter |
||
579 | * when a new adapter is inserted (and it87_driver is still present) */ |
||
580 | static int it87_attach_adapter(struct i2c_adapter *adapter) |
||
581 | { |
||
582 | if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) |
||
583 | return 0; |
||
584 | return i2c_detect(adapter, &addr_data, it87_detect); |
||
585 | } |
||
586 | |||
587 | /* This function is called by i2c_detect */ |
||
588 | int it87_detect(struct i2c_adapter *adapter, int address, int kind) |
||
589 | { |
||
590 | int i; |
||
591 | struct i2c_client *new_client = NULL; |
||
592 | struct it87_data *data; |
||
593 | int err = 0; |
||
594 | const char *name = ""; |
||
595 | int is_isa = i2c_is_isa_adapter(adapter); |
||
596 | |||
597 | if (!is_isa && |
||
598 | !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
||
599 | goto ERROR0; |
||
600 | |||
601 | /* Reserve the ISA region */ |
||
602 | if (is_isa) |
||
603 | if (!request_region(address, IT87_EXTENT, name)) |
||
604 | goto ERROR0; |
||
605 | |||
606 | /* Probe whether there is anything available on this address. Already |
||
607 | done for SMBus clients */ |
||
608 | if (kind < 0) { |
||
609 | if (is_isa) { |
||
610 | |||
611 | #define REALLY_SLOW_IO |
||
612 | /* We need the timeouts for at least some IT87-like chips. But only |
||
613 | if we read 'undefined' registers. */ |
||
614 | i = inb_p(address + 1); |
||
615 | if (inb_p(address + 2) != i) |
||
616 | goto ERROR1; |
||
617 | if (inb_p(address + 3) != i) |
||
618 | goto ERROR1; |
||
619 | if (inb_p(address + 7) != i) |
||
620 | goto ERROR1; |
||
621 | #undef REALLY_SLOW_IO |
||
622 | |||
623 | /* Let's just hope nothing breaks here */ |
||
624 | i = inb_p(address + 5) & 0x7f; |
||
625 | outb_p(~i & 0x7f, address + 5); |
||
626 | if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { |
||
627 | outb_p(i, address + 5); |
||
628 | return 0; |
||
629 | } |
||
630 | } |
||
631 | } |
||
632 | |||
633 | /* OK. For now, we presume we have a valid client. We now create the |
||
634 | client structure, even though we cannot fill it completely yet. |
||
635 | But it allows us to access it87_{read,write}_value. */ |
||
636 | |||
637 | if (!(new_client = kmalloc((sizeof(struct i2c_client)) + |
||
638 | sizeof(struct it87_data), |
||
639 | GFP_KERNEL))) { |
||
640 | err = -ENOMEM; |
||
641 | goto ERROR1; |
||
642 | } |
||
643 | memset(new_client, 0x00, sizeof(struct i2c_client) + |
||
644 | sizeof(struct it87_data)); |
||
645 | |||
646 | data = (struct it87_data *) (new_client + 1); |
||
647 | if (is_isa) |
||
648 | init_MUTEX(&data->lock); |
||
649 | i2c_set_clientdata(new_client, data); |
||
650 | new_client->addr = address; |
||
651 | new_client->adapter = adapter; |
||
652 | new_client->driver = &it87_driver; |
||
653 | new_client->flags = 0; |
||
654 | |||
655 | /* Now, we do the remaining detection. */ |
||
656 | |||
657 | if (kind < 0) { |
||
658 | if (it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) |
||
659 | goto ERROR1; |
||
660 | if (!is_isa |
||
661 | && (it87_read_value(new_client, IT87_REG_I2C_ADDR) != |
||
662 | address)) goto ERROR1; |
||
663 | } |
||
664 | |||
665 | /* Determine the chip type. */ |
||
666 | if (kind <= 0) { |
||
667 | i = it87_read_value(new_client, IT87_REG_CHIPID); |
||
668 | if (i == 0x90) { |
||
669 | kind = it87; |
||
670 | } |
||
671 | else { |
||
672 | if (kind == 0) |
||
673 | printk |
||
674 | ("it87.o: Ignoring 'force' parameter for unknown chip at " |
||
675 | "adapter %d, address 0x%02x\n", |
||
676 | i2c_adapter_id(adapter), address); |
||
677 | goto ERROR1; |
||
678 | } |
||
679 | } |
||
680 | |||
681 | if (kind == it87) { |
||
682 | name = "it87"; |
||
683 | } /* else if (kind == it8712) { |
||
684 | name = "it8712"; |
||
685 | } */ else { |
||
686 | dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?", |
||
687 | kind); |
||
688 | goto ERROR1; |
||
689 | } |
||
690 | |||
691 | /* Fill in the remaining client fields and put it into the global list */ |
||
692 | strlcpy(new_client->name, name, I2C_NAME_SIZE); |
||
693 | |||
694 | data->type = kind; |
||
695 | |||
696 | new_client->id = it87_id++; |
||
697 | data->valid = 0; |
||
698 | init_MUTEX(&data->update_lock); |
||
699 | |||
700 | /* Tell the I2C layer a new client has arrived */ |
||
701 | if ((err = i2c_attach_client(new_client))) |
||
702 | goto ERROR1; |
||
703 | |||
704 | /* Initialize the IT87 chip */ |
||
705 | it87_init_client(new_client, data); |
||
706 | |||
707 | /* Register sysfs hooks */ |
||
708 | device_create_file(&new_client->dev, &dev_attr_in_input0); |
||
709 | device_create_file(&new_client->dev, &dev_attr_in_input1); |
||
710 | device_create_file(&new_client->dev, &dev_attr_in_input2); |
||
711 | device_create_file(&new_client->dev, &dev_attr_in_input3); |
||
712 | device_create_file(&new_client->dev, &dev_attr_in_input4); |
||
713 | device_create_file(&new_client->dev, &dev_attr_in_input5); |
||
714 | device_create_file(&new_client->dev, &dev_attr_in_input6); |
||
715 | device_create_file(&new_client->dev, &dev_attr_in_input7); |
||
716 | device_create_file(&new_client->dev, &dev_attr_in_input8); |
||
717 | device_create_file(&new_client->dev, &dev_attr_in_min0); |
||
718 | device_create_file(&new_client->dev, &dev_attr_in_min1); |
||
719 | device_create_file(&new_client->dev, &dev_attr_in_min2); |
||
720 | device_create_file(&new_client->dev, &dev_attr_in_min3); |
||
721 | device_create_file(&new_client->dev, &dev_attr_in_min4); |
||
722 | device_create_file(&new_client->dev, &dev_attr_in_min5); |
||
723 | device_create_file(&new_client->dev, &dev_attr_in_min6); |
||
724 | device_create_file(&new_client->dev, &dev_attr_in_min7); |
||
725 | device_create_file(&new_client->dev, &dev_attr_in_max0); |
||
726 | device_create_file(&new_client->dev, &dev_attr_in_max1); |
||
727 | device_create_file(&new_client->dev, &dev_attr_in_max2); |
||
728 | device_create_file(&new_client->dev, &dev_attr_in_max3); |
||
729 | device_create_file(&new_client->dev, &dev_attr_in_max4); |
||
730 | device_create_file(&new_client->dev, &dev_attr_in_max5); |
||
731 | device_create_file(&new_client->dev, &dev_attr_in_max6); |
||
732 | device_create_file(&new_client->dev, &dev_attr_in_max7); |
||
733 | device_create_file(&new_client->dev, &dev_attr_temp_input1); |
||
734 | device_create_file(&new_client->dev, &dev_attr_temp_input2); |
||
735 | device_create_file(&new_client->dev, &dev_attr_temp_input3); |
||
736 | device_create_file(&new_client->dev, &dev_attr_temp_max1); |
||
737 | device_create_file(&new_client->dev, &dev_attr_temp_max2); |
||
738 | device_create_file(&new_client->dev, &dev_attr_temp_max3); |
||
739 | device_create_file(&new_client->dev, &dev_attr_temp_min1); |
||
740 | device_create_file(&new_client->dev, &dev_attr_temp_min2); |
||
741 | device_create_file(&new_client->dev, &dev_attr_temp_min3); |
||
742 | device_create_file(&new_client->dev, &dev_attr_sensor1); |
||
743 | device_create_file(&new_client->dev, &dev_attr_sensor2); |
||
744 | device_create_file(&new_client->dev, &dev_attr_sensor3); |
||
745 | device_create_file(&new_client->dev, &dev_attr_fan_input1); |
||
746 | device_create_file(&new_client->dev, &dev_attr_fan_input2); |
||
747 | device_create_file(&new_client->dev, &dev_attr_fan_input3); |
||
748 | device_create_file(&new_client->dev, &dev_attr_fan_min1); |
||
749 | device_create_file(&new_client->dev, &dev_attr_fan_min2); |
||
750 | device_create_file(&new_client->dev, &dev_attr_fan_min3); |
||
751 | device_create_file(&new_client->dev, &dev_attr_fan_div1); |
||
752 | device_create_file(&new_client->dev, &dev_attr_fan_div2); |
||
753 | device_create_file(&new_client->dev, &dev_attr_fan_div3); |
||
754 | device_create_file(&new_client->dev, &dev_attr_alarm); |
||
755 | |||
756 | return 0; |
||
757 | |||
758 | ERROR1: |
||
759 | kfree(new_client); |
||
760 | |||
761 | if (is_isa) |
||
762 | release_region(address, IT87_EXTENT); |
||
763 | ERROR0: |
||
764 | return err; |
||
765 | } |
||
766 | |||
767 | static int it87_detach_client(struct i2c_client *client) |
||
768 | { |
||
769 | int err; |
||
770 | |||
771 | if ((err = i2c_detach_client(client))) { |
||
772 | dev_err(&client->dev, |
||
773 | "Client deregistration failed, client not detached.\n"); |
||
774 | return err; |
||
775 | } |
||
776 | |||
777 | if(i2c_is_isa_client(client)) |
||
778 | release_region(client->addr, IT87_EXTENT); |
||
779 | kfree(client); |
||
780 | |||
781 | return 0; |
||
782 | } |
||
783 | |||
784 | /* The SMBus locks itself, but ISA access must be locked explicitely! |
||
785 | We don't want to lock the whole ISA bus, so we lock each client |
||
786 | separately. |
||
787 | We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, |
||
788 | would slow down the IT87 access and should not be necessary. |
||
789 | There are some ugly typecasts here, but the good new is - they should |
||
790 | nowhere else be necessary! */ |
||
791 | static int it87_read_value(struct i2c_client *client, u8 reg) |
||
792 | { |
||
793 | struct it87_data *data = i2c_get_clientdata(client); |
||
794 | |||
795 | int res; |
||
796 | if (i2c_is_isa_client(client)) { |
||
797 | down(&data->lock); |
||
798 | outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); |
||
799 | res = inb_p(client->addr + IT87_DATA_REG_OFFSET); |
||
800 | up(&data->lock); |
||
801 | return res; |
||
802 | } else |
||
803 | return i2c_smbus_read_byte_data(client, reg); |
||
804 | } |
||
805 | |||
806 | /* The SMBus locks itself, but ISA access muse be locked explicitely! |
||
807 | We don't want to lock the whole ISA bus, so we lock each client |
||
808 | separately. |
||
809 | We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, |
||
810 | would slow down the IT87 access and should not be necessary. |
||
811 | There are some ugly typecasts here, but the good new is - they should |
||
812 | nowhere else be necessary! */ |
||
813 | static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) |
||
814 | { |
||
815 | struct it87_data *data = i2c_get_clientdata(client); |
||
816 | |||
817 | if (i2c_is_isa_client(client)) { |
||
818 | down(&data->lock); |
||
819 | outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); |
||
820 | outb_p(value, client->addr + IT87_DATA_REG_OFFSET); |
||
821 | up(&data->lock); |
||
822 | return 0; |
||
823 | } else |
||
824 | return i2c_smbus_write_byte_data(client, reg, value); |
||
825 | } |
||
826 | |||
827 | /* Called when we have found a new IT87. It should set limits, etc. */ |
||
828 | static void it87_init_client(struct i2c_client *client, struct it87_data *data) |
||
829 | { |
||
830 | /* Reset all except Watchdog values and last conversion values |
||
831 | This sets fan-divs to 2, among others */ |
||
832 | it87_write_value(client, IT87_REG_CONFIG, 0x80); |
||
833 | it87_write_value(client, IT87_REG_VIN_MIN(0), |
||
834 | IN_TO_REG(IT87_INIT_IN_MIN_0)); |
||
835 | it87_write_value(client, IT87_REG_VIN_MAX(0), |
||
836 | IN_TO_REG(IT87_INIT_IN_MAX_0)); |
||
837 | it87_write_value(client, IT87_REG_VIN_MIN(1), |
||
838 | IN_TO_REG(IT87_INIT_IN_MIN_1)); |
||
839 | it87_write_value(client, IT87_REG_VIN_MAX(1), |
||
840 | IN_TO_REG(IT87_INIT_IN_MAX_1)); |
||
841 | it87_write_value(client, IT87_REG_VIN_MIN(2), |
||
842 | IN_TO_REG(IT87_INIT_IN_MIN_2)); |
||
843 | it87_write_value(client, IT87_REG_VIN_MAX(2), |
||
844 | IN_TO_REG(IT87_INIT_IN_MAX_2)); |
||
845 | it87_write_value(client, IT87_REG_VIN_MIN(3), |
||
846 | IN_TO_REG(IT87_INIT_IN_MIN_3)); |
||
847 | it87_write_value(client, IT87_REG_VIN_MAX(3), |
||
848 | IN_TO_REG(IT87_INIT_IN_MAX_3)); |
||
849 | it87_write_value(client, IT87_REG_VIN_MIN(4), |
||
850 | IN_TO_REG(IT87_INIT_IN_MIN_4)); |
||
851 | it87_write_value(client, IT87_REG_VIN_MAX(4), |
||
852 | IN_TO_REG(IT87_INIT_IN_MAX_4)); |
||
853 | it87_write_value(client, IT87_REG_VIN_MIN(5), |
||
854 | IN_TO_REG(IT87_INIT_IN_MIN_5)); |
||
855 | it87_write_value(client, IT87_REG_VIN_MAX(5), |
||
856 | IN_TO_REG(IT87_INIT_IN_MAX_5)); |
||
857 | it87_write_value(client, IT87_REG_VIN_MIN(6), |
||
858 | IN_TO_REG(IT87_INIT_IN_MIN_6)); |
||
859 | it87_write_value(client, IT87_REG_VIN_MAX(6), |
||
860 | IN_TO_REG(IT87_INIT_IN_MAX_6)); |
||
861 | it87_write_value(client, IT87_REG_VIN_MIN(7), |
||
862 | IN_TO_REG(IT87_INIT_IN_MIN_7)); |
||
863 | it87_write_value(client, IT87_REG_VIN_MAX(7), |
||
864 | IN_TO_REG(IT87_INIT_IN_MAX_7)); |
||
865 | /* Note: Battery voltage does not have limit registers */ |
||
866 | it87_write_value(client, IT87_REG_FAN_MIN(0), |
||
867 | FAN_TO_REG(IT87_INIT_FAN_MIN_1, 2)); |
||
868 | it87_write_value(client, IT87_REG_FAN_MIN(1), |
||
869 | FAN_TO_REG(IT87_INIT_FAN_MIN_2, 2)); |
||
870 | it87_write_value(client, IT87_REG_FAN_MIN(2), |
||
871 | FAN_TO_REG(IT87_INIT_FAN_MIN_3, 2)); |
||
872 | it87_write_value(client, IT87_REG_TEMP_HIGH(0), |
||
873 | TEMP_TO_REG(IT87_INIT_TEMP_HIGH_1)); |
||
874 | it87_write_value(client, IT87_REG_TEMP_LOW(0), |
||
875 | TEMP_TO_REG(IT87_INIT_TEMP_LOW_1)); |
||
876 | it87_write_value(client, IT87_REG_TEMP_HIGH(1), |
||
877 | TEMP_TO_REG(IT87_INIT_TEMP_HIGH_2)); |
||
878 | it87_write_value(client, IT87_REG_TEMP_LOW(1), |
||
879 | TEMP_TO_REG(IT87_INIT_TEMP_LOW_2)); |
||
880 | it87_write_value(client, IT87_REG_TEMP_HIGH(2), |
||
881 | TEMP_TO_REG(IT87_INIT_TEMP_HIGH_3)); |
||
882 | it87_write_value(client, IT87_REG_TEMP_LOW(2), |
||
883 | TEMP_TO_REG(IT87_INIT_TEMP_LOW_3)); |
||
884 | |||
885 | /* Enable voltage monitors */ |
||
886 | it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); |
||
887 | |||
888 | /* Enable Temp1-Temp3 */ |
||
889 | data->sensor = (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0); |
||
890 | data->sensor |= temp_type & 0x3f; |
||
891 | it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); |
||
892 | |||
893 | /* Enable fans */ |
||
894 | it87_write_value(client, IT87_REG_FAN_CTRL, |
||
895 | (it87_read_value(client, IT87_REG_FAN_CTRL) & 0x8f) |
||
896 | | 0x70); |
||
897 | |||
898 | /* Start monitoring */ |
||
899 | it87_write_value(client, IT87_REG_CONFIG, |
||
900 | (it87_read_value(client, IT87_REG_CONFIG) & 0xb7) |
||
901 | | (update_vbat ? 0x41 : 0x01)); |
||
902 | } |
||
903 | |||
904 | static void it87_update_client(struct i2c_client *client) |
||
905 | { |
||
906 | struct it87_data *data = i2c_get_clientdata(client); |
||
907 | int i; |
||
908 | |||
909 | down(&data->update_lock); |
||
910 | |||
911 | if ((jiffies - data->last_updated > HZ + HZ / 2) || |
||
912 | (jiffies < data->last_updated) || !data->valid) { |
||
913 | |||
914 | if (update_vbat) { |
||
915 | /* Cleared after each update, so reenable. Value |
||
916 | returned by this read will be previous value */ |
||
917 | it87_write_value(client, IT87_REG_CONFIG, |
||
918 | it87_read_value(client, IT87_REG_CONFIG) | 0x40); |
||
919 | } |
||
920 | for (i = 0; i <= 7; i++) { |
||
921 | data->in[i] = |
||
922 | it87_read_value(client, IT87_REG_VIN(i)); |
||
923 | data->in_min[i] = |
||
924 | it87_read_value(client, IT87_REG_VIN_MIN(i)); |
||
925 | data->in_max[i] = |
||
926 | it87_read_value(client, IT87_REG_VIN_MAX(i)); |
||
927 | } |
||
928 | data->in[8] = |
||
929 | it87_read_value(client, IT87_REG_VIN(8)); |
||
930 | /* Temperature sensor doesn't have limit registers, set |
||
931 | to min and max value */ |
||
932 | data->in_min[8] = 0; |
||
933 | data->in_max[8] = 255; |
||
934 | |||
935 | for (i = 0; i < 3; i++) { |
||
936 | data->fan[i] = |
||
937 | it87_read_value(client, IT87_REG_FAN(i)); |
||
938 | data->fan_min[i] = |
||
939 | it87_read_value(client, IT87_REG_FAN_MIN(i)); |
||
940 | } |
||
941 | for (i = 0; i < 3; i++) { |
||
942 | data->temp[i] = |
||
943 | it87_read_value(client, IT87_REG_TEMP(i)); |
||
944 | data->temp_high[i] = |
||
945 | it87_read_value(client, IT87_REG_TEMP_HIGH(i)); |
||
946 | data->temp_low[i] = |
||
947 | it87_read_value(client, IT87_REG_TEMP_LOW(i)); |
||
948 | } |
||
949 | |||
950 | /* The 8705 does not have VID capability */ |
||
951 | /*if (data->type == it8712) { |
||
952 | data->vid = it87_read_value(client, IT87_REG_VID); |
||
953 | data->vid &= 0x1f; |
||
954 | } |
||
955 | else */ { |
||
956 | data->vid = 0x1f; |
||
957 | } |
||
958 | |||
959 | i = it87_read_value(client, IT87_REG_FAN_DIV); |
||
960 | data->fan_div[0] = i & 0x07; |
||
961 | data->fan_div[1] = (i >> 3) & 0x07; |
||
962 | data->fan_div[2] = (i & 0x40) ? 3 : 1; |
||
963 | |||
964 | data->alarms = |
||
965 | it87_read_value(client, IT87_REG_ALARM1) | |
||
966 | (it87_read_value(client, IT87_REG_ALARM2) << 8) | |
||
967 | (it87_read_value(client, IT87_REG_ALARM3) << 16); |
||
968 | |||
969 | data->last_updated = jiffies; |
||
970 | data->valid = 1; |
||
971 | } |
||
972 | |||
973 | up(&data->update_lock); |
||
974 | } |
||
975 | |||
976 | static int __init sm_it87_init(void) |
||
977 | { |
||
978 | return i2c_add_driver(&it87_driver); |
||
979 | } |
||
980 | |||
981 | static void __exit sm_it87_exit(void) |
||
982 | { |
||
983 | i2c_del_driver(&it87_driver); |
||
984 | } |
||
985 | |||
986 | |||
987 | MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>"); |
||
988 | MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); |
||
989 | MODULE_PARM(update_vbat, "i"); |
||
990 | MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); |
||
991 | MODULE_PARM(temp_type, "i"); |
||
992 | MODULE_PARM_DESC(temp_type, "Temperature sensor type, normally leave unset"); |
||
993 | MODULE_LICENSE("GPL"); |
||
994 | |||
995 | module_init(sm_it87_init); |
||
996 | module_exit(sm_it87_exit); |