blob: d10fe706c85621a773559b3b6a720f4de0df2474 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
Guenter Roecke7e1ca62011-02-04 13:24:30 -08003 the Winbond W83627EHF Super-I/O chip
Jean Delvare08e7e272005-04-25 22:43:25 +02004 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Guenter Roecke7e1ca62011-02-04 13:24:30 -08006 Rudolf Marek <r.marek@assembler.cz>
7 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
Guenter Roecke7e1ca62011-02-04 13:24:30 -080038 0x8860 0xa1
David Hubbard657c93b2007-02-14 21:15:04 +010039 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 Jun237c8d2f2009-03-30 21:46:42 +020041 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Guenter Roeckd36cf322011-02-07 15:08:54 -080042 w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020043*/
44
Joe Perchesabdc6fd2010-10-20 06:51:54 +000045#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
46
Jean Delvare08e7e272005-04-25 22:43:25 +020047#include <linux/module.h>
48#include <linux/init.h>
49#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020050#include <linux/jiffies.h>
51#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040052#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010053#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020054#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040055#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010056#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010057#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020058#include <linux/io.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020059#include "lm75.h"
60
Guenter Roeckc39aeda2010-08-14 21:08:55 +020061enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
David Hubbard1ea6dd32007-06-24 11:16:15 +020062
63/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
Guenter Roecke7e1ca62011-02-04 13:24:30 -080064static const char * const w83627ehf_device_names[] = {
David Hubbard1ea6dd32007-06-24 11:16:15 +020065 "w83627ehf",
66 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020067 "w83627dhg",
Gong Jun237c8d2f2009-03-30 21:46:42 +020068 "w83667hg",
Guenter Roeckc39aeda2010-08-14 21:08:55 +020069 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020070};
71
Jean Delvare67b671b2007-12-06 23:13:42 +010072static unsigned short force_id;
73module_param(force_id, ushort, 0);
74MODULE_PARM_DESC(force_id, "Override the detected device ID");
75
David Hubbard1ea6dd32007-06-24 11:16:15 +020076#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020077
78/*
79 * Super-I/O constants and functions
80 */
81
Jean Delvare08e7e272005-04-25 22:43:25 +020082#define W83627EHF_LD_HWM 0x0b
Guenter Roecke7e1ca62011-02-04 13:24:30 -080083#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020084
85#define SIO_REG_LDSEL 0x07 /* Logical device select */
86#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020087#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020088#define SIO_REG_ENABLE 0x30 /* Logical device enable */
89#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020090#define SIO_REG_VID_CTRL 0xF0 /* VID control */
91#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020092
David Hubbard657c93b2007-02-14 21:15:04 +010093#define SIO_W83627EHF_ID 0x8850
94#define SIO_W83627EHG_ID 0x8860
95#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +020096#define SIO_W83627DHG_P_ID 0xb070
Guenter Roecke7e1ca62011-02-04 13:24:30 -080097#define SIO_W83667HG_ID 0xa510
Guenter Roeckc39aeda2010-08-14 21:08:55 +020098#define SIO_W83667HG_B_ID 0xb350
David Hubbard657c93b2007-02-14 21:15:04 +010099#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +0200100
101static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +0200103{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200104 outb(reg, ioreg);
105 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200106}
107
108static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200110{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200111 outb(reg, ioreg);
112 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200113}
114
115static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200117{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200118 outb(SIO_REG_LDSEL, ioreg);
119 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200120}
121
122static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200123superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200124{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200125 outb(0x87, ioreg);
126 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200127}
128
129static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200130superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200131{
Jonas Jonsson022b75a2010-09-17 17:24:13 +0200132 outb(0xaa, ioreg);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200133 outb(0x02, ioreg);
134 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200135}
136
137/*
138 * ISA constants
139 */
140
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800141#define IOREGION_ALIGNMENT (~7)
Jean Delvare1a641fc2007-04-23 14:41:16 -0700142#define IOREGION_OFFSET 5
143#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200144#define ADDR_REG_OFFSET 0
145#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200146
147#define W83627EHF_REG_BANK 0x4E
148#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100149
150/* Not currently used:
151 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
152 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
153 * REG_MAN_ID is at port 0x4f
154 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200155
156static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
157static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
158
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100159/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
160#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
161 (0x554 + (((nr) - 7) * 2)))
162#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
163 (0x555 + (((nr) - 7) * 2)))
164#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
165 (0x550 + (nr) - 7))
166
Guenter Roeckd36cf322011-02-07 15:08:54 -0800167static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
168static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
169static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
170static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
Jean Delvare08e7e272005-04-25 22:43:25 +0200171
172/* Fan clock dividers are spread over the following five registers */
173#define W83627EHF_REG_FANDIV1 0x47
174#define W83627EHF_REG_FANDIV2 0x4B
175#define W83627EHF_REG_VBAT 0x5D
176#define W83627EHF_REG_DIODE 0x59
177#define W83627EHF_REG_SMI_OVT 0x4C
178
Jean Delvarea4589db2006-03-23 16:30:29 +0100179#define W83627EHF_REG_ALARM1 0x459
180#define W83627EHF_REG_ALARM2 0x45A
181#define W83627EHF_REG_ALARM3 0x45B
182
Rudolf Marek08c79952006-07-05 18:14:31 +0200183/* SmartFan registers */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800184#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
185#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
186
Rudolf Marek08c79952006-07-05 18:14:31 +0200187/* DC or PWM output fan configuration */
188static const u8 W83627EHF_REG_PWM_ENABLE[] = {
189 0x04, /* SYS FAN0 output mode and PWM mode */
190 0x04, /* CPU FAN0 output mode and PWM mode */
191 0x12, /* AUX FAN mode */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800192 0x62, /* CPU FAN1 mode */
Rudolf Marek08c79952006-07-05 18:14:31 +0200193};
194
195static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
196static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
197
198/* FAN Duty Cycle, be used to control */
199static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
200static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
201static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
202
Rudolf Marek08c79952006-07-05 18:14:31 +0200203/* Advanced Fan control, some values are common for all fans */
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800204static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
205static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
206static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
Guenter Roeckc39aeda2010-08-14 21:08:55 +0200207
208static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
209 = { 0xff, 0x67, 0xff, 0x69 };
210static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
211 = { 0xff, 0x68, 0xff, 0x6a };
212
213static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
214static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
Rudolf Marek08c79952006-07-05 18:14:31 +0200215
Guenter Roeckd36cf322011-02-07 15:08:54 -0800216static const char *const w83667hg_b_temp_label[] = {
217 "SYSTIN",
218 "CPUTIN",
219 "AUXTIN",
220 "AMDTSI",
221 "PECI Agent 1",
222 "PECI Agent 2",
223 "PECI Agent 3",
224 "PECI Agent 4"
225};
226
227#define NUM_REG_TEMP 4
228
Guenter Roeckbce26c52011-02-04 12:54:14 -0800229static inline int is_word_sized(u16 reg)
230{
231 return (((reg & 0xff00) == 0x100
232 || (reg & 0xff00) == 0x200)
233 && ((reg & 0x00ff) == 0x50
234 || (reg & 0x00ff) == 0x53
235 || (reg & 0x00ff) == 0x55));
236}
237
Jean Delvare08e7e272005-04-25 22:43:25 +0200238/*
239 * Conversions
240 */
241
Rudolf Marek08c79952006-07-05 18:14:31 +0200242/* 1 is PWM mode, output in ms */
243static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
244{
245 return mode ? 100 * reg : 400 * reg;
246}
247
248static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
249{
250 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
251 (msec + 200) / 400), 1, 255);
252}
253
Jean Delvare08e7e272005-04-25 22:43:25 +0200254static inline unsigned int
255fan_from_reg(u8 reg, unsigned int div)
256{
257 if (reg == 0 || reg == 255)
258 return 0;
259 return 1350000U / (reg * div);
260}
261
262static inline unsigned int
263div_from_reg(u8 reg)
264{
265 return 1 << reg;
266}
267
268static inline int
Guenter Roeckbce26c52011-02-04 12:54:14 -0800269temp_from_reg(u16 reg, s16 regval)
Jean Delvare08e7e272005-04-25 22:43:25 +0200270{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800271 if (is_word_sized(reg))
272 return LM75_TEMP_FROM_REG(regval);
273 return regval * 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200274}
275
Guenter Roeckbce26c52011-02-04 12:54:14 -0800276static inline s16
277temp_to_reg(u16 reg, long temp)
Jean Delvare08e7e272005-04-25 22:43:25 +0200278{
Guenter Roeckbce26c52011-02-04 12:54:14 -0800279 if (is_word_sized(reg))
280 return LM75_TEMP_TO_REG(temp);
281 return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
Jean Delvare08e7e272005-04-25 22:43:25 +0200282}
283
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100284/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
285
286static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
287
288static inline long in_from_reg(u8 reg, u8 nr)
289{
290 return reg * scale_in[nr];
291}
292
293static inline u8 in_to_reg(u32 val, u8 nr)
294{
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800295 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
296 255);
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100297}
298
Jean Delvare08e7e272005-04-25 22:43:25 +0200299/*
300 * Data structures and manipulation thereof
301 */
302
303struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200304 int addr; /* IO base of hw monitor block */
305 const char *name;
306
Tony Jones1beeffe2007-08-20 13:46:20 -0700307 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100308 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200309
Guenter Roeckd36cf322011-02-07 15:08:54 -0800310 u8 temp_src[NUM_REG_TEMP];
311 const char * const *temp_label;
312
Guenter Roeckda2e0252010-08-14 21:08:55 +0200313 const u8 *REG_FAN_START_OUTPUT;
314 const u8 *REG_FAN_STOP_OUTPUT;
315 const u8 *REG_FAN_MAX_OUTPUT;
316 const u8 *REG_FAN_STEP_OUTPUT;
317
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100318 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200319 char valid; /* !=0 if following fields are valid */
320 unsigned long last_updated; /* In jiffies */
321
322 /* Register values */
Guenter Roeck83cc8982011-02-06 08:10:15 -0800323 u8 bank; /* current register bank */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200324 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100325 u8 in[10]; /* Register value */
326 u8 in_max[10]; /* Register value */
327 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200328 u8 fan[5];
329 u8 fan_min[5];
330 u8 fan_div[5];
331 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200332 u8 temp_type[3];
Guenter Roeckd36cf322011-02-07 15:08:54 -0800333 s16 temp[4];
334 s16 temp_max[4];
335 s16 temp_max_hyst[4];
Jean Delvarea4589db2006-03-23 16:30:29 +0100336 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200337
338 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
339 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800340 2->thermal cruise mode (also called SmartFan I)
341 3->fan speed cruise mode
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800342 4->variable thermal cruise (also called
343 SmartFan III) */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200344 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200345 u8 pwm[4];
346 u8 target_temp[4];
347 u8 tolerance[4];
348
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800349 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
350 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
351 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
352 u8 fan_max_output[4]; /* maximum fan speed */
353 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200354
355 u8 vid;
356 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200357
Guenter Roeckd36cf322011-02-07 15:08:54 -0800358 u8 have_temp;
Gong Juna157d062009-03-30 21:46:43 +0200359 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200360};
361
David Hubbard1ea6dd32007-06-24 11:16:15 +0200362struct w83627ehf_sio_data {
363 int sioreg;
364 enum kinds kind;
365};
366
Guenter Roeck83cc8982011-02-06 08:10:15 -0800367/*
368 * On older chips, only registers 0x50-0x5f are banked.
369 * On more recent chips, all registers are banked.
370 * Assume that is the case and set the bank number for each access.
371 * Cache the bank number so it only needs to be set if it changes.
372 */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200373static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200374{
Guenter Roeck83cc8982011-02-06 08:10:15 -0800375 u8 bank = reg >> 8;
376 if (data->bank != bank) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200377 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
Guenter Roeck83cc8982011-02-06 08:10:15 -0800378 outb_p(bank, data->addr + DATA_REG_OFFSET);
379 data->bank = bank;
Jean Delvare08e7e272005-04-25 22:43:25 +0200380 }
381}
382
David Hubbard1ea6dd32007-06-24 11:16:15 +0200383static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200384{
Jean Delvare08e7e272005-04-25 22:43:25 +0200385 int res, word_sized = is_word_sized(reg);
386
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100387 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200388
David Hubbard1ea6dd32007-06-24 11:16:15 +0200389 w83627ehf_set_bank(data, reg);
390 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
391 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200392 if (word_sized) {
393 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200394 data->addr + ADDR_REG_OFFSET);
395 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200396 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200397
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100398 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200399 return res;
400}
401
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800402static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
403 u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200404{
Jean Delvare08e7e272005-04-25 22:43:25 +0200405 int word_sized = is_word_sized(reg);
406
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100407 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200408
David Hubbard1ea6dd32007-06-24 11:16:15 +0200409 w83627ehf_set_bank(data, reg);
410 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200411 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200412 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200413 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200414 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200415 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200416 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200417
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100418 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200419 return 0;
420}
421
422/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200423static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200424{
Jean Delvare08e7e272005-04-25 22:43:25 +0200425 u8 reg;
426
427 switch (nr) {
428 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200429 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200430 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200431 /* fan5 input control bit is write only, compute the value */
432 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200433 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
434 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200435 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200436 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200437 break;
438 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200439 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200440 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200441 /* fan5 input control bit is write only, compute the value */
442 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200443 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
444 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200445 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200446 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200447 break;
448 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200449 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200450 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200451 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
452 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200453 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200454 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200455 break;
456 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200457 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200458 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200459 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
460 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200461 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200462 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200463 break;
464 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200465 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700466 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200467 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200468 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200469 break;
470 }
471}
472
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400473static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
474{
475 int i;
476
477 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
478 data->fan_div[0] = (i >> 4) & 0x03;
479 data->fan_div[1] = (i >> 6) & 0x03;
480 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
481 data->fan_div[2] = (i >> 6) & 0x03;
482 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
483 data->fan_div[0] |= (i >> 3) & 0x04;
484 data->fan_div[1] |= (i >> 4) & 0x04;
485 data->fan_div[2] |= (i >> 5) & 0x04;
486 if (data->has_fan & ((1 << 3) | (1 << 4))) {
487 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
488 data->fan_div[3] = i & 0x03;
489 data->fan_div[4] = ((i >> 2) & 0x03)
490 | ((i >> 5) & 0x04);
491 }
492 if (data->has_fan & (1 << 3)) {
493 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
494 data->fan_div[3] |= (i >> 5) & 0x04;
495 }
496}
497
Jean Delvare08e7e272005-04-25 22:43:25 +0200498static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
499{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200500 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200501 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200502 int i;
503
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100504 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200505
Jean Delvare6b3e4642007-06-24 11:19:01 +0200506 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200507 || !data->valid) {
508 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400509 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200510
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100511 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200512 for (i = 0; i < data->in_num; i++) {
513 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100514 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200515 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100516 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200517 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100518 W83627EHF_REG_IN_MAX(i));
519 }
520
Jean Delvare08e7e272005-04-25 22:43:25 +0200521 /* Measured fan speeds and limits */
522 for (i = 0; i < 5; i++) {
523 if (!(data->has_fan & (1 << i)))
524 continue;
525
David Hubbard1ea6dd32007-06-24 11:16:15 +0200526 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200527 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200528 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200529 W83627EHF_REG_FAN_MIN[i]);
530
531 /* If we failed to measure the fan speed and clock
532 divider can be increased, let's try that for next
533 time */
534 if (data->fan[i] == 0xff
535 && data->fan_div[i] < 0x07) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800536 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200537 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700538 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200539 div_from_reg(data->fan_div[i] + 1));
540 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200541 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200542 /* Preserve min limit if possible */
543 if (data->fan_min[i] >= 2
544 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200545 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200546 W83627EHF_REG_FAN_MIN[i],
547 (data->fan_min[i] /= 2));
548 }
549 }
550
Guenter Roeckda2e0252010-08-14 21:08:55 +0200551 for (i = 0; i < data->pwm_num; i++) {
552 if (!(data->has_fan & (1 << i)))
553 continue;
554
Jean Delvare77fa49d2009-01-07 16:37:35 +0100555 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200556 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200557 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200558 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200559 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200560 W83627EHF_REG_TOLERANCE[i]);
561 }
562 data->pwm_mode[i] =
563 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
564 ? 0 : 1;
565 data->pwm_enable[i] =
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800566 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
567 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200568 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200569 W83627EHF_REG_PWM[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800570 data->fan_start_output[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800571 W83627EHF_REG_FAN_START_OUTPUT[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800572 data->fan_stop_output[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800573 W83627EHF_REG_FAN_STOP_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200574 data->fan_stop_time[i] = w83627ehf_read_value(data,
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800575 W83627EHF_REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200576
577 if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
578 data->fan_max_output[i] =
579 w83627ehf_read_value(data,
580 data->REG_FAN_MAX_OUTPUT[i]);
581
582 if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
583 data->fan_step_output[i] =
584 w83627ehf_read_value(data,
585 data->REG_FAN_STEP_OUTPUT[i]);
586
Rudolf Marek08c79952006-07-05 18:14:31 +0200587 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200588 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200589 W83627EHF_REG_TARGET[i]) &
590 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
591 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
592 & 0x0f;
593 }
594
Jean Delvare08e7e272005-04-25 22:43:25 +0200595 /* Measured temperatures and limits */
Guenter Roeckd36cf322011-02-07 15:08:54 -0800596 for (i = 0; i < NUM_REG_TEMP; i++) {
597 if (!(data->have_temp & (1 << i)))
598 continue;
599 data->temp[i]
600 = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]);
601 if (i > 2)
602 break;
603 data->temp_max[i]
604 = w83627ehf_read_value(data,
605 W83627EHF_REG_TEMP_OVER[i]);
606 data->temp_max_hyst[i]
607 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200608 W83627EHF_REG_TEMP_HYST[i]);
609 }
610
David Hubbard1ea6dd32007-06-24 11:16:15 +0200611 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100612 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200613 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100614 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200615 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100616 W83627EHF_REG_ALARM3) << 16);
617
Jean Delvare08e7e272005-04-25 22:43:25 +0200618 data->last_updated = jiffies;
619 data->valid = 1;
620 }
621
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100622 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200623 return data;
624}
625
626/*
627 * Sysfs callback functions
628 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100629#define show_in_reg(reg) \
630static ssize_t \
631show_##reg(struct device *dev, struct device_attribute *attr, \
632 char *buf) \
633{ \
634 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800635 struct sensor_device_attribute *sensor_attr = \
636 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100637 int nr = sensor_attr->index; \
638 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
639}
640show_in_reg(in)
641show_in_reg(in_min)
642show_in_reg(in_max)
643
644#define store_in_reg(REG, reg) \
645static ssize_t \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800646store_in_##reg(struct device *dev, struct device_attribute *attr, \
647 const char *buf, size_t count) \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100648{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200649 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800650 struct sensor_device_attribute *sensor_attr = \
651 to_sensor_dev_attr(attr); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100652 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800653 unsigned long val; \
654 int err; \
655 err = strict_strtoul(buf, 10, &val); \
656 if (err < 0) \
657 return err; \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100658 mutex_lock(&data->update_lock); \
659 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200660 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100661 data->in_##reg[nr]); \
662 mutex_unlock(&data->update_lock); \
663 return count; \
664}
665
666store_in_reg(MIN, min)
667store_in_reg(MAX, max)
668
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800669static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
670 char *buf)
Jean Delvarea4589db2006-03-23 16:30:29 +0100671{
672 struct w83627ehf_data *data = w83627ehf_update_device(dev);
673 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
674 int nr = sensor_attr->index;
675 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
676}
677
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100678static struct sensor_device_attribute sda_in_input[] = {
679 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
680 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
681 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
682 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
683 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
684 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
685 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
686 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
687 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
688 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
689};
690
Jean Delvarea4589db2006-03-23 16:30:29 +0100691static struct sensor_device_attribute sda_in_alarm[] = {
692 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
693 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
694 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
695 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
696 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
697 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
698 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
699 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
700 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
701 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
702};
703
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100704static struct sensor_device_attribute sda_in_min[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800705 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
706 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
707 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
708 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
709 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
710 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
711 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
712 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
713 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
714 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100715};
716
717static struct sensor_device_attribute sda_in_max[] = {
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800718 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
719 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
720 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
721 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
722 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
723 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
724 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
725 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
726 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
727 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100728};
729
Jean Delvare08e7e272005-04-25 22:43:25 +0200730#define show_fan_reg(reg) \
731static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100732show_##reg(struct device *dev, struct device_attribute *attr, \
733 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200734{ \
735 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800736 struct sensor_device_attribute *sensor_attr = \
737 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100738 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200739 return sprintf(buf, "%d\n", \
740 fan_from_reg(data->reg[nr], \
741 div_from_reg(data->fan_div[nr]))); \
742}
743show_fan_reg(fan);
744show_fan_reg(fan_min);
745
746static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100747show_fan_div(struct device *dev, struct device_attribute *attr,
748 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200749{
750 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100751 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
752 int nr = sensor_attr->index;
753 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200754}
755
756static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100757store_fan_min(struct device *dev, struct device_attribute *attr,
758 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200759{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200760 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100761 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
762 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800763 unsigned long val;
764 int err;
Jean Delvare08e7e272005-04-25 22:43:25 +0200765 unsigned int reg;
766 u8 new_div;
767
Guenter Roeckbce26c52011-02-04 12:54:14 -0800768 err = strict_strtoul(buf, 10, &val);
769 if (err < 0)
770 return err;
771
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100772 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200773 if (!val) {
774 /* No min limit, alarm disabled */
775 data->fan_min[nr] = 255;
776 new_div = data->fan_div[nr]; /* No change */
777 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
778 } else if ((reg = 1350000U / val) >= 128 * 255) {
779 /* Speed below this value cannot possibly be represented,
780 even with the highest divider (128) */
781 data->fan_min[nr] = 254;
782 new_div = 7; /* 128 == (1 << 7) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800783 dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
Jean Delvare08e7e272005-04-25 22:43:25 +0200784 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
785 } else if (!reg) {
786 /* Speed above this value cannot possibly be represented,
787 even with the lowest divider (1) */
788 data->fan_min[nr] = 1;
789 new_div = 0; /* 1 == (1 << 0) */
Guenter Roeckbce26c52011-02-04 12:54:14 -0800790 dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200791 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200792 } else {
793 /* Automatically pick the best divider, i.e. the one such
794 that the min limit will correspond to a register value
795 in the 96..192 range */
796 new_div = 0;
797 while (reg > 192 && new_div < 7) {
798 reg >>= 1;
799 new_div++;
800 }
801 data->fan_min[nr] = reg;
802 }
803
804 /* Write both the fan clock divider (if it changed) and the new
805 fan min (unconditionally) */
806 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200807 /* Preserve the fan speed reading */
808 if (data->fan[nr] != 0xff) {
809 if (new_div > data->fan_div[nr])
810 data->fan[nr] >>= new_div - data->fan_div[nr];
811 else if (data->fan[nr] & 0x80)
812 data->fan[nr] = 0xff;
813 else
814 data->fan[nr] <<= data->fan_div[nr] - new_div;
815 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200816
817 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
818 nr + 1, div_from_reg(data->fan_div[nr]),
819 div_from_reg(new_div));
820 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200821 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200822 /* Give the chip time to sample a new speed value */
823 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200824 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200825 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200826 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100827 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200828
829 return count;
830}
831
Yuan Mu412fec82006-02-05 23:24:16 +0100832static struct sensor_device_attribute sda_fan_input[] = {
833 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
834 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
835 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
836 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
837 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
838};
Jean Delvare08e7e272005-04-25 22:43:25 +0200839
Jean Delvarea4589db2006-03-23 16:30:29 +0100840static struct sensor_device_attribute sda_fan_alarm[] = {
841 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
842 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
843 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
844 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
845 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
846};
847
Yuan Mu412fec82006-02-05 23:24:16 +0100848static struct sensor_device_attribute sda_fan_min[] = {
849 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
850 store_fan_min, 0),
851 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
852 store_fan_min, 1),
853 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
854 store_fan_min, 2),
855 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
856 store_fan_min, 3),
857 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
858 store_fan_min, 4),
859};
Jean Delvare08e7e272005-04-25 22:43:25 +0200860
Yuan Mu412fec82006-02-05 23:24:16 +0100861static struct sensor_device_attribute sda_fan_div[] = {
862 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
863 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
864 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
865 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
866 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
867};
Jean Delvare08e7e272005-04-25 22:43:25 +0200868
Guenter Roeckd36cf322011-02-07 15:08:54 -0800869static ssize_t
870show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
871{
872 struct w83627ehf_data *data = w83627ehf_update_device(dev);
873 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
874 int nr = sensor_attr->index;
875 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
876}
877
Guenter Roeckbce26c52011-02-04 12:54:14 -0800878#define show_temp_reg(REG, reg) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200879static 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); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800884 struct sensor_device_attribute *sensor_attr = \
885 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100886 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200887 return sprintf(buf, "%d\n", \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800888 temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200889}
Guenter Roeckbce26c52011-02-04 12:54:14 -0800890show_temp_reg(TEMP, temp);
891show_temp_reg(TEMP_OVER, temp_max);
892show_temp_reg(TEMP_HYST, temp_max_hyst);
Jean Delvare08e7e272005-04-25 22:43:25 +0200893
894#define store_temp_reg(REG, reg) \
895static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100896store_##reg(struct device *dev, struct device_attribute *attr, \
897 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200898{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200899 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800900 struct sensor_device_attribute *sensor_attr = \
901 to_sensor_dev_attr(attr); \
Yuan Mu412fec82006-02-05 23:24:16 +0100902 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800903 int err; \
904 long val; \
905 err = strict_strtol(buf, 10, &val); \
906 if (err < 0) \
907 return err; \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100908 mutex_lock(&data->update_lock); \
Guenter Roeckbce26c52011-02-04 12:54:14 -0800909 data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200910 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200911 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100912 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200913 return count; \
914}
915store_temp_reg(OVER, temp_max);
916store_temp_reg(HYST, temp_max_hyst);
917
Jean Delvareda667362007-06-24 11:21:02 +0200918static ssize_t
919show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
920{
921 struct w83627ehf_data *data = w83627ehf_update_device(dev);
922 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
923 int nr = sensor_attr->index;
924 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
925}
926
Gong Juna157d062009-03-30 21:46:43 +0200927static struct sensor_device_attribute sda_temp_input[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800928 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
929 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
930 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
Guenter Roeckd36cf322011-02-07 15:08:54 -0800931 SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
932};
933
934static struct sensor_device_attribute sda_temp_label[] = {
935 SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
936 SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
937 SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
938 SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
Gong Juna157d062009-03-30 21:46:43 +0200939};
940
941static struct sensor_device_attribute sda_temp_max[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800942 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100943 store_temp_max, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800944 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
Yuan Mu412fec82006-02-05 23:24:16 +0100945 store_temp_max, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800946 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
947 store_temp_max, 2),
Gong Juna157d062009-03-30 21:46:43 +0200948};
949
950static struct sensor_device_attribute sda_temp_max_hyst[] = {
Guenter Roeckbce26c52011-02-04 12:54:14 -0800951 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100952 store_temp_max_hyst, 0),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800953 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
Yuan Mu412fec82006-02-05 23:24:16 +0100954 store_temp_max_hyst, 1),
Guenter Roeckbce26c52011-02-04 12:54:14 -0800955 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
956 store_temp_max_hyst, 2),
Gong Juna157d062009-03-30 21:46:43 +0200957};
958
959static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100960 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
961 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
962 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200963};
964
965static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200966 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
967 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
968 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100969};
Jean Delvare08e7e272005-04-25 22:43:25 +0200970
Rudolf Marek08c79952006-07-05 18:14:31 +0200971#define show_pwm_reg(reg) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800972static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
973 char *buf) \
Rudolf Marek08c79952006-07-05 18:14:31 +0200974{ \
975 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -0800976 struct sensor_device_attribute *sensor_attr = \
977 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200978 int nr = sensor_attr->index; \
979 return sprintf(buf, "%d\n", data->reg[nr]); \
980}
981
982show_pwm_reg(pwm_mode)
983show_pwm_reg(pwm_enable)
984show_pwm_reg(pwm)
985
986static ssize_t
987store_pwm_mode(struct device *dev, struct device_attribute *attr,
988 const char *buf, size_t count)
989{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200990 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200991 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
992 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -0800993 unsigned long val;
994 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +0200995 u16 reg;
996
Guenter Roeckbce26c52011-02-04 12:54:14 -0800997 err = strict_strtoul(buf, 10, &val);
998 if (err < 0)
999 return err;
1000
Rudolf Marek08c79952006-07-05 18:14:31 +02001001 if (val > 1)
1002 return -EINVAL;
1003 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001004 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001005 data->pwm_mode[nr] = val;
1006 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
1007 if (!val)
1008 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001009 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001010 mutex_unlock(&data->update_lock);
1011 return count;
1012}
1013
1014static ssize_t
1015store_pwm(struct device *dev, struct device_attribute *attr,
1016 const char *buf, size_t count)
1017{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001018 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001019 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1020 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001021 unsigned long val;
1022 int err;
1023
1024 err = strict_strtoul(buf, 10, &val);
1025 if (err < 0)
1026 return err;
1027
1028 val = SENSORS_LIMIT(val, 0, 255);
Rudolf Marek08c79952006-07-05 18:14:31 +02001029
1030 mutex_lock(&data->update_lock);
1031 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001032 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001033 mutex_unlock(&data->update_lock);
1034 return count;
1035}
1036
1037static ssize_t
1038store_pwm_enable(struct device *dev, struct device_attribute *attr,
1039 const char *buf, size_t count)
1040{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001041 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001042 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1043 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001044 unsigned long val;
1045 int err;
Rudolf Marek08c79952006-07-05 18:14:31 +02001046 u16 reg;
1047
Guenter Roeckbce26c52011-02-04 12:54:14 -08001048 err = strict_strtoul(buf, 10, &val);
1049 if (err < 0)
1050 return err;
1051
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001052 if (!val || (val > 4))
Rudolf Marek08c79952006-07-05 18:14:31 +02001053 return -EINVAL;
1054 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001055 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001056 data->pwm_enable[nr] = val;
1057 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1058 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001059 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001060 mutex_unlock(&data->update_lock);
1061 return count;
1062}
1063
1064
1065#define show_tol_temp(reg) \
1066static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1067 char *buf) \
1068{ \
1069 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001070 struct sensor_device_attribute *sensor_attr = \
1071 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001072 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001073 return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001074}
1075
1076show_tol_temp(tolerance)
1077show_tol_temp(target_temp)
1078
1079static ssize_t
1080store_target_temp(struct device *dev, struct device_attribute *attr,
1081 const char *buf, size_t count)
1082{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001083 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001084 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1085 int nr = sensor_attr->index;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001086 long val;
1087 int err;
1088
1089 err = strict_strtol(buf, 10, &val);
1090 if (err < 0)
1091 return err;
1092
1093 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
Rudolf Marek08c79952006-07-05 18:14:31 +02001094
1095 mutex_lock(&data->update_lock);
1096 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001097 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001098 mutex_unlock(&data->update_lock);
1099 return count;
1100}
1101
1102static ssize_t
1103store_tolerance(struct device *dev, struct device_attribute *attr,
1104 const char *buf, size_t count)
1105{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001106 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001107 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1108 int nr = sensor_attr->index;
1109 u16 reg;
Guenter Roeckbce26c52011-02-04 12:54:14 -08001110 long val;
1111 int err;
1112
1113 err = strict_strtol(buf, 10, &val);
1114 if (err < 0)
1115 return err;
1116
Rudolf Marek08c79952006-07-05 18:14:31 +02001117 /* Limit the temp to 0C - 15C */
Guenter Roeckbce26c52011-02-04 12:54:14 -08001118 val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
Rudolf Marek08c79952006-07-05 18:14:31 +02001119
1120 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001121 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001122 data->tolerance[nr] = val;
1123 if (nr == 1)
1124 reg = (reg & 0x0f) | (val << 4);
1125 else
1126 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001127 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001128 mutex_unlock(&data->update_lock);
1129 return count;
1130}
1131
1132static struct sensor_device_attribute sda_pwm[] = {
1133 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1134 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1135 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1136 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1137};
1138
1139static struct sensor_device_attribute sda_pwm_mode[] = {
1140 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1141 store_pwm_mode, 0),
1142 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1143 store_pwm_mode, 1),
1144 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1145 store_pwm_mode, 2),
1146 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1147 store_pwm_mode, 3),
1148};
1149
1150static struct sensor_device_attribute sda_pwm_enable[] = {
1151 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1152 store_pwm_enable, 0),
1153 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1154 store_pwm_enable, 1),
1155 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1156 store_pwm_enable, 2),
1157 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1158 store_pwm_enable, 3),
1159};
1160
1161static struct sensor_device_attribute sda_target_temp[] = {
1162 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1163 store_target_temp, 0),
1164 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1165 store_target_temp, 1),
1166 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1167 store_target_temp, 2),
1168 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1169 store_target_temp, 3),
1170};
1171
1172static struct sensor_device_attribute sda_tolerance[] = {
1173 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1174 store_tolerance, 0),
1175 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1176 store_tolerance, 1),
1177 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1178 store_tolerance, 2),
1179 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1180 store_tolerance, 3),
1181};
1182
Rudolf Marek08c79952006-07-05 18:14:31 +02001183/* Smart Fan registers */
1184
1185#define fan_functions(reg, REG) \
1186static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1187 char *buf) \
1188{ \
1189 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001190 struct sensor_device_attribute *sensor_attr = \
1191 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001192 int nr = sensor_attr->index; \
1193 return sprintf(buf, "%d\n", data->reg[nr]); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001194} \
Rudolf Marek08c79952006-07-05 18:14:31 +02001195static ssize_t \
1196store_##reg(struct device *dev, struct device_attribute *attr, \
1197 const char *buf, size_t count) \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001198{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001199 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001200 struct sensor_device_attribute *sensor_attr = \
1201 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001202 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001203 unsigned long val; \
1204 int err; \
1205 err = strict_strtoul(buf, 10, &val); \
1206 if (err < 0) \
1207 return err; \
1208 val = SENSORS_LIMIT(val, 1, 255); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001209 mutex_lock(&data->update_lock); \
1210 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001211 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001212 mutex_unlock(&data->update_lock); \
1213 return count; \
1214}
1215
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001216fan_functions(fan_start_output, FAN_START_OUTPUT)
1217fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1218fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1219fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001220
1221#define fan_time_functions(reg, REG) \
1222static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1223 char *buf) \
1224{ \
1225 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001226 struct sensor_device_attribute *sensor_attr = \
1227 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001228 int nr = sensor_attr->index; \
1229 return sprintf(buf, "%d\n", \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001230 step_time_from_reg(data->reg[nr], \
1231 data->pwm_mode[nr])); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001232} \
1233\
1234static ssize_t \
1235store_##reg(struct device *dev, struct device_attribute *attr, \
1236 const char *buf, size_t count) \
1237{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001238 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001239 struct sensor_device_attribute *sensor_attr = \
1240 to_sensor_dev_attr(attr); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001241 int nr = sensor_attr->index; \
Guenter Roeckbce26c52011-02-04 12:54:14 -08001242 unsigned long val; \
1243 int err; \
1244 err = strict_strtoul(buf, 10, &val); \
1245 if (err < 0) \
1246 return err; \
1247 val = step_time_to_reg(val, data->pwm_mode[nr]); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001248 mutex_lock(&data->update_lock); \
1249 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001250 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001251 mutex_unlock(&data->update_lock); \
1252 return count; \
1253} \
1254
1255fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1256
David Hubbard1ea6dd32007-06-24 11:16:15 +02001257static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1258 char *buf)
1259{
1260 struct w83627ehf_data *data = dev_get_drvdata(dev);
1261
1262 return sprintf(buf, "%s\n", data->name);
1263}
1264static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001265
1266static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1267 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1268 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001269 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1270 store_fan_start_output, 3),
1271 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1272 store_fan_stop_output, 3),
1273 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1274 store_fan_max_output, 3),
1275 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1276 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001277};
1278
1279static struct sensor_device_attribute sda_sf3_arrays[] = {
1280 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1281 store_fan_stop_time, 0),
1282 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1283 store_fan_stop_time, 1),
1284 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1285 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001286 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1287 store_fan_start_output, 0),
1288 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1289 store_fan_start_output, 1),
1290 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1291 store_fan_start_output, 2),
1292 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1293 store_fan_stop_output, 0),
1294 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1295 store_fan_stop_output, 1),
1296 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1297 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001298};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001299
Guenter Roeckda2e0252010-08-14 21:08:55 +02001300
1301/*
1302 * pwm1 and pwm3 don't support max and step settings on all chips.
1303 * Need to check support while generating/removing attribute files.
1304 */
1305static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1306 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1307 store_fan_max_output, 0),
1308 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1309 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001310 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1311 store_fan_max_output, 1),
1312 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1313 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001314 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1315 store_fan_max_output, 2),
1316 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1317 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001318};
1319
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001320static ssize_t
1321show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1322{
1323 struct w83627ehf_data *data = dev_get_drvdata(dev);
1324 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1325}
1326static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1327
Jean Delvare08e7e272005-04-25 22:43:25 +02001328/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001329 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001330 */
1331
David Hubbardc18beb52006-09-24 21:04:38 +02001332static void w83627ehf_device_remove_files(struct device *dev)
1333{
1334 /* some entries in the following arrays may not have been used in
1335 * device_create_file(), but device_remove_file() will ignore them */
1336 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001337 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001338
1339 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1340 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001341 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1342 struct sensor_device_attribute *attr =
1343 &sda_sf3_max_step_arrays[i];
1344 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1345 device_remove_file(dev, &attr->dev_attr);
1346 }
David Hubbardc18beb52006-09-24 21:04:38 +02001347 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1348 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001349 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001350 if ((i == 6) && data->in6_skip)
1351 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001352 device_remove_file(dev, &sda_in_input[i].dev_attr);
1353 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1354 device_remove_file(dev, &sda_in_min[i].dev_attr);
1355 device_remove_file(dev, &sda_in_max[i].dev_attr);
1356 }
1357 for (i = 0; i < 5; i++) {
1358 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1359 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1360 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1361 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1362 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001363 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001364 device_remove_file(dev, &sda_pwm[i].dev_attr);
1365 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1366 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1367 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1368 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1369 }
Guenter Roeckd36cf322011-02-07 15:08:54 -08001370 for (i = 0; i < NUM_REG_TEMP; i++) {
1371 if (!(data->have_temp & (1 << i)))
Gong Juna157d062009-03-30 21:46:43 +02001372 continue;
1373 device_remove_file(dev, &sda_temp_input[i].dev_attr);
Guenter Roeckd36cf322011-02-07 15:08:54 -08001374 device_remove_file(dev, &sda_temp_label[i].dev_attr);
1375 if (i > 2)
1376 break;
Gong Juna157d062009-03-30 21:46:43 +02001377 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1378 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1379 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1380 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1381 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001382
1383 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001384 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001385}
1386
David Hubbard1ea6dd32007-06-24 11:16:15 +02001387/* Get the monitoring functions started */
1388static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001389{
1390 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001391 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001392
1393 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001394 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001395 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001396 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001397 tmp | 0x01);
1398
Guenter Roeckd36cf322011-02-07 15:08:54 -08001399 /* Enable temperature sensors if needed */
1400 for (i = 0; i < NUM_REG_TEMP; i++) {
1401 if (!(data->have_temp & (1 << i)))
1402 continue;
1403 if (!W83627EHF_REG_TEMP_CONFIG[i])
1404 continue;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001405 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001406 W83627EHF_REG_TEMP_CONFIG[i]);
1407 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001408 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001409 W83627EHF_REG_TEMP_CONFIG[i],
1410 tmp & 0xfe);
1411 }
Jean Delvared3130f02007-06-24 11:20:13 +02001412
1413 /* Enable VBAT monitoring if needed */
1414 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1415 if (!(tmp & 0x01))
1416 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001417
1418 /* Get thermal sensor types */
1419 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1420 for (i = 0; i < 3; i++) {
1421 if ((tmp & (0x02 << i)))
1422 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1423 else
1424 data->temp_type[i] = 4; /* thermistor */
1425 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001426}
1427
David Hubbard1ea6dd32007-06-24 11:16:15 +02001428static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001429{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001430 struct device *dev = &pdev->dev;
1431 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001432 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001433 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001434 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001435 int i, err = 0;
1436
David Hubbard1ea6dd32007-06-24 11:16:15 +02001437 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1438 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001439 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001440 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1441 (unsigned long)res->start,
1442 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001443 goto exit;
1444 }
1445
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001446 data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
1447 if (!data) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001448 err = -ENOMEM;
1449 goto exit_release;
1450 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001451
David Hubbard1ea6dd32007-06-24 11:16:15 +02001452 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001453 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001454 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001455 data->name = w83627ehf_device_names[sio_data->kind];
1456 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001457
Gong Jun237c8d2f2009-03-30 21:46:42 +02001458 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1459 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1460 /* 667HG has 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001461 data->pwm_num = (sio_data->kind == w83667hg
1462 || sio_data->kind == w83667hg_b) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001463
Guenter Roeckd36cf322011-02-07 15:08:54 -08001464 data->have_temp = 0x07;
Gong Juna157d062009-03-30 21:46:43 +02001465 /* Check temp3 configuration bit for 667HG */
Guenter Roeckd36cf322011-02-07 15:08:54 -08001466 if (sio_data->kind == w83667hg) {
1467 u8 reg;
1468
1469 reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1470 if (reg & 0x01)
1471 data->have_temp &= ~(1 << 2);
1472 else
1473 data->in6_skip = 1; /* Either temp3 or in6 */
1474 } else if (sio_data->kind == w83667hg_b) {
1475 u8 reg;
1476
1477 reg = w83627ehf_read_value(data, 0x4a);
1478 data->temp_src[0] = reg >> 5;
1479 reg = w83627ehf_read_value(data, 0x49);
1480 data->temp_src[1] = reg & 0x07;
1481 data->temp_src[2] = (reg >> 4) & 0x07;
1482
1483 /*
1484 * W83667HG-B has another temperature register at 0x7e.
1485 * The temperature source is selected with register 0x7d.
1486 * Support it if the source differs from already reported
1487 * sources.
1488 */
1489 reg = w83627ehf_read_value(data, 0x7d);
1490 reg &= 0x07;
1491 if (reg != data->temp_src[0] && reg != data->temp_src[1]
1492 && reg != data->temp_src[2]) {
1493 data->temp_src[3] = reg;
1494 data->have_temp |= 1 << 3;
1495 }
1496
1497 /*
1498 * Chip supports either AUXTIN or VIN3. Try to find out which
1499 * one.
1500 */
1501 reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1502 if (data->temp_src[2] == 2 && (reg & 0x01))
1503 data->have_temp &= ~(1 << 2);
1504
1505 if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
1506 || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
1507 data->in6_skip = 1;
1508
1509 data->temp_label = w83667hg_b_temp_label;
Gong Juna157d062009-03-30 21:46:43 +02001510 }
1511
Guenter Roeckda2e0252010-08-14 21:08:55 +02001512 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1513 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001514 if (sio_data->kind == w83667hg_b) {
1515 data->REG_FAN_MAX_OUTPUT =
1516 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1517 data->REG_FAN_STEP_OUTPUT =
1518 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1519 } else {
1520 data->REG_FAN_MAX_OUTPUT =
1521 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1522 data->REG_FAN_STEP_OUTPUT =
1523 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1524 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001525
Jean Delvare08e7e272005-04-25 22:43:25 +02001526 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001527 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001528
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001529 data->vrm = vid_which_vrm();
1530 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001531 /* Read VID value */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001532 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001533 /* W83667HG has different pins for VID input and output, so
1534 we can get the VID input values directly at logical device D
1535 0xe3. */
1536 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1537 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001538 err = device_create_file(dev, &dev_attr_cpu0_vid);
1539 if (err)
1540 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001541 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001542 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1543 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1544 /* Set VID input sensibility if needed. In theory the
1545 BIOS should have set it, but in practice it's not
1546 always the case. We only do it for the W83627EHF/EHG
1547 because the W83627DHG is more complex in this
1548 respect. */
1549 if (sio_data->kind == w83627ehf) {
1550 en_vrm10 = superio_inb(sio_data->sioreg,
1551 SIO_REG_EN_VRM10);
1552 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1553 dev_warn(dev, "Setting VID input "
1554 "voltage to TTL\n");
1555 superio_outb(sio_data->sioreg,
1556 SIO_REG_EN_VRM10,
1557 en_vrm10 & ~0x08);
1558 } else if (!(en_vrm10 & 0x08)
1559 && data->vrm == 100) {
1560 dev_warn(dev, "Setting VID input "
1561 "voltage to VRM10\n");
1562 superio_outb(sio_data->sioreg,
1563 SIO_REG_EN_VRM10,
1564 en_vrm10 | 0x08);
1565 }
1566 }
1567
1568 data->vid = superio_inb(sio_data->sioreg,
1569 SIO_REG_VID_DATA);
1570 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1571 data->vid &= 0x3f;
1572
1573 err = device_create_file(dev, &dev_attr_cpu0_vid);
1574 if (err)
1575 goto exit_release;
1576 } else {
1577 dev_info(dev, "VID pins in output mode, CPU VID not "
1578 "available\n");
1579 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001580 }
1581
Rudolf Marek08c79952006-07-05 18:14:31 +02001582 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001583 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001584 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1585 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1586 } else {
1587 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1588 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1589 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001590 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001591
Jean Delvare08e7e272005-04-25 22:43:25 +02001592 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001593 as fan on/off switches, but fan5 control is write only :/
1594 We assume that if the serial interface is disabled, designers
1595 connected fan5 as input unless they are emitting log 1, which
1596 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001597
Jean Delvare08e7e272005-04-25 22:43:25 +02001598 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001599 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001600 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001601 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001602 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001603 data->has_fan |= (1 << 4);
1604
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001605 /* Read fan clock dividers immediately */
1606 w83627ehf_update_fan_div(data);
1607
Jean Delvare08e7e272005-04-25 22:43:25 +02001608 /* Register sysfs hooks */
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001609 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
1610 err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
1611 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02001612 goto exit_remove;
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001613 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001614
Guenter Roeckda2e0252010-08-14 21:08:55 +02001615 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1616 struct sensor_device_attribute *attr =
1617 &sda_sf3_max_step_arrays[i];
1618 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
1619 err = device_create_file(dev, &attr->dev_attr);
1620 if (err)
1621 goto exit_remove;
1622 }
1623 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001624 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001625 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001626 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001627 err = device_create_file(dev,
1628 &sda_sf3_arrays_fan4[i].dev_attr);
1629 if (err)
David Hubbardc18beb52006-09-24 21:04:38 +02001630 goto exit_remove;
1631 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001632
Gong Juna157d062009-03-30 21:46:43 +02001633 for (i = 0; i < data->in_num; i++) {
1634 if ((i == 6) && data->in6_skip)
1635 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001636 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1637 || (err = device_create_file(dev,
1638 &sda_in_alarm[i].dev_attr))
1639 || (err = device_create_file(dev,
1640 &sda_in_min[i].dev_attr))
1641 || (err = device_create_file(dev,
1642 &sda_in_max[i].dev_attr)))
1643 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001644 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001645
Yuan Mu412fec82006-02-05 23:24:16 +01001646 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001647 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001648 if ((err = device_create_file(dev,
1649 &sda_fan_input[i].dev_attr))
1650 || (err = device_create_file(dev,
1651 &sda_fan_alarm[i].dev_attr))
1652 || (err = device_create_file(dev,
1653 &sda_fan_div[i].dev_attr))
1654 || (err = device_create_file(dev,
1655 &sda_fan_min[i].dev_attr)))
1656 goto exit_remove;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001657 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001658 ((err = device_create_file(dev,
1659 &sda_pwm[i].dev_attr))
1660 || (err = device_create_file(dev,
1661 &sda_pwm_mode[i].dev_attr))
1662 || (err = device_create_file(dev,
1663 &sda_pwm_enable[i].dev_attr))
1664 || (err = device_create_file(dev,
1665 &sda_target_temp[i].dev_attr))
1666 || (err = device_create_file(dev,
1667 &sda_tolerance[i].dev_attr))))
1668 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001669 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001670 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001671
Guenter Roeckd36cf322011-02-07 15:08:54 -08001672 for (i = 0; i < NUM_REG_TEMP; i++) {
1673 if (!(data->have_temp & (1 << i)))
Gong Juna157d062009-03-30 21:46:43 +02001674 continue;
Guenter Roeckd36cf322011-02-07 15:08:54 -08001675 err = device_create_file(dev, &sda_temp_input[i].dev_attr);
1676 if (err)
1677 goto exit_remove;
1678 if (data->temp_label) {
1679 err = device_create_file(dev,
1680 &sda_temp_label[i].dev_attr);
1681 if (err)
1682 goto exit_remove;
1683 }
1684 if (i > 2)
1685 break;
1686 if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr))
Gong Juna157d062009-03-30 21:46:43 +02001687 || (err = device_create_file(dev,
1688 &sda_temp_max_hyst[i].dev_attr))
1689 || (err = device_create_file(dev,
1690 &sda_temp_alarm[i].dev_attr))
1691 || (err = device_create_file(dev,
1692 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001693 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001694 }
David Hubbardc18beb52006-09-24 21:04:38 +02001695
David Hubbard1ea6dd32007-06-24 11:16:15 +02001696 err = device_create_file(dev, &dev_attr_name);
1697 if (err)
1698 goto exit_remove;
1699
Tony Jones1beeffe2007-08-20 13:46:20 -07001700 data->hwmon_dev = hwmon_device_register(dev);
1701 if (IS_ERR(data->hwmon_dev)) {
1702 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001703 goto exit_remove;
1704 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001705
1706 return 0;
1707
David Hubbardc18beb52006-09-24 21:04:38 +02001708exit_remove:
1709 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001710 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001711 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001712exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001713 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001714exit:
1715 return err;
1716}
1717
David Hubbard1ea6dd32007-06-24 11:16:15 +02001718static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001719{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001720 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001721
Tony Jones1beeffe2007-08-20 13:46:20 -07001722 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001723 w83627ehf_device_remove_files(&pdev->dev);
1724 release_region(data->addr, IOREGION_LENGTH);
1725 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001726 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001727
1728 return 0;
1729}
1730
David Hubbard1ea6dd32007-06-24 11:16:15 +02001731static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001732 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001733 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001734 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001735 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001736 .probe = w83627ehf_probe,
1737 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001738};
1739
David Hubbard1ea6dd32007-06-24 11:16:15 +02001740/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1741static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1742 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001743{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001744 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1745 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1746 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001747 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d2f2009-03-30 21:46:42 +02001748 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001749 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001750
Jean Delvare08e7e272005-04-25 22:43:25 +02001751 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001752 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001753
David Hubbard1ea6dd32007-06-24 11:16:15 +02001754 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001755
Jean Delvare67b671b2007-12-06 23:13:42 +01001756 if (force_id)
1757 val = force_id;
1758 else
1759 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1760 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001761 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001762 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001763 sio_data->kind = w83627ehf;
1764 sio_name = sio_name_W83627EHF;
1765 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001766 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001767 sio_data->kind = w83627ehf;
1768 sio_name = sio_name_W83627EHG;
1769 break;
1770 case SIO_W83627DHG_ID:
1771 sio_data->kind = w83627dhg;
1772 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001773 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001774 case SIO_W83627DHG_P_ID:
1775 sio_data->kind = w83627dhg_p;
1776 sio_name = sio_name_W83627DHG_P;
1777 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001778 case SIO_W83667HG_ID:
1779 sio_data->kind = w83667hg;
1780 sio_name = sio_name_W83667HG;
1781 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001782 case SIO_W83667HG_B_ID:
1783 sio_data->kind = w83667hg_b;
1784 sio_name = sio_name_W83667HG_B;
1785 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001786 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001787 if (val != 0xffff)
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001788 pr_debug("unsupported chip ID: 0x%04x\n", val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001789 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001790 return -ENODEV;
1791 }
1792
David Hubbard1ea6dd32007-06-24 11:16:15 +02001793 /* We have a known chip, find the HWM I/O address */
1794 superio_select(sioaddr, W83627EHF_LD_HWM);
1795 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1796 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001797 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001798 if (*addr == 0) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001799 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001800 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001801 return -ENODEV;
1802 }
1803
1804 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001805 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001806 if (!(val & 0x01)) {
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001807 pr_warn("Forcibly enabling Super-I/O. "
1808 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001809 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001810 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001811
David Hubbard1ea6dd32007-06-24 11:16:15 +02001812 superio_exit(sioaddr);
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001813 pr_info("Found %s chip at %#x\n", sio_name, *addr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001814 sio_data->sioreg = sioaddr;
1815
Jean Delvare08e7e272005-04-25 22:43:25 +02001816 return 0;
1817}
1818
David Hubbard1ea6dd32007-06-24 11:16:15 +02001819/* when Super-I/O functions move to a separate file, the Super-I/O
1820 * bus will manage the lifetime of the device and this module will only keep
1821 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1822 * must keep track of the device */
1823static struct platform_device *pdev;
1824
Jean Delvare08e7e272005-04-25 22:43:25 +02001825static int __init sensors_w83627ehf_init(void)
1826{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001827 int err;
1828 unsigned short address;
1829 struct resource res;
1830 struct w83627ehf_sio_data sio_data;
1831
1832 /* initialize sio_data->kind and sio_data->sioreg.
1833 *
1834 * when Super-I/O functions move to a separate file, the Super-I/O
1835 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1836 * w83627ehf hardware monitor, and call probe() */
1837 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1838 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001839 return -ENODEV;
1840
David Hubbard1ea6dd32007-06-24 11:16:15 +02001841 err = platform_driver_register(&w83627ehf_driver);
1842 if (err)
1843 goto exit;
1844
Guenter Roecke7e1ca62011-02-04 13:24:30 -08001845 pdev = platform_device_alloc(DRVNAME, address);
1846 if (!pdev) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001847 err = -ENOMEM;
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001848 pr_err("Device allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001849 goto exit_unregister;
1850 }
1851
1852 err = platform_device_add_data(pdev, &sio_data,
1853 sizeof(struct w83627ehf_sio_data));
1854 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001855 pr_err("Platform data allocation failed\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001856 goto exit_device_put;
1857 }
1858
1859 memset(&res, 0, sizeof(res));
1860 res.name = DRVNAME;
1861 res.start = address + IOREGION_OFFSET;
1862 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1863 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001864
1865 err = acpi_check_resource_conflict(&res);
1866 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001867 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001868
David Hubbard1ea6dd32007-06-24 11:16:15 +02001869 err = platform_device_add_resources(pdev, &res, 1);
1870 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001871 pr_err("Device resource addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001872 goto exit_device_put;
1873 }
1874
1875 /* platform_device_add calls probe() */
1876 err = platform_device_add(pdev);
1877 if (err) {
Joe Perchesabdc6fd2010-10-20 06:51:54 +00001878 pr_err("Device addition failed (%d)\n", err);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001879 goto exit_device_put;
1880 }
1881
1882 return 0;
1883
1884exit_device_put:
1885 platform_device_put(pdev);
1886exit_unregister:
1887 platform_driver_unregister(&w83627ehf_driver);
1888exit:
1889 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001890}
1891
1892static void __exit sensors_w83627ehf_exit(void)
1893{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001894 platform_device_unregister(pdev);
1895 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001896}
1897
1898MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1899MODULE_DESCRIPTION("W83627EHF driver");
1900MODULE_LICENSE("GPL");
1901
1902module_init(sensors_w83627ehf_init);
1903module_exit(sensors_w83627ehf_exit);