blob: 072c58008a633b713e1f68fd3a522572a41842d1 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
3 the Winbond W83627EHF Super-I/O chip
4 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Jean Delvare7188cc62006-12-12 18:18:30 +01006 Rudolf Marek <r.marek@assembler.cz>
David Hubbardc18beb52006-09-24 21:04:38 +02007 David Hubbard <david.c.hubbard@gmail.com>
Daniel J Blueman41e9a062009-12-14 18:01:37 -08008 Daniel J Blueman <daniel.blueman@gmail.com>
Jean Delvare08e7e272005-04-25 22:43:25 +02009
10 Shamelessly ripped from the w83627hf driver
11 Copyright (C) 2003 Mark Studebaker
12
13 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
14 in testing and debugging this driver.
15
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020016 This driver also supports the W83627EHG, which is the lead-free
17 version of the W83627EHF.
18
Jean Delvare08e7e272005-04-25 22:43:25 +020019 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32
33
34 Supports the following chips:
35
David Hubbard657c93b2007-02-14 21:15:04 +010036 Chip #vin #fan #pwm #temp chip IDs man ID
37 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
38 0x8860 0xa1
39 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvarec1e48dc2009-06-15 18:39:50 +020040 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
Gong Jun237c8d22009-03-30 21:46:42 +020041 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Guenter Roeckc39aeda2010-08-14 21:08:55 +020042 w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020043*/
44
45#include <linux/module.h>
46#include <linux/init.h>
47#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020048#include <linux/jiffies.h>
49#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040050#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010051#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020052#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040053#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010054#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010055#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020056#include <linux/io.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020057#include "lm75.h"
58
Guenter Roeckc39aeda2010-08-14 21:08:55 +020059enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
David Hubbard1ea6dd32007-06-24 11:16:15 +020060
61/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
62static const char * w83627ehf_device_names[] = {
63 "w83627ehf",
64 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020065 "w83627dhg",
Gong Jun237c8d22009-03-30 21:46:42 +020066 "w83667hg",
Guenter Roeckc39aeda2010-08-14 21:08:55 +020067 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020068};
69
Jean Delvare67b671b2007-12-06 23:13:42 +010070static unsigned short force_id;
71module_param(force_id, ushort, 0);
72MODULE_PARM_DESC(force_id, "Override the detected device ID");
73
David Hubbard1ea6dd32007-06-24 11:16:15 +020074#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020075
76/*
77 * Super-I/O constants and functions
78 */
79
Jean Delvare08e7e272005-04-25 22:43:25 +020080#define W83627EHF_LD_HWM 0x0b
Gong Jun237c8d22009-03-30 21:46:42 +020081#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020082
83#define SIO_REG_LDSEL 0x07 /* Logical device select */
84#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020085#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020086#define SIO_REG_ENABLE 0x30 /* Logical device enable */
87#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020088#define SIO_REG_VID_CTRL 0xF0 /* VID control */
89#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020090
David Hubbard657c93b2007-02-14 21:15:04 +010091#define SIO_W83627EHF_ID 0x8850
92#define SIO_W83627EHG_ID 0x8860
93#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +020094#define SIO_W83627DHG_P_ID 0xb070
Gong Jun237c8d22009-03-30 21:46:42 +020095#define SIO_W83667HG_ID 0xa510
Guenter Roeckc39aeda2010-08-14 21:08:55 +020096#define SIO_W83667HG_B_ID 0xb350
David Hubbard657c93b2007-02-14 21:15:04 +010097#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +020098
99static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200100superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +0200101{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102 outb(reg, ioreg);
103 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200104}
105
106static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200107superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200108{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109 outb(reg, ioreg);
110 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200111}
112
113static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200114superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200115{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116 outb(SIO_REG_LDSEL, ioreg);
117 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200118}
119
120static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200121superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200122{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200123 outb(0x87, ioreg);
124 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200125}
126
127static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200128superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200129{
Jonas Jonsson022b75a2010-09-17 17:24:13 +0200130 outb(0xaa, ioreg);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200131 outb(0x02, ioreg);
132 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200133}
134
135/*
136 * ISA constants
137 */
138
Jean Delvare1a641fc2007-04-23 14:41:16 -0700139#define IOREGION_ALIGNMENT ~7
140#define IOREGION_OFFSET 5
141#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200142#define ADDR_REG_OFFSET 0
143#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200144
145#define W83627EHF_REG_BANK 0x4E
146#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100147
148/* Not currently used:
149 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
150 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
151 * REG_MAN_ID is at port 0x4f
152 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200153
154static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
155static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
156
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100157/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
158#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
159 (0x554 + (((nr) - 7) * 2)))
160#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
161 (0x555 + (((nr) - 7) * 2)))
162#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
163 (0x550 + (nr) - 7))
164
Jean Delvare08e7e272005-04-25 22:43:25 +0200165#define W83627EHF_REG_TEMP1 0x27
166#define W83627EHF_REG_TEMP1_HYST 0x3a
167#define W83627EHF_REG_TEMP1_OVER 0x39
168static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
169static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
170static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
171static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
172
173/* Fan clock dividers are spread over the following five registers */
174#define W83627EHF_REG_FANDIV1 0x47
175#define W83627EHF_REG_FANDIV2 0x4B
176#define W83627EHF_REG_VBAT 0x5D
177#define W83627EHF_REG_DIODE 0x59
178#define W83627EHF_REG_SMI_OVT 0x4C
179
Jean Delvarea4589db2006-03-23 16:30:29 +0100180#define W83627EHF_REG_ALARM1 0x459
181#define W83627EHF_REG_ALARM2 0x45A
182#define W83627EHF_REG_ALARM3 0x45B
183
Rudolf Marek08c79952006-07-05 18:14:31 +0200184/* SmartFan registers */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800185#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
186#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
187
Rudolf Marek08c79952006-07-05 18:14:31 +0200188/* DC or PWM output fan configuration */
189static const u8 W83627EHF_REG_PWM_ENABLE[] = {
190 0x04, /* SYS FAN0 output mode and PWM mode */
191 0x04, /* CPU FAN0 output mode and PWM mode */
192 0x12, /* AUX FAN mode */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800193 0x62, /* CPU FAN1 mode */
Rudolf Marek08c79952006-07-05 18:14:31 +0200194};
195
196static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
197static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
198
199/* FAN Duty Cycle, be used to control */
200static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
201static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
202static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
203
Rudolf Marek08c79952006-07-05 18:14:31 +0200204/* Advanced Fan control, some values are common for all fans */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800205static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
206static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
207static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200208
209static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
210 = { 0xff, 0x67, 0xff, 0x69 };
211static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
212 = { 0xff, 0x68, 0xff, 0x6a };
213
214static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
215static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
Rudolf Marek08c79952006-07-05 18:14:31 +0200216
Jean Delvare08e7e272005-04-25 22:43:25 +0200217/*
218 * Conversions
219 */
220
Rudolf Marek08c79952006-07-05 18:14:31 +0200221/* 1 is PWM mode, output in ms */
222static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
223{
224 return mode ? 100 * reg : 400 * reg;
225}
226
227static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
228{
229 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
230 (msec + 200) / 400), 1, 255);
231}
232
Jean Delvare08e7e272005-04-25 22:43:25 +0200233static inline unsigned int
234fan_from_reg(u8 reg, unsigned int div)
235{
236 if (reg == 0 || reg == 255)
237 return 0;
238 return 1350000U / (reg * div);
239}
240
241static inline unsigned int
242div_from_reg(u8 reg)
243{
244 return 1 << reg;
245}
246
247static inline int
248temp1_from_reg(s8 reg)
249{
250 return reg * 1000;
251}
252
253static inline s8
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200254temp1_to_reg(long temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200255{
Rudolf Marek08c79952006-07-05 18:14:31 +0200256 if (temp <= min)
257 return min / 1000;
258 if (temp >= max)
259 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200260 if (temp < 0)
261 return (temp - 500) / 1000;
262 return (temp + 500) / 1000;
263}
264
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100265/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
266
267static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
268
269static inline long in_from_reg(u8 reg, u8 nr)
270{
271 return reg * scale_in[nr];
272}
273
274static inline u8 in_to_reg(u32 val, u8 nr)
275{
276 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
277}
278
Jean Delvare08e7e272005-04-25 22:43:25 +0200279/*
280 * Data structures and manipulation thereof
281 */
282
283struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200284 int addr; /* IO base of hw monitor block */
285 const char *name;
286
Tony Jones1beeffe2007-08-20 13:46:20 -0700287 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100288 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200289
Guenter Roeckda2e0252010-08-14 21:08:55 +0200290 const u8 *REG_FAN_START_OUTPUT;
291 const u8 *REG_FAN_STOP_OUTPUT;
292 const u8 *REG_FAN_MAX_OUTPUT;
293 const u8 *REG_FAN_STEP_OUTPUT;
294
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100295 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200296 char valid; /* !=0 if following fields are valid */
297 unsigned long last_updated; /* In jiffies */
298
299 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200300 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100301 u8 in[10]; /* Register value */
302 u8 in_max[10]; /* Register value */
303 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200304 u8 fan[5];
305 u8 fan_min[5];
306 u8 fan_div[5];
307 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200308 u8 temp_type[3];
Jean Delvare08e7e272005-04-25 22:43:25 +0200309 s8 temp1;
310 s8 temp1_max;
311 s8 temp1_max_hyst;
312 s16 temp[2];
313 s16 temp_max[2];
314 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100315 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200316
317 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
318 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800319 2->thermal cruise mode (also called SmartFan I)
320 3->fan speed cruise mode
321 4->variable thermal cruise (also called SmartFan III) */
Gong Jun237c8d22009-03-30 21:46:42 +0200322 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200323 u8 pwm[4];
324 u8 target_temp[4];
325 u8 tolerance[4];
326
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800327 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
328 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
329 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
330 u8 fan_max_output[4]; /* maximum fan speed */
331 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200332
333 u8 vid;
334 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200335
336 u8 temp3_disable;
337 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200338};
339
David Hubbard1ea6dd32007-06-24 11:16:15 +0200340struct w83627ehf_sio_data {
341 int sioreg;
342 enum kinds kind;
343};
344
Jean Delvare08e7e272005-04-25 22:43:25 +0200345static inline int is_word_sized(u16 reg)
346{
347 return (((reg & 0xff00) == 0x100
348 || (reg & 0xff00) == 0x200)
349 && ((reg & 0x00ff) == 0x50
350 || (reg & 0x00ff) == 0x53
351 || (reg & 0x00ff) == 0x55));
352}
353
Jean Delvare09568952007-08-11 13:57:05 +0200354/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200355static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200356{
Jean Delvare09568952007-08-11 13:57:05 +0200357 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200358 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
359 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200360 }
361}
362
Jean Delvare09568952007-08-11 13:57:05 +0200363/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200364static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200365{
366 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200367 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
368 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200369 }
370}
371
David Hubbard1ea6dd32007-06-24 11:16:15 +0200372static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200373{
Jean Delvare08e7e272005-04-25 22:43:25 +0200374 int res, word_sized = is_word_sized(reg);
375
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100376 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200377
David Hubbard1ea6dd32007-06-24 11:16:15 +0200378 w83627ehf_set_bank(data, reg);
379 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
380 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200381 if (word_sized) {
382 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200383 data->addr + ADDR_REG_OFFSET);
384 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200385 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200386 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200387
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100388 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200389
390 return res;
391}
392
David Hubbard1ea6dd32007-06-24 11:16:15 +0200393static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200394{
Jean Delvare08e7e272005-04-25 22:43:25 +0200395 int word_sized = is_word_sized(reg);
396
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100397 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200398
David Hubbard1ea6dd32007-06-24 11:16:15 +0200399 w83627ehf_set_bank(data, reg);
400 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200401 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200402 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200403 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200404 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200405 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200406 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
407 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200408
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100409 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200410 return 0;
411}
412
413/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200414static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200415{
Jean Delvare08e7e272005-04-25 22:43:25 +0200416 u8 reg;
417
418 switch (nr) {
419 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200420 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200421 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200422 /* fan5 input control bit is write only, compute the value */
423 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200424 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
425 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200426 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200427 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200428 break;
429 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200430 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200431 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200432 /* fan5 input control bit is write only, compute the value */
433 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200434 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
435 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200436 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200437 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200438 break;
439 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200440 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200441 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200442 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
443 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200444 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200445 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200446 break;
447 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200448 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200449 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200450 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
451 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200452 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200453 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200454 break;
455 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200456 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700457 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200458 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200459 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200460 break;
461 }
462}
463
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400464static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
465{
466 int i;
467
468 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
469 data->fan_div[0] = (i >> 4) & 0x03;
470 data->fan_div[1] = (i >> 6) & 0x03;
471 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
472 data->fan_div[2] = (i >> 6) & 0x03;
473 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
474 data->fan_div[0] |= (i >> 3) & 0x04;
475 data->fan_div[1] |= (i >> 4) & 0x04;
476 data->fan_div[2] |= (i >> 5) & 0x04;
477 if (data->has_fan & ((1 << 3) | (1 << 4))) {
478 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
479 data->fan_div[3] = i & 0x03;
480 data->fan_div[4] = ((i >> 2) & 0x03)
481 | ((i >> 5) & 0x04);
482 }
483 if (data->has_fan & (1 << 3)) {
484 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
485 data->fan_div[3] |= (i >> 5) & 0x04;
486 }
487}
488
Jean Delvare08e7e272005-04-25 22:43:25 +0200489static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
490{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200491 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200492 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200493 int i;
494
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100495 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200496
Jean Delvare6b3e4642007-06-24 11:19:01 +0200497 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200498 || !data->valid) {
499 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400500 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200501
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100502 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200503 for (i = 0; i < data->in_num; i++) {
504 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100505 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200506 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100507 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200508 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100509 W83627EHF_REG_IN_MAX(i));
510 }
511
Jean Delvare08e7e272005-04-25 22:43:25 +0200512 /* Measured fan speeds and limits */
513 for (i = 0; i < 5; i++) {
514 if (!(data->has_fan & (1 << i)))
515 continue;
516
David Hubbard1ea6dd32007-06-24 11:16:15 +0200517 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200518 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200519 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200520 W83627EHF_REG_FAN_MIN[i]);
521
522 /* If we failed to measure the fan speed and clock
523 divider can be increased, let's try that for next
524 time */
525 if (data->fan[i] == 0xff
526 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200527 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200528 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700529 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200530 div_from_reg(data->fan_div[i] + 1));
531 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200532 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200533 /* Preserve min limit if possible */
534 if (data->fan_min[i] >= 2
535 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200536 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200537 W83627EHF_REG_FAN_MIN[i],
538 (data->fan_min[i] /= 2));
539 }
540 }
541
Guenter Roeckda2e0252010-08-14 21:08:55 +0200542 for (i = 0; i < data->pwm_num; i++) {
543 if (!(data->has_fan & (1 << i)))
544 continue;
545
Jean Delvare77fa49d2009-01-07 16:37:35 +0100546 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200547 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200548 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200549 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200550 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200551 W83627EHF_REG_TOLERANCE[i]);
552 }
553 data->pwm_mode[i] =
554 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
555 ? 0 : 1;
556 data->pwm_enable[i] =
557 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
558 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200559 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200560 W83627EHF_REG_PWM[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800561 data->fan_start_output[i] = w83627ehf_read_value(data,
562 W83627EHF_REG_FAN_START_OUTPUT[i]);
563 data->fan_stop_output[i] = w83627ehf_read_value(data,
564 W83627EHF_REG_FAN_STOP_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200565 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200566 W83627EHF_REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200567
568 if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
569 data->fan_max_output[i] =
570 w83627ehf_read_value(data,
571 data->REG_FAN_MAX_OUTPUT[i]);
572
573 if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
574 data->fan_step_output[i] =
575 w83627ehf_read_value(data,
576 data->REG_FAN_STEP_OUTPUT[i]);
577
Rudolf Marek08c79952006-07-05 18:14:31 +0200578 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200579 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200580 W83627EHF_REG_TARGET[i]) &
581 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
582 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
583 & 0x0f;
584 }
585
Jean Delvare08e7e272005-04-25 22:43:25 +0200586 /* Measured temperatures and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200587 data->temp1 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200588 W83627EHF_REG_TEMP1);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200589 data->temp1_max = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200590 W83627EHF_REG_TEMP1_OVER);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200591 data->temp1_max_hyst = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200592 W83627EHF_REG_TEMP1_HYST);
593 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200594 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200595 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200596 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200597 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200598 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200599 W83627EHF_REG_TEMP_HYST[i]);
600 }
601
David Hubbard1ea6dd32007-06-24 11:16:15 +0200602 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100603 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200604 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100605 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200606 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100607 W83627EHF_REG_ALARM3) << 16);
608
Jean Delvare08e7e272005-04-25 22:43:25 +0200609 data->last_updated = jiffies;
610 data->valid = 1;
611 }
612
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100613 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200614 return data;
615}
616
617/*
618 * Sysfs callback functions
619 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100620#define show_in_reg(reg) \
621static ssize_t \
622show_##reg(struct device *dev, struct device_attribute *attr, \
623 char *buf) \
624{ \
625 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
626 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
627 int nr = sensor_attr->index; \
628 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
629}
630show_in_reg(in)
631show_in_reg(in_min)
632show_in_reg(in_max)
633
634#define store_in_reg(REG, reg) \
635static ssize_t \
636store_in_##reg (struct device *dev, struct device_attribute *attr, \
637 const char *buf, size_t count) \
638{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200639 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100640 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
641 int nr = sensor_attr->index; \
642 u32 val = simple_strtoul(buf, NULL, 10); \
643 \
644 mutex_lock(&data->update_lock); \
645 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200646 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100647 data->in_##reg[nr]); \
648 mutex_unlock(&data->update_lock); \
649 return count; \
650}
651
652store_in_reg(MIN, min)
653store_in_reg(MAX, max)
654
Jean Delvarea4589db2006-03-23 16:30:29 +0100655static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
656{
657 struct w83627ehf_data *data = w83627ehf_update_device(dev);
658 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
659 int nr = sensor_attr->index;
660 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
661}
662
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100663static struct sensor_device_attribute sda_in_input[] = {
664 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
665 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
666 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
667 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
668 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
669 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
670 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
671 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
672 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
673 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
674};
675
Jean Delvarea4589db2006-03-23 16:30:29 +0100676static struct sensor_device_attribute sda_in_alarm[] = {
677 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
678 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
679 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
680 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
681 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
682 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
683 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
684 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
685 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
686 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
687};
688
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100689static struct sensor_device_attribute sda_in_min[] = {
690 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
691 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
692 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
693 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
694 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
695 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
696 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
697 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
698 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
699 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
700};
701
702static struct sensor_device_attribute sda_in_max[] = {
703 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
704 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
705 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
706 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
707 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
708 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
709 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
710 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
711 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
712 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
713};
714
Jean Delvare08e7e272005-04-25 22:43:25 +0200715#define show_fan_reg(reg) \
716static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100717show_##reg(struct device *dev, struct device_attribute *attr, \
718 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200719{ \
720 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100721 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
722 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200723 return sprintf(buf, "%d\n", \
724 fan_from_reg(data->reg[nr], \
725 div_from_reg(data->fan_div[nr]))); \
726}
727show_fan_reg(fan);
728show_fan_reg(fan_min);
729
730static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100731show_fan_div(struct device *dev, struct device_attribute *attr,
732 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200733{
734 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100735 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
736 int nr = sensor_attr->index;
737 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200738}
739
740static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100741store_fan_min(struct device *dev, struct device_attribute *attr,
742 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200743{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200744 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100745 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
746 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200747 unsigned int val = simple_strtoul(buf, NULL, 10);
748 unsigned int reg;
749 u8 new_div;
750
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100751 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200752 if (!val) {
753 /* No min limit, alarm disabled */
754 data->fan_min[nr] = 255;
755 new_div = data->fan_div[nr]; /* No change */
756 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
757 } else if ((reg = 1350000U / val) >= 128 * 255) {
758 /* Speed below this value cannot possibly be represented,
759 even with the highest divider (128) */
760 data->fan_min[nr] = 254;
761 new_div = 7; /* 128 == (1 << 7) */
762 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
763 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
764 } else if (!reg) {
765 /* Speed above this value cannot possibly be represented,
766 even with the lowest divider (1) */
767 data->fan_min[nr] = 1;
768 new_div = 0; /* 1 == (1 << 0) */
769 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200770 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200771 } else {
772 /* Automatically pick the best divider, i.e. the one such
773 that the min limit will correspond to a register value
774 in the 96..192 range */
775 new_div = 0;
776 while (reg > 192 && new_div < 7) {
777 reg >>= 1;
778 new_div++;
779 }
780 data->fan_min[nr] = reg;
781 }
782
783 /* Write both the fan clock divider (if it changed) and the new
784 fan min (unconditionally) */
785 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200786 /* Preserve the fan speed reading */
787 if (data->fan[nr] != 0xff) {
788 if (new_div > data->fan_div[nr])
789 data->fan[nr] >>= new_div - data->fan_div[nr];
790 else if (data->fan[nr] & 0x80)
791 data->fan[nr] = 0xff;
792 else
793 data->fan[nr] <<= data->fan_div[nr] - new_div;
794 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200795
796 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
797 nr + 1, div_from_reg(data->fan_div[nr]),
798 div_from_reg(new_div));
799 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200800 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200801 /* Give the chip time to sample a new speed value */
802 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200803 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200804 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200805 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100806 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200807
808 return count;
809}
810
Yuan Mu412fec82006-02-05 23:24:16 +0100811static struct sensor_device_attribute sda_fan_input[] = {
812 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
813 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
814 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
815 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
816 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
817};
Jean Delvare08e7e272005-04-25 22:43:25 +0200818
Jean Delvarea4589db2006-03-23 16:30:29 +0100819static struct sensor_device_attribute sda_fan_alarm[] = {
820 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
821 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
822 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
823 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
824 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
825};
826
Yuan Mu412fec82006-02-05 23:24:16 +0100827static struct sensor_device_attribute sda_fan_min[] = {
828 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
829 store_fan_min, 0),
830 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
831 store_fan_min, 1),
832 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
833 store_fan_min, 2),
834 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
835 store_fan_min, 3),
836 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
837 store_fan_min, 4),
838};
Jean Delvare08e7e272005-04-25 22:43:25 +0200839
Yuan Mu412fec82006-02-05 23:24:16 +0100840static struct sensor_device_attribute sda_fan_div[] = {
841 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
842 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
843 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
844 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
845 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
846};
Jean Delvare08e7e272005-04-25 22:43:25 +0200847
Jean Delvare08e7e272005-04-25 22:43:25 +0200848#define show_temp1_reg(reg) \
849static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700850show_##reg(struct device *dev, struct device_attribute *attr, \
851 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200852{ \
853 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
854 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
855}
856show_temp1_reg(temp1);
857show_temp1_reg(temp1_max);
858show_temp1_reg(temp1_max_hyst);
859
860#define store_temp1_reg(REG, reg) \
861static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700862store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
863 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200864{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200865 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200866 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200867 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100868 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200869 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200870 w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
Jean Delvare08e7e272005-04-25 22:43:25 +0200871 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100872 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200873 return count; \
874}
875store_temp1_reg(OVER, max);
876store_temp1_reg(HYST, max_hyst);
877
Jean Delvare08e7e272005-04-25 22:43:25 +0200878#define show_temp_reg(reg) \
879static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100880show_##reg(struct device *dev, struct device_attribute *attr, \
881 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200882{ \
883 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100884 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
885 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200886 return sprintf(buf, "%d\n", \
887 LM75_TEMP_FROM_REG(data->reg[nr])); \
888}
889show_temp_reg(temp);
890show_temp_reg(temp_max);
891show_temp_reg(temp_max_hyst);
892
893#define store_temp_reg(REG, reg) \
894static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100895store_##reg(struct device *dev, struct device_attribute *attr, \
896 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200897{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200898 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100899 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
900 int nr = sensor_attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200901 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200902 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100903 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200904 data->reg[nr] = LM75_TEMP_TO_REG(val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200905 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200906 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100907 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200908 return count; \
909}
910store_temp_reg(OVER, temp_max);
911store_temp_reg(HYST, temp_max_hyst);
912
Jean Delvareda667362007-06-24 11:21:02 +0200913static ssize_t
914show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
915{
916 struct w83627ehf_data *data = w83627ehf_update_device(dev);
917 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
918 int nr = sensor_attr->index;
919 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
920}
921
Gong Juna157d062009-03-30 21:46:43 +0200922static struct sensor_device_attribute sda_temp_input[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100923 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
924 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
925 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
Gong Juna157d062009-03-30 21:46:43 +0200926};
927
928static struct sensor_device_attribute sda_temp_max[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100929 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
930 store_temp1_max, 0),
931 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
932 store_temp_max, 0),
933 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
934 store_temp_max, 1),
Gong Juna157d062009-03-30 21:46:43 +0200935};
936
937static struct sensor_device_attribute sda_temp_max_hyst[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100938 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
939 store_temp1_max_hyst, 0),
940 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
941 store_temp_max_hyst, 0),
942 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
943 store_temp_max_hyst, 1),
Gong Juna157d062009-03-30 21:46:43 +0200944};
945
946static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100947 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
948 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
949 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200950};
951
952static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200953 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
954 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
955 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100956};
Jean Delvare08e7e272005-04-25 22:43:25 +0200957
Rudolf Marek08c79952006-07-05 18:14:31 +0200958#define show_pwm_reg(reg) \
959static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
960 char *buf) \
961{ \
962 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
963 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
964 int nr = sensor_attr->index; \
965 return sprintf(buf, "%d\n", data->reg[nr]); \
966}
967
968show_pwm_reg(pwm_mode)
969show_pwm_reg(pwm_enable)
970show_pwm_reg(pwm)
971
972static ssize_t
973store_pwm_mode(struct device *dev, struct device_attribute *attr,
974 const char *buf, size_t count)
975{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200976 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200977 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
978 int nr = sensor_attr->index;
979 u32 val = simple_strtoul(buf, NULL, 10);
980 u16 reg;
981
982 if (val > 1)
983 return -EINVAL;
984 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200985 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200986 data->pwm_mode[nr] = val;
987 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
988 if (!val)
989 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200990 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200991 mutex_unlock(&data->update_lock);
992 return count;
993}
994
995static ssize_t
996store_pwm(struct device *dev, struct device_attribute *attr,
997 const char *buf, size_t count)
998{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200999 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001000 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1001 int nr = sensor_attr->index;
1002 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
1003
1004 mutex_lock(&data->update_lock);
1005 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001006 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001007 mutex_unlock(&data->update_lock);
1008 return count;
1009}
1010
1011static ssize_t
1012store_pwm_enable(struct device *dev, struct device_attribute *attr,
1013 const char *buf, size_t count)
1014{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001015 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001016 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1017 int nr = sensor_attr->index;
1018 u32 val = simple_strtoul(buf, NULL, 10);
1019 u16 reg;
1020
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001021 if (!val || (val > 4))
Rudolf Marek08c79952006-07-05 18:14:31 +02001022 return -EINVAL;
1023 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001024 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001025 data->pwm_enable[nr] = val;
1026 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1027 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001028 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001029 mutex_unlock(&data->update_lock);
1030 return count;
1031}
1032
1033
1034#define show_tol_temp(reg) \
1035static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1036 char *buf) \
1037{ \
1038 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1039 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1040 int nr = sensor_attr->index; \
1041 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
1042}
1043
1044show_tol_temp(tolerance)
1045show_tol_temp(target_temp)
1046
1047static ssize_t
1048store_target_temp(struct device *dev, struct device_attribute *attr,
1049 const char *buf, size_t count)
1050{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001051 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001052 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1053 int nr = sensor_attr->index;
1054 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
1055
1056 mutex_lock(&data->update_lock);
1057 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001058 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001059 mutex_unlock(&data->update_lock);
1060 return count;
1061}
1062
1063static ssize_t
1064store_tolerance(struct device *dev, struct device_attribute *attr,
1065 const char *buf, size_t count)
1066{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001067 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001068 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1069 int nr = sensor_attr->index;
1070 u16 reg;
1071 /* Limit the temp to 0C - 15C */
1072 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
1073
1074 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001075 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001076 data->tolerance[nr] = val;
1077 if (nr == 1)
1078 reg = (reg & 0x0f) | (val << 4);
1079 else
1080 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001081 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001082 mutex_unlock(&data->update_lock);
1083 return count;
1084}
1085
1086static struct sensor_device_attribute sda_pwm[] = {
1087 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1088 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1089 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1090 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1091};
1092
1093static struct sensor_device_attribute sda_pwm_mode[] = {
1094 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1095 store_pwm_mode, 0),
1096 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1097 store_pwm_mode, 1),
1098 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1099 store_pwm_mode, 2),
1100 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1101 store_pwm_mode, 3),
1102};
1103
1104static struct sensor_device_attribute sda_pwm_enable[] = {
1105 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1106 store_pwm_enable, 0),
1107 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1108 store_pwm_enable, 1),
1109 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1110 store_pwm_enable, 2),
1111 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1112 store_pwm_enable, 3),
1113};
1114
1115static struct sensor_device_attribute sda_target_temp[] = {
1116 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1117 store_target_temp, 0),
1118 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1119 store_target_temp, 1),
1120 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1121 store_target_temp, 2),
1122 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1123 store_target_temp, 3),
1124};
1125
1126static struct sensor_device_attribute sda_tolerance[] = {
1127 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1128 store_tolerance, 0),
1129 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1130 store_tolerance, 1),
1131 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1132 store_tolerance, 2),
1133 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1134 store_tolerance, 3),
1135};
1136
Rudolf Marek08c79952006-07-05 18:14:31 +02001137/* Smart Fan registers */
1138
1139#define fan_functions(reg, REG) \
1140static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1141 char *buf) \
1142{ \
1143 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1144 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1145 int nr = sensor_attr->index; \
1146 return sprintf(buf, "%d\n", data->reg[nr]); \
1147}\
1148static ssize_t \
1149store_##reg(struct device *dev, struct device_attribute *attr, \
1150 const char *buf, size_t count) \
1151{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001152 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001153 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1154 int nr = sensor_attr->index; \
1155 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1156 mutex_lock(&data->update_lock); \
1157 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001158 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001159 mutex_unlock(&data->update_lock); \
1160 return count; \
1161}
1162
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001163fan_functions(fan_start_output, FAN_START_OUTPUT)
1164fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1165fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1166fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001167
1168#define fan_time_functions(reg, REG) \
1169static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1170 char *buf) \
1171{ \
1172 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1173 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1174 int nr = sensor_attr->index; \
1175 return sprintf(buf, "%d\n", \
1176 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1177} \
1178\
1179static ssize_t \
1180store_##reg(struct device *dev, struct device_attribute *attr, \
1181 const char *buf, size_t count) \
1182{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001183 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001184 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1185 int nr = sensor_attr->index; \
1186 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1187 data->pwm_mode[nr]); \
1188 mutex_lock(&data->update_lock); \
1189 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001190 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001191 mutex_unlock(&data->update_lock); \
1192 return count; \
1193} \
1194
1195fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1196
David Hubbard1ea6dd32007-06-24 11:16:15 +02001197static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1198 char *buf)
1199{
1200 struct w83627ehf_data *data = dev_get_drvdata(dev);
1201
1202 return sprintf(buf, "%s\n", data->name);
1203}
1204static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001205
1206static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1207 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1208 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001209 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1210 store_fan_start_output, 3),
1211 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1212 store_fan_stop_output, 3),
1213 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1214 store_fan_max_output, 3),
1215 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1216 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001217};
1218
1219static struct sensor_device_attribute sda_sf3_arrays[] = {
1220 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1221 store_fan_stop_time, 0),
1222 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1223 store_fan_stop_time, 1),
1224 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1225 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001226 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1227 store_fan_start_output, 0),
1228 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1229 store_fan_start_output, 1),
1230 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1231 store_fan_start_output, 2),
1232 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1233 store_fan_stop_output, 0),
1234 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1235 store_fan_stop_output, 1),
1236 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1237 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001238};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001239
Guenter Roeckda2e0252010-08-14 21:08:55 +02001240
1241/*
1242 * pwm1 and pwm3 don't support max and step settings on all chips.
1243 * Need to check support while generating/removing attribute files.
1244 */
1245static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1246 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1247 store_fan_max_output, 0),
1248 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1249 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001250 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1251 store_fan_max_output, 1),
1252 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1253 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001254 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1255 store_fan_max_output, 2),
1256 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1257 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001258};
1259
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001260static ssize_t
1261show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1262{
1263 struct w83627ehf_data *data = dev_get_drvdata(dev);
1264 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1265}
1266static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1267
Jean Delvare08e7e272005-04-25 22:43:25 +02001268/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001269 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001270 */
1271
David Hubbardc18beb52006-09-24 21:04:38 +02001272static void w83627ehf_device_remove_files(struct device *dev)
1273{
1274 /* some entries in the following arrays may not have been used in
1275 * device_create_file(), but device_remove_file() will ignore them */
1276 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001277 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001278
1279 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1280 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001281 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1282 struct sensor_device_attribute *attr =
1283 &sda_sf3_max_step_arrays[i];
1284 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1285 device_remove_file(dev, &attr->dev_attr);
1286 }
David Hubbardc18beb52006-09-24 21:04:38 +02001287 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1288 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001289 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001290 if ((i == 6) && data->in6_skip)
1291 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001292 device_remove_file(dev, &sda_in_input[i].dev_attr);
1293 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1294 device_remove_file(dev, &sda_in_min[i].dev_attr);
1295 device_remove_file(dev, &sda_in_max[i].dev_attr);
1296 }
1297 for (i = 0; i < 5; i++) {
1298 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1299 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1300 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1301 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1302 }
Gong Jun237c8d22009-03-30 21:46:42 +02001303 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001304 device_remove_file(dev, &sda_pwm[i].dev_attr);
1305 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1306 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1307 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1308 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1309 }
Gong Juna157d062009-03-30 21:46:43 +02001310 for (i = 0; i < 3; i++) {
1311 if ((i == 2) && data->temp3_disable)
1312 continue;
1313 device_remove_file(dev, &sda_temp_input[i].dev_attr);
1314 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1315 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1316 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1317 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1318 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001319
1320 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001321 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001322}
1323
David Hubbard1ea6dd32007-06-24 11:16:15 +02001324/* Get the monitoring functions started */
1325static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001326{
1327 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001328 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001329
1330 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001331 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001332 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001333 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001334 tmp | 0x01);
1335
1336 /* Enable temp2 and temp3 if needed */
1337 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001338 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001339 W83627EHF_REG_TEMP_CONFIG[i]);
Gong Juna157d062009-03-30 21:46:43 +02001340 if ((i == 1) && data->temp3_disable)
1341 continue;
Jean Delvare08e7e272005-04-25 22:43:25 +02001342 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001343 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001344 W83627EHF_REG_TEMP_CONFIG[i],
1345 tmp & 0xfe);
1346 }
Jean Delvared3130f02007-06-24 11:20:13 +02001347
1348 /* Enable VBAT monitoring if needed */
1349 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1350 if (!(tmp & 0x01))
1351 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001352
1353 /* Get thermal sensor types */
1354 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1355 for (i = 0; i < 3; i++) {
1356 if ((tmp & (0x02 << i)))
1357 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1358 else
1359 data->temp_type[i] = 4; /* thermistor */
1360 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001361}
1362
David Hubbard1ea6dd32007-06-24 11:16:15 +02001363static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001364{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001365 struct device *dev = &pdev->dev;
1366 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001367 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001368 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001369 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001370 int i, err = 0;
1371
David Hubbard1ea6dd32007-06-24 11:16:15 +02001372 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1373 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001374 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001375 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1376 (unsigned long)res->start,
1377 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001378 goto exit;
1379 }
1380
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001381 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001382 err = -ENOMEM;
1383 goto exit_release;
1384 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001385
David Hubbard1ea6dd32007-06-24 11:16:15 +02001386 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001387 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001388 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001389 data->name = w83627ehf_device_names[sio_data->kind];
1390 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001391
Gong Jun237c8d22009-03-30 21:46:42 +02001392 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1393 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1394 /* 667HG has 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001395 data->pwm_num = (sio_data->kind == w83667hg
1396 || sio_data->kind == w83667hg_b) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001397
Gong Juna157d062009-03-30 21:46:43 +02001398 /* Check temp3 configuration bit for 667HG */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001399 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Juna157d062009-03-30 21:46:43 +02001400 data->temp3_disable = w83627ehf_read_value(data,
1401 W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
1402 data->in6_skip = !data->temp3_disable;
1403 }
1404
Guenter Roeckda2e0252010-08-14 21:08:55 +02001405 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1406 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001407 if (sio_data->kind == w83667hg_b) {
1408 data->REG_FAN_MAX_OUTPUT =
1409 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1410 data->REG_FAN_STEP_OUTPUT =
1411 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1412 } else {
1413 data->REG_FAN_MAX_OUTPUT =
1414 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1415 data->REG_FAN_STEP_OUTPUT =
1416 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1417 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001418
Jean Delvare08e7e272005-04-25 22:43:25 +02001419 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001420 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001421
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001422 data->vrm = vid_which_vrm();
1423 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001424 /* Read VID value */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001425 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d22009-03-30 21:46:42 +02001426 /* W83667HG has different pins for VID input and output, so
1427 we can get the VID input values directly at logical device D
1428 0xe3. */
1429 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1430 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001431 err = device_create_file(dev, &dev_attr_cpu0_vid);
1432 if (err)
1433 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001434 } else {
Gong Jun237c8d22009-03-30 21:46:42 +02001435 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1436 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1437 /* Set VID input sensibility if needed. In theory the
1438 BIOS should have set it, but in practice it's not
1439 always the case. We only do it for the W83627EHF/EHG
1440 because the W83627DHG is more complex in this
1441 respect. */
1442 if (sio_data->kind == w83627ehf) {
1443 en_vrm10 = superio_inb(sio_data->sioreg,
1444 SIO_REG_EN_VRM10);
1445 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1446 dev_warn(dev, "Setting VID input "
1447 "voltage to TTL\n");
1448 superio_outb(sio_data->sioreg,
1449 SIO_REG_EN_VRM10,
1450 en_vrm10 & ~0x08);
1451 } else if (!(en_vrm10 & 0x08)
1452 && data->vrm == 100) {
1453 dev_warn(dev, "Setting VID input "
1454 "voltage to VRM10\n");
1455 superio_outb(sio_data->sioreg,
1456 SIO_REG_EN_VRM10,
1457 en_vrm10 | 0x08);
1458 }
1459 }
1460
1461 data->vid = superio_inb(sio_data->sioreg,
1462 SIO_REG_VID_DATA);
1463 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1464 data->vid &= 0x3f;
1465
1466 err = device_create_file(dev, &dev_attr_cpu0_vid);
1467 if (err)
1468 goto exit_release;
1469 } else {
1470 dev_info(dev, "VID pins in output mode, CPU VID not "
1471 "available\n");
1472 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001473 }
1474
Rudolf Marek08c79952006-07-05 18:14:31 +02001475 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001476 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d22009-03-30 21:46:42 +02001477 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1478 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1479 } else {
1480 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1481 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1482 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001483 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001484
Jean Delvare08e7e272005-04-25 22:43:25 +02001485 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001486 as fan on/off switches, but fan5 control is write only :/
1487 We assume that if the serial interface is disabled, designers
1488 connected fan5 as input unless they are emitting log 1, which
1489 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001490
Jean Delvare08e7e272005-04-25 22:43:25 +02001491 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001492 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001493 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001494 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001495 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001496 data->has_fan |= (1 << 4);
1497
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001498 /* Read fan clock dividers immediately */
1499 w83627ehf_update_fan_div(data);
1500
Jean Delvare08e7e272005-04-25 22:43:25 +02001501 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001502 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001503 if ((err = device_create_file(dev,
1504 &sda_sf3_arrays[i].dev_attr)))
1505 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001506
Guenter Roeckda2e0252010-08-14 21:08:55 +02001507 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1508 struct sensor_device_attribute *attr =
1509 &sda_sf3_max_step_arrays[i];
1510 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
1511 err = device_create_file(dev, &attr->dev_attr);
1512 if (err)
1513 goto exit_remove;
1514 }
1515 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001516 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d22009-03-30 21:46:42 +02001517 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001518 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1519 if ((err = device_create_file(dev,
1520 &sda_sf3_arrays_fan4[i].dev_attr)))
1521 goto exit_remove;
1522 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001523
Gong Juna157d062009-03-30 21:46:43 +02001524 for (i = 0; i < data->in_num; i++) {
1525 if ((i == 6) && data->in6_skip)
1526 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001527 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1528 || (err = device_create_file(dev,
1529 &sda_in_alarm[i].dev_attr))
1530 || (err = device_create_file(dev,
1531 &sda_in_min[i].dev_attr))
1532 || (err = device_create_file(dev,
1533 &sda_in_max[i].dev_attr)))
1534 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001535 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001536
Yuan Mu412fec82006-02-05 23:24:16 +01001537 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001538 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001539 if ((err = device_create_file(dev,
1540 &sda_fan_input[i].dev_attr))
1541 || (err = device_create_file(dev,
1542 &sda_fan_alarm[i].dev_attr))
1543 || (err = device_create_file(dev,
1544 &sda_fan_div[i].dev_attr))
1545 || (err = device_create_file(dev,
1546 &sda_fan_min[i].dev_attr)))
1547 goto exit_remove;
Gong Jun237c8d22009-03-30 21:46:42 +02001548 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001549 ((err = device_create_file(dev,
1550 &sda_pwm[i].dev_attr))
1551 || (err = device_create_file(dev,
1552 &sda_pwm_mode[i].dev_attr))
1553 || (err = device_create_file(dev,
1554 &sda_pwm_enable[i].dev_attr))
1555 || (err = device_create_file(dev,
1556 &sda_target_temp[i].dev_attr))
1557 || (err = device_create_file(dev,
1558 &sda_tolerance[i].dev_attr))))
1559 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001560 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001561 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001562
Gong Juna157d062009-03-30 21:46:43 +02001563 for (i = 0; i < 3; i++) {
1564 if ((i == 2) && data->temp3_disable)
1565 continue;
1566 if ((err = device_create_file(dev,
1567 &sda_temp_input[i].dev_attr))
1568 || (err = device_create_file(dev,
1569 &sda_temp_max[i].dev_attr))
1570 || (err = device_create_file(dev,
1571 &sda_temp_max_hyst[i].dev_attr))
1572 || (err = device_create_file(dev,
1573 &sda_temp_alarm[i].dev_attr))
1574 || (err = device_create_file(dev,
1575 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001576 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001577 }
David Hubbardc18beb52006-09-24 21:04:38 +02001578
David Hubbard1ea6dd32007-06-24 11:16:15 +02001579 err = device_create_file(dev, &dev_attr_name);
1580 if (err)
1581 goto exit_remove;
1582
Tony Jones1beeffe2007-08-20 13:46:20 -07001583 data->hwmon_dev = hwmon_device_register(dev);
1584 if (IS_ERR(data->hwmon_dev)) {
1585 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001586 goto exit_remove;
1587 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001588
1589 return 0;
1590
David Hubbardc18beb52006-09-24 21:04:38 +02001591exit_remove:
1592 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001593 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001594 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001595exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001596 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001597exit:
1598 return err;
1599}
1600
David Hubbard1ea6dd32007-06-24 11:16:15 +02001601static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001602{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001603 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001604
Tony Jones1beeffe2007-08-20 13:46:20 -07001605 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001606 w83627ehf_device_remove_files(&pdev->dev);
1607 release_region(data->addr, IOREGION_LENGTH);
1608 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001609 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001610
1611 return 0;
1612}
1613
David Hubbard1ea6dd32007-06-24 11:16:15 +02001614static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001615 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001616 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001617 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001618 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001619 .probe = w83627ehf_probe,
1620 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001621};
1622
David Hubbard1ea6dd32007-06-24 11:16:15 +02001623/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1624static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1625 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001626{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001627 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1628 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1629 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001630 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d22009-03-30 21:46:42 +02001631 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001632 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001633
Jean Delvare08e7e272005-04-25 22:43:25 +02001634 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001635 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001636
David Hubbard1ea6dd32007-06-24 11:16:15 +02001637 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001638
Jean Delvare67b671b2007-12-06 23:13:42 +01001639 if (force_id)
1640 val = force_id;
1641 else
1642 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1643 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001644 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001645 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001646 sio_data->kind = w83627ehf;
1647 sio_name = sio_name_W83627EHF;
1648 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001649 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001650 sio_data->kind = w83627ehf;
1651 sio_name = sio_name_W83627EHG;
1652 break;
1653 case SIO_W83627DHG_ID:
1654 sio_data->kind = w83627dhg;
1655 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001656 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001657 case SIO_W83627DHG_P_ID:
1658 sio_data->kind = w83627dhg_p;
1659 sio_name = sio_name_W83627DHG_P;
1660 break;
Gong Jun237c8d22009-03-30 21:46:42 +02001661 case SIO_W83667HG_ID:
1662 sio_data->kind = w83667hg;
1663 sio_name = sio_name_W83667HG;
1664 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001665 case SIO_W83667HG_B_ID:
1666 sio_data->kind = w83667hg_b;
1667 sio_name = sio_name_W83667HG_B;
1668 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001669 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001670 if (val != 0xffff)
1671 pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
1672 val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001673 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001674 return -ENODEV;
1675 }
1676
David Hubbard1ea6dd32007-06-24 11:16:15 +02001677 /* We have a known chip, find the HWM I/O address */
1678 superio_select(sioaddr, W83627EHF_LD_HWM);
1679 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1680 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001681 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001682 if (*addr == 0) {
David Hubbard475ef852007-06-24 11:17:09 +02001683 printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
1684 "device with a base I/O port 0.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001685 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001686 return -ENODEV;
1687 }
1688
1689 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001690 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001691 if (!(val & 0x01)) {
1692 printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
1693 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001694 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001695 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001696
David Hubbard1ea6dd32007-06-24 11:16:15 +02001697 superio_exit(sioaddr);
1698 pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
1699 sio_data->sioreg = sioaddr;
1700
Jean Delvare08e7e272005-04-25 22:43:25 +02001701 return 0;
1702}
1703
David Hubbard1ea6dd32007-06-24 11:16:15 +02001704/* when Super-I/O functions move to a separate file, the Super-I/O
1705 * bus will manage the lifetime of the device and this module will only keep
1706 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1707 * must keep track of the device */
1708static struct platform_device *pdev;
1709
Jean Delvare08e7e272005-04-25 22:43:25 +02001710static int __init sensors_w83627ehf_init(void)
1711{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001712 int err;
1713 unsigned short address;
1714 struct resource res;
1715 struct w83627ehf_sio_data sio_data;
1716
1717 /* initialize sio_data->kind and sio_data->sioreg.
1718 *
1719 * when Super-I/O functions move to a separate file, the Super-I/O
1720 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1721 * w83627ehf hardware monitor, and call probe() */
1722 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1723 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001724 return -ENODEV;
1725
David Hubbard1ea6dd32007-06-24 11:16:15 +02001726 err = platform_driver_register(&w83627ehf_driver);
1727 if (err)
1728 goto exit;
1729
1730 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1731 err = -ENOMEM;
1732 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1733 goto exit_unregister;
1734 }
1735
1736 err = platform_device_add_data(pdev, &sio_data,
1737 sizeof(struct w83627ehf_sio_data));
1738 if (err) {
1739 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1740 goto exit_device_put;
1741 }
1742
1743 memset(&res, 0, sizeof(res));
1744 res.name = DRVNAME;
1745 res.start = address + IOREGION_OFFSET;
1746 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1747 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001748
1749 err = acpi_check_resource_conflict(&res);
1750 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001751 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001752
David Hubbard1ea6dd32007-06-24 11:16:15 +02001753 err = platform_device_add_resources(pdev, &res, 1);
1754 if (err) {
1755 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1756 "(%d)\n", err);
1757 goto exit_device_put;
1758 }
1759
1760 /* platform_device_add calls probe() */
1761 err = platform_device_add(pdev);
1762 if (err) {
1763 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1764 err);
1765 goto exit_device_put;
1766 }
1767
1768 return 0;
1769
1770exit_device_put:
1771 platform_device_put(pdev);
1772exit_unregister:
1773 platform_driver_unregister(&w83627ehf_driver);
1774exit:
1775 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001776}
1777
1778static void __exit sensors_w83627ehf_exit(void)
1779{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001780 platform_device_unregister(pdev);
1781 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001782}
1783
1784MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1785MODULE_DESCRIPTION("W83627EHF driver");
1786MODULE_LICENSE("GPL");
1787
1788module_init(sensors_w83627ehf_init);
1789module_exit(sensors_w83627ehf_exit);