blob: 996fc1ca3227b2aa1c80e26ac0689a329ab2ecd8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
4 Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
5 Philip Edelbrock <phil@netroedge.com>,
6 and Mark Studebaker <mdsxyz123@yahoo.com>
7 Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
Jean Delvare787c72b2007-05-08 17:22:00 +02008 Copyright (c) 2007 Jean Delvare <khali@linux-fr.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25/*
26 Supports following chips:
27
28 Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
29 w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC)
30 w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
31 w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC)
Jean Delvarec2db6ce2006-01-18 23:22:12 +010032 w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
34
35 For other winbond chips, and for i2c support in the above chips,
36 use w83781d.c.
37
38 Note: automatic ("cruise") fan control for 697, 637 & 627thf not
39 supported yet.
40*/
41
42#include <linux/module.h>
43#include <linux/init.h>
44#include <linux/slab.h>
45#include <linux/jiffies.h>
Jean Delvare787c72b2007-05-08 17:22:00 +020046#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/hwmon.h>
Jim Cromie07584c72007-10-12 21:08:00 +020048#include <linux/hwmon-sysfs.h>
Jean Delvare303760b2005-07-31 21:52:01 +020049#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040050#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010051#include <linux/mutex.h>
Jean Delvared27c37c2007-05-08 17:21:59 +020052#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/io.h>
54#include "lm75.h"
55
Jean Delvare787c72b2007-05-08 17:22:00 +020056static struct platform_device *pdev;
Jean Delvared27c37c2007-05-08 17:21:59 +020057
58#define DRVNAME "w83627hf"
59enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061static u16 force_addr;
62module_param(force_addr, ushort, 0);
63MODULE_PARM_DESC(force_addr,
64 "Initialize the base address of the sensors");
65static u8 force_i2c = 0x1f;
66module_param(force_i2c, byte, 0);
67MODULE_PARM_DESC(force_i2c,
68 "Initialize the i2c address of the sensors");
69
Jean Delvare2251cf12005-09-04 22:52:17 +020070static int reset;
71module_param(reset, bool, 0);
72MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int init = 1;
75module_param(init, bool, 0);
76MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
77
78/* modified from kernel/include/traps.c */
79static int REG; /* The register to read/write */
80#define DEV 0x07 /* Register: Logical device select */
81static int VAL; /* The value to read/write */
82
83/* logical device numbers for superio_select (below) */
84#define W83627HF_LD_FDC 0x00
85#define W83627HF_LD_PRT 0x01
86#define W83627HF_LD_UART1 0x02
87#define W83627HF_LD_UART2 0x03
88#define W83627HF_LD_KBC 0x05
89#define W83627HF_LD_CIR 0x06 /* w83627hf only */
90#define W83627HF_LD_GAME 0x07
91#define W83627HF_LD_MIDI 0x07
92#define W83627HF_LD_GPIO1 0x07
93#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */
94#define W83627HF_LD_GPIO2 0x08
95#define W83627HF_LD_GPIO3 0x09
96#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
97#define W83627HF_LD_ACPI 0x0a
98#define W83627HF_LD_HWM 0x0b
99
100#define DEVID 0x20 /* Register: Device ID */
101
102#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */
103#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */
104#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */
105
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100106#define W83687THF_VID_EN 0x29 /* w83687thf only */
107#define W83687THF_VID_CFG 0xF0 /* w83687thf only */
108#define W83687THF_VID_DATA 0xF1 /* w83687thf only */
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110static inline void
111superio_outb(int reg, int val)
112{
113 outb(reg, REG);
114 outb(val, VAL);
115}
116
117static inline int
118superio_inb(int reg)
119{
120 outb(reg, REG);
121 return inb(VAL);
122}
123
124static inline void
125superio_select(int ld)
126{
127 outb(DEV, REG);
128 outb(ld, VAL);
129}
130
131static inline void
132superio_enter(void)
133{
134 outb(0x87, REG);
135 outb(0x87, REG);
136}
137
138static inline void
139superio_exit(void)
140{
141 outb(0xAA, REG);
142}
143
144#define W627_DEVID 0x52
145#define W627THF_DEVID 0x82
146#define W697_DEVID 0x60
147#define W637_DEVID 0x70
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100148#define W687THF_DEVID 0x85
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#define WINB_ACT_REG 0x30
150#define WINB_BASE_REG 0x60
151/* Constants specified below */
152
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200153/* Alignment of the base address */
154#define WINB_ALIGNMENT ~7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Petr Vandrovecada0c2f2005-10-07 23:11:03 +0200156/* Offset & size of I/O region we are interested in */
157#define WINB_REGION_OFFSET 5
158#define WINB_REGION_SIZE 2
159
Jean Delvare787c72b2007-05-08 17:22:00 +0200160/* Where are the sensors address/data registers relative to the region offset */
161#define W83781D_ADDR_REG_OFFSET 0
162#define W83781D_DATA_REG_OFFSET 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164/* The W83781D registers */
165/* The W83782D registers for nr=7,8 are in bank 5 */
166#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
167 (0x554 + (((nr) - 7) * 2)))
168#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
169 (0x555 + (((nr) - 7) * 2)))
170#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
171 (0x550 + (nr) - 7))
172
173#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
174#define W83781D_REG_FAN(nr) (0x27 + (nr))
175
176#define W83781D_REG_TEMP2_CONFIG 0x152
177#define W83781D_REG_TEMP3_CONFIG 0x252
178#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
179 ((nr == 2) ? (0x0150) : \
180 (0x27)))
181#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
182 ((nr == 2) ? (0x153) : \
183 (0x3A)))
184#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
185 ((nr == 2) ? (0x155) : \
186 (0x39)))
187
188#define W83781D_REG_BANK 0x4E
189
190#define W83781D_REG_CONFIG 0x40
Yuan Mu4a1c44472005-11-07 22:19:04 +0100191#define W83781D_REG_ALARM1 0x459
192#define W83781D_REG_ALARM2 0x45A
193#define W83781D_REG_ALARM3 0x45B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195#define W83781D_REG_BEEP_CONFIG 0x4D
196#define W83781D_REG_BEEP_INTS1 0x56
197#define W83781D_REG_BEEP_INTS2 0x57
198#define W83781D_REG_BEEP_INTS3 0x453
199
200#define W83781D_REG_VID_FANDIV 0x47
201
202#define W83781D_REG_CHIPID 0x49
203#define W83781D_REG_WCHIPID 0x58
204#define W83781D_REG_CHIPMAN 0x4F
205#define W83781D_REG_PIN 0x4B
206
207#define W83781D_REG_VBAT 0x5D
208
209#define W83627HF_REG_PWM1 0x5A
210#define W83627HF_REG_PWM2 0x5B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100212#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
213#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
214#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100216#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
219static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
220 W83627THF_REG_PWM3 };
221#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
Jim Cromie07584c72007-10-12 21:08:00 +0200222 regpwm_627hf[nr] : regpwm[nr])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400224#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
225
226#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
227#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
228#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
229
230static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
231 W83637HF_REG_PWM_FREQ2,
232 W83637HF_REG_PWM_FREQ3 };
233
234#define W83627HF_BASE_PWM_FREQ 46870
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236#define W83781D_REG_I2C_ADDR 0x48
237#define W83781D_REG_I2C_SUBADDR 0x4A
238
239/* Sensor selection */
240#define W83781D_REG_SCFG1 0x5D
241static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
242#define W83781D_REG_SCFG2 0x59
243static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
244#define W83781D_DEFAULT_BETA 3435
245
246/* Conversions. Limit checking is only done on the TO_REG
247 variants. Note that you should be a bit careful with which arguments
248 these macros are called: arguments may be evaluated more than once.
249 Fixing this is just not worth it. */
250#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
251#define IN_FROM_REG(val) ((val) * 16)
252
253static inline u8 FAN_TO_REG(long rpm, int div)
254{
255 if (rpm == 0)
256 return 255;
257 rpm = SENSORS_LIMIT(rpm, 1, 1000000);
258 return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
259 254);
260}
261
262#define TEMP_MIN (-128000)
263#define TEMP_MAX ( 127000)
264
265/* TEMP: 0.001C/bit (-128C to +127C)
266 REG: 1C/bit, two's complement */
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200267static u8 TEMP_TO_REG(long temp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
269 int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
270 ntemp += (ntemp<0 ? -500 : 500);
271 return (u8)(ntemp / 1000);
272}
273
274static int TEMP_FROM_REG(u8 reg)
275{
276 return (s8)reg * 1000;
277}
278
279#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
280
281#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
282
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400283static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
284{
285 unsigned long freq;
286 freq = W83627HF_BASE_PWM_FREQ >> reg;
287 return freq;
288}
289static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
290{
291 u8 i;
292 /* Only 5 dividers (1 2 4 8 16)
293 Search for the nearest available frequency */
294 for (i = 0; i < 4; i++) {
295 if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
296 (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
297 break;
298 }
299 return i;
300}
301
302static inline unsigned long pwm_freq_from_reg(u8 reg)
303{
304 /* Clock bit 8 -> 180 kHz or 24 MHz */
305 unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
306
307 reg &= 0x7f;
308 /* This should not happen but anyway... */
309 if (reg == 0)
310 reg++;
311 return (clock / (reg << 8));
312}
313static inline u8 pwm_freq_to_reg(unsigned long val)
314{
315 /* Minimum divider value is 0x01 and maximum is 0x7F */
316 if (val >= 93750) /* The highest we can do */
317 return 0x01;
318 if (val >= 720) /* Use 24 MHz clock */
319 return (24000000UL / (val << 8));
320 if (val < 6) /* The lowest we can do */
321 return 0xFF;
322 else /* Use 180 kHz clock */
323 return (0x80 | (180000UL / (val << 8)));
324}
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#define BEEP_MASK_FROM_REG(val) (val)
327#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
328#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
329#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
330
331#define DIV_FROM_REG(val) (1 << (val))
332
333static inline u8 DIV_TO_REG(long val)
334{
335 int i;
336 val = SENSORS_LIMIT(val, 1, 128) >> 1;
Grant Coadyabc01922005-05-12 13:41:51 +1000337 for (i = 0; i < 7; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (val == 0)
339 break;
340 val >>= 1;
341 }
342 return ((u8) i);
343}
344
Jean Delvareed6bafb2007-02-14 21:15:03 +0100345/* For each registered chip, we need to keep some data in memory.
346 The structure is dynamically allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347struct w83627hf_data {
Jean Delvare787c72b2007-05-08 17:22:00 +0200348 unsigned short addr;
349 const char *name;
Tony Jones1beeffe2007-08-20 13:46:20 -0700350 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100351 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 enum chips type;
353
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100354 struct mutex update_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 char valid; /* !=0 if following fields are valid */
356 unsigned long last_updated; /* In jiffies */
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 u8 in[9]; /* Register value */
359 u8 in_max[9]; /* Register value */
360 u8 in_min[9]; /* Register value */
361 u8 fan[3]; /* Register value */
362 u8 fan_min[3]; /* Register value */
363 u8 temp;
364 u8 temp_max; /* Register value */
365 u8 temp_max_hyst; /* Register value */
366 u16 temp_add[2]; /* Register value */
367 u16 temp_max_add[2]; /* Register value */
368 u16 temp_max_hyst_add[2]; /* Register value */
369 u8 fan_div[3]; /* Register encoding, shifted right */
370 u8 vid; /* Register encoding, combined */
371 u32 alarms; /* Register encoding, combined */
372 u32 beep_mask; /* Register encoding, combined */
373 u8 beep_enable; /* Boolean */
374 u8 pwm[3]; /* Register value */
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400375 u8 pwm_freq[3]; /* Register value */
Jean Delvareb26f9332007-08-16 14:30:01 +0200376 u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
377 4 = thermistor */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 u8 vrm;
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100379 u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380};
381
Jean Delvare787c72b2007-05-08 17:22:00 +0200382struct w83627hf_sio_data {
383 enum chips type;
384};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Jean Delvare787c72b2007-05-08 17:22:00 +0200387static int w83627hf_probe(struct platform_device *pdev);
Jean Delvared0546122007-07-22 12:09:48 +0200388static int __devexit w83627hf_remove(struct platform_device *pdev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200389
390static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
391static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392static struct w83627hf_data *w83627hf_update_device(struct device *dev);
Jean Delvare787c72b2007-05-08 17:22:00 +0200393static void w83627hf_init_device(struct platform_device *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Jean Delvare787c72b2007-05-08 17:22:00 +0200395static struct platform_driver w83627hf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100396 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +0200397 .owner = THIS_MODULE,
Jean Delvared27c37c2007-05-08 17:21:59 +0200398 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +0100399 },
Jean Delvare787c72b2007-05-08 17:22:00 +0200400 .probe = w83627hf_probe,
401 .remove = __devexit_p(w83627hf_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402};
403
Jim Cromie07584c72007-10-12 21:08:00 +0200404static ssize_t
405show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
406{
407 int nr = to_sensor_dev_attr(devattr)->index;
408 struct w83627hf_data *data = w83627hf_update_device(dev);
409 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
Jim Cromie07584c72007-10-12 21:08:00 +0200411static ssize_t
412show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
413{
414 int nr = to_sensor_dev_attr(devattr)->index;
415 struct w83627hf_data *data = w83627hf_update_device(dev);
416 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
Jim Cromie07584c72007-10-12 21:08:00 +0200418static ssize_t
419show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
420{
421 int nr = to_sensor_dev_attr(devattr)->index;
422 struct w83627hf_data *data = w83627hf_update_device(dev);
423 return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
424}
425static ssize_t
426store_in_min(struct device *dev, struct device_attribute *devattr,
427 const char *buf, size_t count)
428{
429 int nr = to_sensor_dev_attr(devattr)->index;
430 struct w83627hf_data *data = dev_get_drvdata(dev);
431 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Jim Cromie07584c72007-10-12 21:08:00 +0200433 mutex_lock(&data->update_lock);
434 data->in_min[nr] = IN_TO_REG(val);
435 w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
436 mutex_unlock(&data->update_lock);
437 return count;
438}
439static ssize_t
440store_in_max(struct device *dev, struct device_attribute *devattr,
441 const char *buf, size_t count)
442{
443 int nr = to_sensor_dev_attr(devattr)->index;
444 struct w83627hf_data *data = dev_get_drvdata(dev);
445 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Jim Cromie07584c72007-10-12 21:08:00 +0200447 mutex_lock(&data->update_lock);
448 data->in_max[nr] = IN_TO_REG(val);
449 w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
450 mutex_unlock(&data->update_lock);
451 return count;
452}
453#define sysfs_vin_decl(offset) \
454static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
455 show_in_input, NULL, offset); \
456static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \
457 show_in_min, store_in_min, offset); \
458static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \
459 show_in_max, store_in_max, offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Jim Cromie07584c72007-10-12 21:08:00 +0200461sysfs_vin_decl(1);
462sysfs_vin_decl(2);
463sysfs_vin_decl(3);
464sysfs_vin_decl(4);
465sysfs_vin_decl(5);
466sysfs_vin_decl(6);
467sysfs_vin_decl(7);
468sysfs_vin_decl(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470/* use a different set of functions for in0 */
471static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
472{
473 long in0;
474
475 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100476 (w83627thf == data->type || w83637hf == data->type
477 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 /* use VRM9 calculation */
480 in0 = (long)((reg * 488 + 70000 + 50) / 100);
481 else
482 /* use VRM8 (standard) calculation */
483 in0 = (long)IN_FROM_REG(reg);
484
485 return sprintf(buf,"%ld\n", in0);
486}
487
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400488static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
490 struct w83627hf_data *data = w83627hf_update_device(dev);
491 return show_in_0(data, buf, data->in[0]);
492}
493
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400494static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
496 struct w83627hf_data *data = w83627hf_update_device(dev);
497 return show_in_0(data, buf, data->in_min[0]);
498}
499
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400500static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 struct w83627hf_data *data = w83627hf_update_device(dev);
503 return show_in_0(data, buf, data->in_max[0]);
504}
505
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400506static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 const char *buf, size_t count)
508{
Jean Delvare787c72b2007-05-08 17:22:00 +0200509 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 u32 val;
511
512 val = simple_strtoul(buf, NULL, 10);
513
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100514 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100517 (w83627thf == data->type || w83637hf == data->type
518 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800521 data->in_min[0] =
522 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
523 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 else
525 /* use VRM8 (standard) calculation */
526 data->in_min[0] = IN_TO_REG(val);
527
Jean Delvare787c72b2007-05-08 17:22:00 +0200528 w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100529 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return count;
531}
532
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400533static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 const char *buf, size_t count)
535{
Jean Delvare787c72b2007-05-08 17:22:00 +0200536 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 u32 val;
538
539 val = simple_strtoul(buf, NULL, 10);
540
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100541 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 if ((data->vrm_ovt & 0x01) &&
Jean Delvarec2db6ce2006-01-18 23:22:12 +0100544 (w83627thf == data->type || w83637hf == data->type
545 || w83687thf == data->type))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 /* use VRM9 calculation */
Yuan Mu2723ab92005-11-23 15:44:21 -0800548 data->in_max[0] =
549 SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
550 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 else
552 /* use VRM8 (standard) calculation */
553 data->in_max[0] = IN_TO_REG(val);
554
Jean Delvare787c72b2007-05-08 17:22:00 +0200555 w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100556 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return count;
558}
559
560static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
561static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
562 show_regs_in_min0, store_regs_in_min0);
563static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
564 show_regs_in_max0, store_regs_in_max0);
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200567show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Jim Cromie07584c72007-10-12 21:08:00 +0200569 int nr = to_sensor_dev_attr(devattr)->index;
570 struct w83627hf_data *data = w83627hf_update_device(dev);
571 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
572 (long)DIV_FROM_REG(data->fan_div[nr])));
573}
574static ssize_t
575show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
576{
577 int nr = to_sensor_dev_attr(devattr)->index;
578 struct w83627hf_data *data = w83627hf_update_device(dev);
579 return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
580 (long)DIV_FROM_REG(data->fan_div[nr])));
581}
582static ssize_t
583store_fan_min(struct device *dev, struct device_attribute *devattr,
584 const char *buf, size_t count)
585{
586 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200587 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200588 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100590 mutex_lock(&data->update_lock);
Jim Cromie07584c72007-10-12 21:08:00 +0200591 data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
592 w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1),
593 data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100595 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 return count;
597}
Jim Cromie07584c72007-10-12 21:08:00 +0200598#define sysfs_fan_decl(offset) \
599static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
600 show_fan_input, NULL, offset - 1); \
601static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
602 show_fan_min, store_fan_min, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Jim Cromie07584c72007-10-12 21:08:00 +0200604sysfs_fan_decl(1);
605sysfs_fan_decl(2);
606sysfs_fan_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Jim Cromie07584c72007-10-12 21:08:00 +0200608static ssize_t
609show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
610{
611 int nr = to_sensor_dev_attr(devattr)->index;
612 struct w83627hf_data *data = w83627hf_update_device(dev);
613 if (nr >= 2) { /* TEMP2 and TEMP3 */
614 return sprintf(buf, "%ld\n",
615 (long)LM75_TEMP_FROM_REG(data->temp_add[nr-2]));
616 } else { /* TEMP1 */
617 return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->temp));
618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Jim Cromie07584c72007-10-12 21:08:00 +0200621static ssize_t
622show_temp_max(struct device *dev, struct device_attribute *devattr,
623 char *buf)
624{
625 int nr = to_sensor_dev_attr(devattr)->index;
626 struct w83627hf_data *data = w83627hf_update_device(dev);
627 if (nr >= 2) { /* TEMP2 and TEMP3 */
628 return sprintf(buf, "%ld\n",
629 (long)LM75_TEMP_FROM_REG(data->temp_max_add[nr-2]));
630 } else { /* TEMP1 */
631 return sprintf(buf, "%ld\n",
632 (long)TEMP_FROM_REG(data->temp_max));
633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Jim Cromie07584c72007-10-12 21:08:00 +0200636static ssize_t
637show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
638 char *buf)
639{
640 int nr = to_sensor_dev_attr(devattr)->index;
641 struct w83627hf_data *data = w83627hf_update_device(dev);
642 if (nr >= 2) { /* TEMP2 and TEMP3 */
643 return sprintf(buf, "%ld\n",
644 (long)LM75_TEMP_FROM_REG(data->temp_max_hyst_add[nr-2]));
645 } else { /* TEMP1 */
646 return sprintf(buf, "%ld\n",
647 (long)TEMP_FROM_REG(data->temp_max_hyst));
648 }
649}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Jim Cromie07584c72007-10-12 21:08:00 +0200651static ssize_t
652store_temp_max(struct device *dev, struct device_attribute *devattr,
653 const char *buf, size_t count)
654{
655 int nr = to_sensor_dev_attr(devattr)->index;
656 struct w83627hf_data *data = dev_get_drvdata(dev);
657 long val = simple_strtol(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Jim Cromie07584c72007-10-12 21:08:00 +0200659 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Jim Cromie07584c72007-10-12 21:08:00 +0200661 if (nr >= 2) { /* TEMP2 and TEMP3 */
662 data->temp_max_add[nr-2] = LM75_TEMP_TO_REG(val);
663 w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
664 data->temp_max_add[nr-2]);
665 } else { /* TEMP1 */
666 data->temp_max = TEMP_TO_REG(val);
667 w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
668 data->temp_max);
669 }
670 mutex_unlock(&data->update_lock);
671 return count;
672}
673
674static ssize_t
675store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
676 const char *buf, size_t count)
677{
678 int nr = to_sensor_dev_attr(devattr)->index;
679 struct w83627hf_data *data = dev_get_drvdata(dev);
680 long val = simple_strtol(buf, NULL, 10);
681
682 mutex_lock(&data->update_lock);
683
684 if (nr >= 2) { /* TEMP2 and TEMP3 */
685 data->temp_max_hyst_add[nr-2] = LM75_TEMP_TO_REG(val);
686 w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
687 data->temp_max_hyst_add[nr-2]);
688 } else { /* TEMP1 */
689 data->temp_max_hyst = TEMP_TO_REG(val);
690 w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
691 data->temp_max_hyst);
692 }
693 mutex_unlock(&data->update_lock);
694 return count;
695}
696
697#define sysfs_temp_decl(offset) \
698static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
699 show_temp, NULL, offset); \
700static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \
701 show_temp_max, store_temp_max, offset); \
702static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \
703 show_temp_max_hyst, store_temp_max_hyst, offset);
704
705sysfs_temp_decl(1);
706sysfs_temp_decl(2);
707sysfs_temp_decl(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400710show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
712 struct w83627hf_data *data = w83627hf_update_device(dev);
713 return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
714}
715static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400718show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
Jean Delvare90d66192007-10-08 18:24:35 +0200720 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return sprintf(buf, "%ld\n", (long) data->vrm);
722}
723static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400724store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
Jean Delvare787c72b2007-05-08 17:22:00 +0200726 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 u32 val;
728
729 val = simple_strtoul(buf, NULL, 10);
730 data->vrm = val;
731
732 return count;
733}
734static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736static ssize_t
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400737show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738{
739 struct w83627hf_data *data = w83627hf_update_device(dev);
740 return sprintf(buf, "%ld\n", (long) data->alarms);
741}
742static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744#define show_beep_reg(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400745static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{ \
747 struct w83627hf_data *data = w83627hf_update_device(dev); \
748 return sprintf(buf,"%ld\n", \
749 (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
750}
751show_beep_reg(ENABLE, enable)
752show_beep_reg(MASK, mask)
753
754#define BEEP_ENABLE 0 /* Store beep_enable */
755#define BEEP_MASK 1 /* Store beep_mask */
756
757static ssize_t
758store_beep_reg(struct device *dev, const char *buf, size_t count,
759 int update_mask)
760{
Jean Delvare787c72b2007-05-08 17:22:00 +0200761 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 u32 val, val2;
763
764 val = simple_strtoul(buf, NULL, 10);
765
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100766 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
769 data->beep_mask = BEEP_MASK_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200770 w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 data->beep_mask & 0xff);
Jean Delvare787c72b2007-05-08 17:22:00 +0200772 w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 ((data->beep_mask) >> 16) & 0xff);
774 val2 = (data->beep_mask >> 8) & 0x7f;
775 } else { /* We are storing beep_enable */
776 val2 =
Jean Delvare787c72b2007-05-08 17:22:00 +0200777 w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 data->beep_enable = BEEP_ENABLE_TO_REG(val);
779 }
780
Jean Delvare787c72b2007-05-08 17:22:00 +0200781 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 val2 | data->beep_enable << 7);
783
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100784 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return count;
786}
787
788#define sysfs_beep(REG, reg) \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400789static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{ \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400791 return show_beep_##reg(dev, attr, buf); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792} \
793static ssize_t \
Yani Ioannoua5099cf2005-05-17 06:42:25 -0400794store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{ \
796 return store_beep_reg(dev, buf, count, BEEP_##REG); \
797} \
798static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
799 show_regs_beep_##reg, store_regs_beep_##reg);
800
801sysfs_beep(ENABLE, enable);
802sysfs_beep(MASK, mask);
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200805show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
Jim Cromie07584c72007-10-12 21:08:00 +0200807 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 struct w83627hf_data *data = w83627hf_update_device(dev);
809 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200810 (long) DIV_FROM_REG(data->fan_div[nr]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812/* Note: we save and restore the fan minimum here, because its value is
813 determined in part by the fan divisor. This follows the principle of
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200814 least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 because the divisor changed. */
816static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200817store_fan_div(struct device *dev, struct device_attribute *devattr,
818 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
Jim Cromie07584c72007-10-12 21:08:00 +0200820 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200821 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 unsigned long min;
823 u8 reg;
824 unsigned long val = simple_strtoul(buf, NULL, 10);
825
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100826 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 /* Save fan_min */
829 min = FAN_FROM_REG(data->fan_min[nr],
830 DIV_FROM_REG(data->fan_div[nr]));
831
832 data->fan_div[nr] = DIV_TO_REG(val);
833
Jean Delvare787c72b2007-05-08 17:22:00 +0200834 reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 & (nr==0 ? 0xcf : 0x3f))
836 | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
Jean Delvare787c72b2007-05-08 17:22:00 +0200837 w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Jean Delvare787c72b2007-05-08 17:22:00 +0200839 reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 & ~(1 << (5 + nr)))
841 | ((data->fan_div[nr] & 0x04) << (3 + nr));
Jean Delvare787c72b2007-05-08 17:22:00 +0200842 w83627hf_write_value(data, W83781D_REG_VBAT, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 /* Restore fan_min */
845 data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
Jean Delvare787c72b2007-05-08 17:22:00 +0200846 w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100848 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 return count;
850}
851
Jim Cromie07584c72007-10-12 21:08:00 +0200852static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
853 show_fan_div, store_fan_div, 0);
854static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
855 show_fan_div, store_fan_div, 1);
856static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
857 show_fan_div, store_fan_div, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200860show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Jim Cromie07584c72007-10-12 21:08:00 +0200862 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200864 return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
867static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200868store_pwm(struct device *dev, struct device_attribute *devattr,
869 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Jim Cromie07584c72007-10-12 21:08:00 +0200871 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200872 struct w83627hf_data *data = dev_get_drvdata(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200873 u32 val = simple_strtoul(buf, NULL, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100875 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 if (data->type == w83627thf) {
878 /* bits 0-3 are reserved in 627THF */
Jim Cromie07584c72007-10-12 21:08:00 +0200879 data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
Jean Delvare787c72b2007-05-08 17:22:00 +0200880 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200882 data->pwm[nr] |
Jean Delvare787c72b2007-05-08 17:22:00 +0200883 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
885 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200886 data->pwm[nr] = PWM_TO_REG(val);
Jean Delvare787c72b2007-05-08 17:22:00 +0200887 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 W836X7HF_REG_PWM(data->type, nr),
Jim Cromie07584c72007-10-12 21:08:00 +0200889 data->pwm[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 }
891
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100892 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return count;
894}
895
Jim Cromie07584c72007-10-12 21:08:00 +0200896static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
897static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
898static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200901show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400902{
Jim Cromie07584c72007-10-12 21:08:00 +0200903 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400904 struct w83627hf_data *data = w83627hf_update_device(dev);
905 if (data->type == w83627hf)
906 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200907 pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400908 else
909 return sprintf(buf, "%ld\n",
Jim Cromie07584c72007-10-12 21:08:00 +0200910 pwm_freq_from_reg(data->pwm_freq[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400911}
912
913static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200914store_pwm_freq(struct device *dev, struct device_attribute *devattr,
915 const char *buf, size_t count)
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400916{
Jim Cromie07584c72007-10-12 21:08:00 +0200917 int nr = to_sensor_dev_attr(devattr)->index;
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400918 struct w83627hf_data *data = dev_get_drvdata(dev);
919 static const u8 mask[]={0xF8, 0x8F};
920 u32 val;
921
922 val = simple_strtoul(buf, NULL, 10);
923
924 mutex_lock(&data->update_lock);
925
926 if (data->type == w83627hf) {
Jim Cromie07584c72007-10-12 21:08:00 +0200927 data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400928 w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
Jim Cromie07584c72007-10-12 21:08:00 +0200929 (data->pwm_freq[nr] << (nr*4)) |
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400930 (w83627hf_read_value(data,
Jim Cromie07584c72007-10-12 21:08:00 +0200931 W83627HF_REG_PWM_FREQ) & mask[nr]));
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400932 } else {
Jim Cromie07584c72007-10-12 21:08:00 +0200933 data->pwm_freq[nr] = pwm_freq_to_reg(val);
934 w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
935 data->pwm_freq[nr]);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400936 }
937
938 mutex_unlock(&data->update_lock);
939 return count;
940}
941
Jim Cromie07584c72007-10-12 21:08:00 +0200942static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
943 show_pwm_freq, store_pwm_freq, 0);
944static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
945 show_pwm_freq, store_pwm_freq, 1);
946static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
947 show_pwm_freq, store_pwm_freq, 2);
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -0400948
949static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200950show_temp_type(struct device *dev, struct device_attribute *devattr,
951 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
Jim Cromie07584c72007-10-12 21:08:00 +0200953 int nr = to_sensor_dev_attr(devattr)->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 struct w83627hf_data *data = w83627hf_update_device(dev);
Jim Cromie07584c72007-10-12 21:08:00 +0200955 return sprintf(buf, "%ld\n", (long) data->sens[nr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956}
957
958static ssize_t
Jim Cromie07584c72007-10-12 21:08:00 +0200959store_temp_type(struct device *dev, struct device_attribute *devattr,
960 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Jim Cromie07584c72007-10-12 21:08:00 +0200962 int nr = to_sensor_dev_attr(devattr)->index;
Jean Delvare787c72b2007-05-08 17:22:00 +0200963 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 u32 val, tmp;
965
966 val = simple_strtoul(buf, NULL, 10);
967
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100968 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 switch (val) {
971 case 1: /* PII/Celeron diode */
Jean Delvare787c72b2007-05-08 17:22:00 +0200972 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
973 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200974 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +0200975 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
976 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +0200977 tmp | BIT_SCFG2[nr]);
978 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 break;
980 case 2: /* 3904 */
Jean Delvare787c72b2007-05-08 17:22:00 +0200981 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
982 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200983 tmp | BIT_SCFG1[nr]);
Jean Delvare787c72b2007-05-08 17:22:00 +0200984 tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
985 w83627hf_write_value(data, W83781D_REG_SCFG2,
Jim Cromie07584c72007-10-12 21:08:00 +0200986 tmp & ~BIT_SCFG2[nr]);
987 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 break;
Jean Delvareb26f9332007-08-16 14:30:01 +0200989 case W83781D_DEFAULT_BETA:
990 dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
991 "instead\n", W83781D_DEFAULT_BETA);
992 /* fall through */
993 case 4: /* thermistor */
Jean Delvare787c72b2007-05-08 17:22:00 +0200994 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
995 w83627hf_write_value(data, W83781D_REG_SCFG1,
Jim Cromie07584c72007-10-12 21:08:00 +0200996 tmp & ~BIT_SCFG1[nr]);
997 data->sens[nr] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 break;
999 default:
Jean Delvare787c72b2007-05-08 17:22:00 +02001000 dev_err(dev,
Jean Delvareb26f9332007-08-16 14:30:01 +02001001 "Invalid sensor type %ld; must be 1, 2, or 4\n",
1002 (long) val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 break;
1004 }
1005
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001006 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return count;
1008}
1009
Jim Cromie07584c72007-10-12 21:08:00 +02001010#define sysfs_temp_type(offset) \
1011static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
1012 show_temp_type, store_temp_type, offset - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Jim Cromie07584c72007-10-12 21:08:00 +02001014sysfs_temp_type(1);
1015sysfs_temp_type(2);
1016sysfs_temp_type(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Jim Cromie07584c72007-10-12 21:08:00 +02001018static ssize_t
1019show_name(struct device *dev, struct device_attribute *devattr, char *buf)
Jean Delvare787c72b2007-05-08 17:22:00 +02001020{
1021 struct w83627hf_data *data = dev_get_drvdata(dev);
1022
1023 return sprintf(buf, "%s\n", data->name);
1024}
1025static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1026
1027static int __init w83627hf_find(int sioaddr, unsigned short *addr,
1028 struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Jean Delvared27c37c2007-05-08 17:21:59 +02001030 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 u16 val;
1032
Jean Delvare787c72b2007-05-08 17:22:00 +02001033 static const __initdata char *names[] = {
1034 "W83627HF",
1035 "W83627THF",
1036 "W83697HF",
1037 "W83637HF",
1038 "W83687THF",
1039 };
1040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 REG = sioaddr;
1042 VAL = sioaddr + 1;
1043
1044 superio_enter();
1045 val= superio_inb(DEVID);
Jean Delvare787c72b2007-05-08 17:22:00 +02001046 switch (val) {
1047 case W627_DEVID:
1048 sio_data->type = w83627hf;
1049 break;
1050 case W627THF_DEVID:
1051 sio_data->type = w83627thf;
1052 break;
1053 case W697_DEVID:
1054 sio_data->type = w83697hf;
1055 break;
1056 case W637_DEVID:
1057 sio_data->type = w83637hf;
1058 break;
1059 case W687THF_DEVID:
1060 sio_data->type = w83687thf;
1061 break;
Jean Delvaree142e2a2007-05-27 22:17:43 +02001062 case 0xff: /* No device at all */
1063 goto exit;
Jean Delvare787c72b2007-05-08 17:22:00 +02001064 default:
Jean Delvaree142e2a2007-05-27 22:17:43 +02001065 pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
Jean Delvared27c37c2007-05-08 17:21:59 +02001066 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 }
1068
1069 superio_select(W83627HF_LD_HWM);
Jean Delvared27c37c2007-05-08 17:21:59 +02001070 force_addr &= WINB_ALIGNMENT;
1071 if (force_addr) {
1072 printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
1073 force_addr);
1074 superio_outb(WINB_BASE_REG, force_addr >> 8);
1075 superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
1076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 val = (superio_inb(WINB_BASE_REG) << 8) |
1078 superio_inb(WINB_BASE_REG + 1);
Petr Vandrovecada0c2f2005-10-07 23:11:03 +02001079 *addr = val & WINB_ALIGNMENT;
Jean Delvared27c37c2007-05-08 17:21:59 +02001080 if (*addr == 0) {
1081 printk(KERN_WARNING DRVNAME ": Base address not set, "
1082 "skipping\n");
1083 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
Jean Delvared27c37c2007-05-08 17:21:59 +02001086 val = superio_inb(WINB_ACT_REG);
1087 if (!(val & 0x01)) {
1088 printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
1089 superio_outb(WINB_ACT_REG, val | 0x01);
1090 }
1091
1092 err = 0;
Jean Delvare787c72b2007-05-08 17:22:00 +02001093 pr_info(DRVNAME ": Found %s chip at %#x\n",
1094 names[sio_data->type], *addr);
Jean Delvared27c37c2007-05-08 17:21:59 +02001095
1096 exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 superio_exit();
Jean Delvared27c37c2007-05-08 17:21:59 +02001098 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099}
1100
Jim Cromie07584c72007-10-12 21:08:00 +02001101#define VIN_UNIT_ATTRS(_X_) \
1102 &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
1103 &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
1104 &sensor_dev_attr_in##_X_##_max.dev_attr.attr
1105
1106#define FAN_UNIT_ATTRS(_X_) \
1107 &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
1108 &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
1109 &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
1110
1111#define TEMP_UNIT_ATTRS(_X_) \
1112 &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
1113 &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
1114 &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
1115 &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
1116
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001117static struct attribute *w83627hf_attributes[] = {
1118 &dev_attr_in0_input.attr,
1119 &dev_attr_in0_min.attr,
1120 &dev_attr_in0_max.attr,
Jim Cromie07584c72007-10-12 21:08:00 +02001121 VIN_UNIT_ATTRS(2),
1122 VIN_UNIT_ATTRS(3),
1123 VIN_UNIT_ATTRS(4),
1124 VIN_UNIT_ATTRS(7),
1125 VIN_UNIT_ATTRS(8),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001126
Jim Cromie07584c72007-10-12 21:08:00 +02001127 FAN_UNIT_ATTRS(1),
1128 FAN_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001129
Jim Cromie07584c72007-10-12 21:08:00 +02001130 TEMP_UNIT_ATTRS(1),
1131 TEMP_UNIT_ATTRS(2),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001132
1133 &dev_attr_alarms.attr,
1134 &dev_attr_beep_enable.attr,
1135 &dev_attr_beep_mask.attr,
1136
Jim Cromie07584c72007-10-12 21:08:00 +02001137 &sensor_dev_attr_pwm1.dev_attr.attr,
1138 &sensor_dev_attr_pwm2.dev_attr.attr,
Jean Delvare787c72b2007-05-08 17:22:00 +02001139 &dev_attr_name.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001140 NULL
1141};
1142
1143static const struct attribute_group w83627hf_group = {
1144 .attrs = w83627hf_attributes,
1145};
1146
1147static struct attribute *w83627hf_attributes_opt[] = {
Jim Cromie07584c72007-10-12 21:08:00 +02001148 VIN_UNIT_ATTRS(1),
1149 VIN_UNIT_ATTRS(5),
1150 VIN_UNIT_ATTRS(6),
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001151
Jim Cromie07584c72007-10-12 21:08:00 +02001152 FAN_UNIT_ATTRS(3),
1153 TEMP_UNIT_ATTRS(3),
1154 &sensor_dev_attr_pwm3.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001155
Jim Cromie07584c72007-10-12 21:08:00 +02001156 &sensor_dev_attr_pwm1_freq.dev_attr.attr,
1157 &sensor_dev_attr_pwm2_freq.dev_attr.attr,
1158 &sensor_dev_attr_pwm3_freq.dev_attr.attr,
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001159 NULL
1160};
1161
1162static const struct attribute_group w83627hf_group_opt = {
1163 .attrs = w83627hf_attributes_opt,
1164};
1165
Jean Delvare787c72b2007-05-08 17:22:00 +02001166static int __devinit w83627hf_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
Jean Delvare787c72b2007-05-08 17:22:00 +02001168 struct device *dev = &pdev->dev;
1169 struct w83627hf_sio_data *sio_data = dev->platform_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 struct w83627hf_data *data;
Jean Delvare787c72b2007-05-08 17:22:00 +02001171 struct resource *res;
1172 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
Jean Delvare787c72b2007-05-08 17:22:00 +02001174 static const char *names[] = {
1175 "w83627hf",
1176 "w83627thf",
1177 "w83697hf",
1178 "w83637hf",
1179 "w83687thf",
1180 };
1181
1182 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1183 if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
1184 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1185 (unsigned long)res->start,
1186 (unsigned long)(res->start + WINB_REGION_SIZE - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 err = -EBUSY;
1188 goto ERROR0;
1189 }
1190
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001191 if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 err = -ENOMEM;
1193 goto ERROR1;
1194 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001195 data->addr = res->start;
1196 data->type = sio_data->type;
1197 data->name = names[sio_data->type];
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001198 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001199 mutex_init(&data->update_lock);
Jean Delvare787c72b2007-05-08 17:22:00 +02001200 platform_set_drvdata(pdev, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 /* Initialize the chip */
Jean Delvare787c72b2007-05-08 17:22:00 +02001203 w83627hf_init_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205 /* A few vars need to be filled upon startup */
Jean Delvare787c72b2007-05-08 17:22:00 +02001206 data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
1207 data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
1208 data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001210 /* Register common device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001211 if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001212 goto ERROR3;
1213
1214 /* Register chip-specific device attributes */
Jean Delvare787c72b2007-05-08 17:22:00 +02001215 if (data->type == w83627hf || data->type == w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001216 if ((err = device_create_file(dev,
1217 &sensor_dev_attr_in5_input.dev_attr))
1218 || (err = device_create_file(dev,
1219 &sensor_dev_attr_in5_min.dev_attr))
1220 || (err = device_create_file(dev,
1221 &sensor_dev_attr_in5_max.dev_attr))
1222 || (err = device_create_file(dev,
1223 &sensor_dev_attr_in6_input.dev_attr))
1224 || (err = device_create_file(dev,
1225 &sensor_dev_attr_in6_min.dev_attr))
1226 || (err = device_create_file(dev,
1227 &sensor_dev_attr_in6_max.dev_attr))
1228 || (err = device_create_file(dev,
1229 &sensor_dev_attr_pwm1_freq.dev_attr))
1230 || (err = device_create_file(dev,
1231 &sensor_dev_attr_pwm2_freq.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001232 goto ERROR4;
1233
Jean Delvare787c72b2007-05-08 17:22:00 +02001234 if (data->type != w83697hf)
Jim Cromie07584c72007-10-12 21:08:00 +02001235 if ((err = device_create_file(dev,
1236 &sensor_dev_attr_in1_input.dev_attr))
1237 || (err = device_create_file(dev,
1238 &sensor_dev_attr_in1_min.dev_attr))
1239 || (err = device_create_file(dev,
1240 &sensor_dev_attr_in1_max.dev_attr))
1241 || (err = device_create_file(dev,
1242 &sensor_dev_attr_fan3_input.dev_attr))
1243 || (err = device_create_file(dev,
1244 &sensor_dev_attr_fan3_min.dev_attr))
1245 || (err = device_create_file(dev,
1246 &sensor_dev_attr_fan3_div.dev_attr))
1247 || (err = device_create_file(dev,
1248 &sensor_dev_attr_temp3_input.dev_attr))
1249 || (err = device_create_file(dev,
1250 &sensor_dev_attr_temp3_max.dev_attr))
1251 || (err = device_create_file(dev,
1252 &sensor_dev_attr_temp3_max_hyst.dev_attr))
1253 || (err = device_create_file(dev,
1254 &sensor_dev_attr_temp3_type.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001255 goto ERROR4;
1256
Jean Delvare787c72b2007-05-08 17:22:00 +02001257 if (data->type != w83697hf && data->vid != 0xff) {
Jean Delvare8a665a02007-05-08 17:21:59 +02001258 /* Convert VID to voltage based on VRM */
1259 data->vrm = vid_which_vrm();
1260
Jean Delvare787c72b2007-05-08 17:22:00 +02001261 if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
1262 || (err = device_create_file(dev, &dev_attr_vrm)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001263 goto ERROR4;
Jean Delvare8a665a02007-05-08 17:21:59 +02001264 }
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001265
Jean Delvare787c72b2007-05-08 17:22:00 +02001266 if (data->type == w83627thf || data->type == w83637hf
1267 || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001268 if ((err = device_create_file(dev,
1269 &sensor_dev_attr_pwm3.dev_attr)))
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001270 goto ERROR4;
1271
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001272 if (data->type == w83637hf || data->type == w83687thf)
Jim Cromie07584c72007-10-12 21:08:00 +02001273 if ((err = device_create_file(dev,
1274 &sensor_dev_attr_pwm1_freq.dev_attr))
1275 || (err = device_create_file(dev,
1276 &sensor_dev_attr_pwm2_freq.dev_attr))
1277 || (err = device_create_file(dev,
1278 &sensor_dev_attr_pwm3_freq.dev_attr)))
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001279 goto ERROR4;
1280
Tony Jones1beeffe2007-08-20 13:46:20 -07001281 data->hwmon_dev = hwmon_device_register(dev);
1282 if (IS_ERR(data->hwmon_dev)) {
1283 err = PTR_ERR(data->hwmon_dev);
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001284 goto ERROR4;
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001285 }
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 return 0;
1288
Mark M. Hoffmanc1685f62006-09-24 20:59:49 +02001289 ERROR4:
Jean Delvare787c72b2007-05-08 17:22:00 +02001290 sysfs_remove_group(&dev->kobj, &w83627hf_group);
1291 sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001292 ERROR3:
Jean Delvare04a62172007-06-12 13:57:19 +02001293 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 kfree(data);
1295 ERROR1:
Jean Delvare787c72b2007-05-08 17:22:00 +02001296 release_region(res->start, WINB_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 ERROR0:
1298 return err;
1299}
1300
Jean Delvare787c72b2007-05-08 17:22:00 +02001301static int __devexit w83627hf_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
Jean Delvare787c72b2007-05-08 17:22:00 +02001303 struct w83627hf_data *data = platform_get_drvdata(pdev);
1304 struct resource *res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Tony Jones1beeffe2007-08-20 13:46:20 -07001306 hwmon_device_unregister(data->hwmon_dev);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001307
Jean Delvare787c72b2007-05-08 17:22:00 +02001308 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
1309 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
Jean Delvare04a62172007-06-12 13:57:19 +02001310 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001311 kfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
Jean Delvare787c72b2007-05-08 17:22:00 +02001313 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1314 release_region(res->start, WINB_REGION_SIZE);
1315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 return 0;
1317}
1318
1319
Jean Delvare787c72b2007-05-08 17:22:00 +02001320static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 int res, word_sized;
1323
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001324 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 word_sized = (((reg & 0xff00) == 0x100)
1326 || ((reg & 0xff00) == 0x200))
1327 && (((reg & 0x00ff) == 0x50)
1328 || ((reg & 0x00ff) == 0x53)
1329 || ((reg & 0x00ff) == 0x55));
1330 if (reg & 0xff00) {
1331 outb_p(W83781D_REG_BANK,
Jean Delvare787c72b2007-05-08 17:22:00 +02001332 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 outb_p(reg >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001334 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001336 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
1337 res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 if (word_sized) {
1339 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001340 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 res =
Jean Delvare787c72b2007-05-08 17:22:00 +02001342 (res << 8) + inb_p(data->addr +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 W83781D_DATA_REG_OFFSET);
1344 }
1345 if (reg & 0xff00) {
1346 outb_p(W83781D_REG_BANK,
Jean Delvare787c72b2007-05-08 17:22:00 +02001347 data->addr + W83781D_ADDR_REG_OFFSET);
1348 outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001350 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return res;
1352}
1353
Jean Delvare787c72b2007-05-08 17:22:00 +02001354static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355{
1356 int res = 0xff, sel;
1357
1358 superio_enter();
1359 superio_select(W83627HF_LD_GPIO5);
1360
1361 /* Make sure these GPIO pins are enabled */
1362 if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001363 dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 goto exit;
1365 }
1366
1367 /* Make sure the pins are configured for input
1368 There must be at least five (VRM 9), and possibly 6 (VRM 10) */
Yuan Mudd149c52005-11-26 20:13:18 +01001369 sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if ((sel & 0x1f) != 0x1f) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001371 dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 "function\n");
1373 goto exit;
1374 }
1375
Jean Delvare787c72b2007-05-08 17:22:00 +02001376 dev_info(&pdev->dev, "Reading VID from GPIO5\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 res = superio_inb(W83627THF_GPIO5_DR) & sel;
1378
1379exit:
1380 superio_exit();
1381 return res;
1382}
1383
Jean Delvare787c72b2007-05-08 17:22:00 +02001384static int __devinit w83687thf_read_vid(struct platform_device *pdev)
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001385{
1386 int res = 0xff;
1387
1388 superio_enter();
1389 superio_select(W83627HF_LD_HWM);
1390
1391 /* Make sure these GPIO pins are enabled */
1392 if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001393 dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001394 goto exit;
1395 }
1396
1397 /* Make sure the pins are configured for input */
1398 if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001399 dev_dbg(&pdev->dev, "VID configured as output, "
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001400 "no VID function\n");
1401 goto exit;
1402 }
1403
1404 res = superio_inb(W83687THF_VID_DATA) & 0x3f;
1405
1406exit:
1407 superio_exit();
1408 return res;
1409}
1410
Jean Delvare787c72b2007-05-08 17:22:00 +02001411static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 int word_sized;
1414
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001415 mutex_lock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 word_sized = (((reg & 0xff00) == 0x100)
1417 || ((reg & 0xff00) == 0x200))
1418 && (((reg & 0x00ff) == 0x53)
1419 || ((reg & 0x00ff) == 0x55));
1420 if (reg & 0xff00) {
1421 outb_p(W83781D_REG_BANK,
Jean Delvare787c72b2007-05-08 17:22:00 +02001422 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 outb_p(reg >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001424 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001426 outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 if (word_sized) {
1428 outb_p(value >> 8,
Jean Delvare787c72b2007-05-08 17:22:00 +02001429 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 outb_p((reg & 0xff) + 1,
Jean Delvare787c72b2007-05-08 17:22:00 +02001431 data->addr + W83781D_ADDR_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 }
1433 outb_p(value & 0xff,
Jean Delvare787c72b2007-05-08 17:22:00 +02001434 data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if (reg & 0xff00) {
1436 outb_p(W83781D_REG_BANK,
Jean Delvare787c72b2007-05-08 17:22:00 +02001437 data->addr + W83781D_ADDR_REG_OFFSET);
1438 outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001440 mutex_unlock(&data->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 return 0;
1442}
1443
Jean Delvare787c72b2007-05-08 17:22:00 +02001444static void __devinit w83627hf_init_device(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445{
Jean Delvare787c72b2007-05-08 17:22:00 +02001446 struct w83627hf_data *data = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 int i;
Jean Delvared27c37c2007-05-08 17:21:59 +02001448 enum chips type = data->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 u8 tmp;
1450
Jean Delvare2251cf12005-09-04 22:52:17 +02001451 if (reset) {
1452 /* Resetting the chip has been the default for a long time,
1453 but repeatedly caused problems (fans going to full
1454 speed...) so it is now optional. It might even go away if
1455 nobody reports it as being useful, as I see very little
1456 reason why this would be needed at all. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001457 dev_info(&pdev->dev, "If reset=1 solved a problem you were "
Jean Delvare2251cf12005-09-04 22:52:17 +02001458 "having, please report!\n");
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 /* save this register */
Jean Delvare787c72b2007-05-08 17:22:00 +02001461 i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 /* Reset all except Watchdog values and last conversion values
1463 This sets fan-divs to 2, among others */
Jean Delvare787c72b2007-05-08 17:22:00 +02001464 w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 /* Restore the register and disable power-on abnormal beep.
1466 This saves FAN 1/2/3 input/output values set by BIOS. */
Jean Delvare787c72b2007-05-08 17:22:00 +02001467 w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 /* Disable master beep-enable (reset turns it on).
1469 Individual beeps should be reset to off but for some reason
1470 disabling this bit helps some people not get beeped */
Jean Delvare787c72b2007-05-08 17:22:00 +02001471 w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473
1474 /* Minimize conflicts with other winbond i2c-only clients... */
1475 /* disable i2c subclients... how to disable main i2c client?? */
1476 /* force i2c address to relatively uncommon address */
Jean Delvare787c72b2007-05-08 17:22:00 +02001477 w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
1478 w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 /* Read VID only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001481 if (type == w83627hf || type == w83637hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001482 int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
1483 int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
Jean Delvared27c37c2007-05-08 17:21:59 +02001485 } else if (type == w83627thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001486 data->vid = w83627thf_read_gpio5(pdev);
Jean Delvared27c37c2007-05-08 17:21:59 +02001487 } else if (type == w83687thf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001488 data->vid = w83687thf_read_vid(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
1490
1491 /* Read VRM & OVT Config only once */
Jean Delvared27c37c2007-05-08 17:21:59 +02001492 if (type == w83627thf || type == w83637hf || type == w83687thf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 data->vrm_ovt =
Jean Delvare787c72b2007-05-08 17:22:00 +02001494 w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 }
1496
Jean Delvare787c72b2007-05-08 17:22:00 +02001497 tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 for (i = 1; i <= 3; i++) {
1499 if (!(tmp & BIT_SCFG1[i - 1])) {
Jean Delvareb26f9332007-08-16 14:30:01 +02001500 data->sens[i - 1] = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 } else {
1502 if (w83627hf_read_value
Jean Delvare787c72b2007-05-08 17:22:00 +02001503 (data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
1505 data->sens[i - 1] = 1;
1506 else
1507 data->sens[i - 1] = 2;
1508 }
1509 if ((type == w83697hf) && (i == 2))
1510 break;
1511 }
1512
1513 if(init) {
1514 /* Enable temp2 */
Jean Delvare787c72b2007-05-08 17:22:00 +02001515 tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001517 dev_warn(&pdev->dev, "Enabling temp2, readings "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 "might not make sense\n");
Jean Delvare787c72b2007-05-08 17:22:00 +02001519 w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 tmp & 0xfe);
1521 }
1522
1523 /* Enable temp3 */
1524 if (type != w83697hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001525 tmp = w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 W83781D_REG_TEMP3_CONFIG);
1527 if (tmp & 0x01) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001528 dev_warn(&pdev->dev, "Enabling temp3, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 "readings might not make sense\n");
Jean Delvare787c72b2007-05-08 17:22:00 +02001530 w83627hf_write_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
1532 }
1533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 }
1535
1536 /* Start monitoring */
Jean Delvare787c72b2007-05-08 17:22:00 +02001537 w83627hf_write_value(data, W83781D_REG_CONFIG,
1538 (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 W83781D_REG_CONFIG) & 0xf7)
1540 | 0x01);
1541}
1542
1543static struct w83627hf_data *w83627hf_update_device(struct device *dev)
1544{
Jean Delvare787c72b2007-05-08 17:22:00 +02001545 struct w83627hf_data *data = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 int i;
1547
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001548 mutex_lock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1551 || !data->valid) {
1552 for (i = 0; i <= 8; i++) {
1553 /* skip missing sensors */
1554 if (((data->type == w83697hf) && (i == 1)) ||
Jean Delvarec2db6ce2006-01-18 23:22:12 +01001555 ((data->type != w83627hf && data->type != w83697hf)
Yuan Mu4a1c44472005-11-07 22:19:04 +01001556 && (i == 5 || i == 6)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 continue;
1558 data->in[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001559 w83627hf_read_value(data, W83781D_REG_IN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 data->in_min[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001561 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 W83781D_REG_IN_MIN(i));
1563 data->in_max[i] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001564 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 W83781D_REG_IN_MAX(i));
1566 }
1567 for (i = 1; i <= 3; i++) {
1568 data->fan[i - 1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001569 w83627hf_read_value(data, W83781D_REG_FAN(i));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 data->fan_min[i - 1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001571 w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 W83781D_REG_FAN_MIN(i));
1573 }
Jim Cromie07584c72007-10-12 21:08:00 +02001574 for (i = 0; i <= 2; i++) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001575 u8 tmp = w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 W836X7HF_REG_PWM(data->type, i));
1577 /* bits 0-3 are reserved in 627THF */
1578 if (data->type == w83627thf)
1579 tmp &= 0xf0;
Jim Cromie07584c72007-10-12 21:08:00 +02001580 data->pwm[i] = tmp;
1581 if (i == 1 &&
1582 (data->type == w83627hf || data->type == w83697hf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 break;
1584 }
Carlos Olalla Martinez1550cb62007-06-09 10:11:16 -04001585 if (data->type == w83627hf) {
1586 u8 tmp = w83627hf_read_value(data,
1587 W83627HF_REG_PWM_FREQ);
1588 data->pwm_freq[0] = tmp & 0x07;
1589 data->pwm_freq[1] = (tmp >> 4) & 0x07;
1590 } else if (data->type != w83627thf) {
1591 for (i = 1; i <= 3; i++) {
1592 data->pwm_freq[i - 1] =
1593 w83627hf_read_value(data,
1594 W83637HF_REG_PWM_FREQ[i - 1]);
1595 if (i == 2 && (data->type == w83697hf))
1596 break;
1597 }
1598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
Jean Delvare787c72b2007-05-08 17:22:00 +02001600 data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 data->temp_max =
Jean Delvare787c72b2007-05-08 17:22:00 +02001602 w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 data->temp_max_hyst =
Jean Delvare787c72b2007-05-08 17:22:00 +02001604 w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 data->temp_add[0] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001606 w83627hf_read_value(data, W83781D_REG_TEMP(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 data->temp_max_add[0] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001608 w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 data->temp_max_hyst_add[0] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001610 w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 if (data->type != w83697hf) {
1612 data->temp_add[1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001613 w83627hf_read_value(data, W83781D_REG_TEMP(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 data->temp_max_add[1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001615 w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 data->temp_max_hyst_add[1] =
Jean Delvare787c72b2007-05-08 17:22:00 +02001617 w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
1619
Jean Delvare787c72b2007-05-08 17:22:00 +02001620 i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 data->fan_div[0] = (i >> 4) & 0x03;
1622 data->fan_div[1] = (i >> 6) & 0x03;
1623 if (data->type != w83697hf) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001624 data->fan_div[2] = (w83627hf_read_value(data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 W83781D_REG_PIN) >> 6) & 0x03;
1626 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001627 i = w83627hf_read_value(data, W83781D_REG_VBAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 data->fan_div[0] |= (i >> 3) & 0x04;
1629 data->fan_div[1] |= (i >> 4) & 0x04;
1630 if (data->type != w83697hf)
1631 data->fan_div[2] |= (i >> 5) & 0x04;
1632 data->alarms =
Jean Delvare787c72b2007-05-08 17:22:00 +02001633 w83627hf_read_value(data, W83781D_REG_ALARM1) |
1634 (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
1635 (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
1636 i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 data->beep_enable = i >> 7;
1638 data->beep_mask = ((i & 0x7f) << 8) |
Jean Delvare787c72b2007-05-08 17:22:00 +02001639 w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
1640 w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 data->last_updated = jiffies;
1642 data->valid = 1;
1643 }
1644
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001645 mutex_unlock(&data->update_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 return data;
1648}
1649
Jean Delvare787c72b2007-05-08 17:22:00 +02001650static int __init w83627hf_device_add(unsigned short address,
1651 const struct w83627hf_sio_data *sio_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652{
Jean Delvare787c72b2007-05-08 17:22:00 +02001653 struct resource res = {
1654 .start = address + WINB_REGION_OFFSET,
1655 .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
1656 .name = DRVNAME,
1657 .flags = IORESOURCE_IO,
1658 };
1659 int err;
1660
1661 pdev = platform_device_alloc(DRVNAME, address);
1662 if (!pdev) {
1663 err = -ENOMEM;
1664 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1665 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Jean Delvare787c72b2007-05-08 17:22:00 +02001668 err = platform_device_add_resources(pdev, &res, 1);
1669 if (err) {
1670 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1671 "(%d)\n", err);
1672 goto exit_device_put;
1673 }
1674
Jean Delvare2df6d812007-06-09 10:11:16 -04001675 err = platform_device_add_data(pdev, sio_data,
1676 sizeof(struct w83627hf_sio_data));
1677 if (err) {
Jean Delvare787c72b2007-05-08 17:22:00 +02001678 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1679 goto exit_device_put;
1680 }
Jean Delvare787c72b2007-05-08 17:22:00 +02001681
1682 err = platform_device_add(pdev);
1683 if (err) {
1684 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1685 err);
1686 goto exit_device_put;
1687 }
1688
1689 return 0;
1690
1691exit_device_put:
1692 platform_device_put(pdev);
1693exit:
1694 return err;
1695}
1696
1697static int __init sensors_w83627hf_init(void)
1698{
1699 int err;
1700 unsigned short address;
1701 struct w83627hf_sio_data sio_data;
1702
1703 if (w83627hf_find(0x2e, &address, &sio_data)
1704 && w83627hf_find(0x4e, &address, &sio_data))
1705 return -ENODEV;
1706
1707 err = platform_driver_register(&w83627hf_driver);
1708 if (err)
1709 goto exit;
1710
1711 /* Sets global pdev as a side effect */
1712 err = w83627hf_device_add(address, &sio_data);
1713 if (err)
1714 goto exit_driver;
1715
1716 return 0;
1717
1718exit_driver:
1719 platform_driver_unregister(&w83627hf_driver);
1720exit:
1721 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
1723
1724static void __exit sensors_w83627hf_exit(void)
1725{
Jean Delvare787c72b2007-05-08 17:22:00 +02001726 platform_device_unregister(pdev);
1727 platform_driver_unregister(&w83627hf_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728}
1729
1730MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1731 "Philip Edelbrock <phil@netroedge.com>, "
1732 "and Mark Studebaker <mdsxyz123@yahoo.com>");
1733MODULE_DESCRIPTION("W83627HF driver");
1734MODULE_LICENSE("GPL");
1735
1736module_init(sensors_w83627hf_init);
1737module_exit(sensors_w83627hf_exit);