blob: e96e69dd36fb4b4faba43ffad13b53815d06bc65 [file] [log] [blame]
Jean Delvare08e7e272005-04-25 22:43:25 +02001/*
2 w83627ehf - Driver for the hardware monitoring functionality of
3 the Winbond W83627EHF Super-I/O chip
4 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Jean Delvare3379cee2006-09-24 21:25:52 +02005 Copyright (C) 2006 Yuan Mu (Winbond),
Jean Delvare7188cc62006-12-12 18:18:30 +01006 Rudolf Marek <r.marek@assembler.cz>
David Hubbardc18beb52006-09-24 21:04:38 +02007 David Hubbard <david.c.hubbard@gmail.com>
Daniel J Blueman41e9a062009-12-14 18:01:37 -08008 Daniel J Blueman <daniel.blueman@gmail.com>
Jean Delvare08e7e272005-04-25 22:43:25 +02009
10 Shamelessly ripped from the w83627hf driver
11 Copyright (C) 2003 Mark Studebaker
12
13 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
14 in testing and debugging this driver.
15
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020016 This driver also supports the W83627EHG, which is the lead-free
17 version of the W83627EHF.
18
Jean Delvare08e7e272005-04-25 22:43:25 +020019 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32
33
34 Supports the following chips:
35
David Hubbard657c93b2007-02-14 21:15:04 +010036 Chip #vin #fan #pwm #temp chip IDs man ID
37 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
38 0x8860 0xa1
39 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Jean Delvarec1e48dc2009-06-15 18:39:50 +020040 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
Gong Jun237c8d22009-03-30 21:46:42 +020041 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Guenter Roeckc39aeda2010-08-14 21:08:55 +020042 w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020043*/
44
45#include <linux/module.h>
46#include <linux/init.h>
47#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020048#include <linux/jiffies.h>
49#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040050#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010051#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020052#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040053#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010054#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010055#include <linux/acpi.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020056#include <linux/io.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020057#include "lm75.h"
58
Guenter Roeckc39aeda2010-08-14 21:08:55 +020059enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
David Hubbard1ea6dd32007-06-24 11:16:15 +020060
61/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
62static const char * w83627ehf_device_names[] = {
63 "w83627ehf",
64 "w83627dhg",
Jean Delvarec1e48dc2009-06-15 18:39:50 +020065 "w83627dhg",
Gong Jun237c8d22009-03-30 21:46:42 +020066 "w83667hg",
Guenter Roeckc39aeda2010-08-14 21:08:55 +020067 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020068};
69
Jean Delvare67b671b2007-12-06 23:13:42 +010070static unsigned short force_id;
71module_param(force_id, ushort, 0);
72MODULE_PARM_DESC(force_id, "Override the detected device ID");
73
David Hubbard1ea6dd32007-06-24 11:16:15 +020074#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020075
76/*
77 * Super-I/O constants and functions
78 */
79
Jean Delvare08e7e272005-04-25 22:43:25 +020080#define W83627EHF_LD_HWM 0x0b
Gong Jun237c8d22009-03-30 21:46:42 +020081#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020082
83#define SIO_REG_LDSEL 0x07 /* Logical device select */
84#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020085#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020086#define SIO_REG_ENABLE 0x30 /* Logical device enable */
87#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020088#define SIO_REG_VID_CTRL 0xF0 /* VID control */
89#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020090
David Hubbard657c93b2007-02-14 21:15:04 +010091#define SIO_W83627EHF_ID 0x8850
92#define SIO_W83627EHG_ID 0x8860
93#define SIO_W83627DHG_ID 0xa020
Jean Delvarec1e48dc2009-06-15 18:39:50 +020094#define SIO_W83627DHG_P_ID 0xb070
Gong Jun237c8d22009-03-30 21:46:42 +020095#define SIO_W83667HG_ID 0xa510
Guenter Roeckc39aeda2010-08-14 21:08:55 +020096#define SIO_W83667HG_B_ID 0xb350
David Hubbard657c93b2007-02-14 21:15:04 +010097#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +020098
99static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200100superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +0200101{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102 outb(reg, ioreg);
103 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200104}
105
106static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200107superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200108{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109 outb(reg, ioreg);
110 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200111}
112
113static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200114superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200115{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116 outb(SIO_REG_LDSEL, ioreg);
117 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200118}
119
120static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200121superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200122{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200123 outb(0x87, ioreg);
124 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200125}
126
127static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200128superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200129{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200130 outb(0x02, ioreg);
131 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200132}
133
134/*
135 * ISA constants
136 */
137
Jean Delvare1a641fc2007-04-23 14:41:16 -0700138#define IOREGION_ALIGNMENT ~7
139#define IOREGION_OFFSET 5
140#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200141#define ADDR_REG_OFFSET 0
142#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200143
144#define W83627EHF_REG_BANK 0x4E
145#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100146
147/* Not currently used:
148 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
149 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
150 * REG_MAN_ID is at port 0x4f
151 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200152
153static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
154static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
155
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100156/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
157#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
158 (0x554 + (((nr) - 7) * 2)))
159#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
160 (0x555 + (((nr) - 7) * 2)))
161#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
162 (0x550 + (nr) - 7))
163
Jean Delvare08e7e272005-04-25 22:43:25 +0200164#define W83627EHF_REG_TEMP1 0x27
165#define W83627EHF_REG_TEMP1_HYST 0x3a
166#define W83627EHF_REG_TEMP1_OVER 0x39
167static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
168static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
169static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
170static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
171
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
Jean Delvare08e7e272005-04-25 22:43:25 +0200216/*
217 * Conversions
218 */
219
Rudolf Marek08c79952006-07-05 18:14:31 +0200220/* 1 is PWM mode, output in ms */
221static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
222{
223 return mode ? 100 * reg : 400 * reg;
224}
225
226static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
227{
228 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
229 (msec + 200) / 400), 1, 255);
230}
231
Jean Delvare08e7e272005-04-25 22:43:25 +0200232static inline unsigned int
233fan_from_reg(u8 reg, unsigned int div)
234{
235 if (reg == 0 || reg == 255)
236 return 0;
237 return 1350000U / (reg * div);
238}
239
240static inline unsigned int
241div_from_reg(u8 reg)
242{
243 return 1 << reg;
244}
245
246static inline int
247temp1_from_reg(s8 reg)
248{
249 return reg * 1000;
250}
251
252static inline s8
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200253temp1_to_reg(long temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200254{
Rudolf Marek08c79952006-07-05 18:14:31 +0200255 if (temp <= min)
256 return min / 1000;
257 if (temp >= max)
258 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200259 if (temp < 0)
260 return (temp - 500) / 1000;
261 return (temp + 500) / 1000;
262}
263
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100264/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
265
266static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
267
268static inline long in_from_reg(u8 reg, u8 nr)
269{
270 return reg * scale_in[nr];
271}
272
273static inline u8 in_to_reg(u32 val, u8 nr)
274{
275 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
276}
277
Jean Delvare08e7e272005-04-25 22:43:25 +0200278/*
279 * Data structures and manipulation thereof
280 */
281
282struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200283 int addr; /* IO base of hw monitor block */
284 const char *name;
285
Tony Jones1beeffe2007-08-20 13:46:20 -0700286 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100287 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200288
Guenter Roeckda2e0252010-08-14 21:08:55 +0200289 const u8 *REG_FAN_START_OUTPUT;
290 const u8 *REG_FAN_STOP_OUTPUT;
291 const u8 *REG_FAN_MAX_OUTPUT;
292 const u8 *REG_FAN_STEP_OUTPUT;
293
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100294 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200295 char valid; /* !=0 if following fields are valid */
296 unsigned long last_updated; /* In jiffies */
297
298 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200299 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100300 u8 in[10]; /* Register value */
301 u8 in_max[10]; /* Register value */
302 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200303 u8 fan[5];
304 u8 fan_min[5];
305 u8 fan_div[5];
306 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200307 u8 temp_type[3];
Jean Delvare08e7e272005-04-25 22:43:25 +0200308 s8 temp1;
309 s8 temp1_max;
310 s8 temp1_max_hyst;
311 s16 temp[2];
312 s16 temp_max[2];
313 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100314 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200315
316 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
317 u8 pwm_enable[4]; /* 1->manual
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800318 2->thermal cruise mode (also called SmartFan I)
319 3->fan speed cruise mode
320 4->variable thermal cruise (also called SmartFan III) */
Gong Jun237c8d22009-03-30 21:46:42 +0200321 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200322 u8 pwm[4];
323 u8 target_temp[4];
324 u8 tolerance[4];
325
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800326 u8 fan_start_output[4]; /* minimum fan speed when spinning up */
327 u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
328 u8 fan_stop_time[4]; /* time at minimum before disabling fan */
329 u8 fan_max_output[4]; /* maximum fan speed */
330 u8 fan_step_output[4]; /* rate of change output value */
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200331
332 u8 vid;
333 u8 vrm;
Gong Juna157d062009-03-30 21:46:43 +0200334
335 u8 temp3_disable;
336 u8 in6_skip;
Jean Delvare08e7e272005-04-25 22:43:25 +0200337};
338
David Hubbard1ea6dd32007-06-24 11:16:15 +0200339struct w83627ehf_sio_data {
340 int sioreg;
341 enum kinds kind;
342};
343
Jean Delvare08e7e272005-04-25 22:43:25 +0200344static inline int is_word_sized(u16 reg)
345{
346 return (((reg & 0xff00) == 0x100
347 || (reg & 0xff00) == 0x200)
348 && ((reg & 0x00ff) == 0x50
349 || (reg & 0x00ff) == 0x53
350 || (reg & 0x00ff) == 0x55));
351}
352
Jean Delvare09568952007-08-11 13:57:05 +0200353/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200354static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200355{
Jean Delvare09568952007-08-11 13:57:05 +0200356 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200357 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
358 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200359 }
360}
361
Jean Delvare09568952007-08-11 13:57:05 +0200362/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200363static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200364{
365 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200366 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
367 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200368 }
369}
370
David Hubbard1ea6dd32007-06-24 11:16:15 +0200371static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200372{
Jean Delvare08e7e272005-04-25 22:43:25 +0200373 int res, word_sized = is_word_sized(reg);
374
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100375 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200376
David Hubbard1ea6dd32007-06-24 11:16:15 +0200377 w83627ehf_set_bank(data, reg);
378 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
379 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200380 if (word_sized) {
381 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200382 data->addr + ADDR_REG_OFFSET);
383 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200384 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200385 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200386
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100387 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200388
389 return res;
390}
391
David Hubbard1ea6dd32007-06-24 11:16:15 +0200392static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200393{
Jean Delvare08e7e272005-04-25 22:43:25 +0200394 int word_sized = is_word_sized(reg);
395
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100396 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200397
David Hubbard1ea6dd32007-06-24 11:16:15 +0200398 w83627ehf_set_bank(data, reg);
399 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200400 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200401 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200402 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200403 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200404 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200405 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
406 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200407
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100408 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200409 return 0;
410}
411
412/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200413static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200414{
Jean Delvare08e7e272005-04-25 22:43:25 +0200415 u8 reg;
416
417 switch (nr) {
418 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200419 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200420 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200421 /* fan5 input control bit is write only, compute the value */
422 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200423 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
424 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200425 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200426 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200427 break;
428 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200429 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200430 | ((data->fan_div[1] & 0x03) << 6);
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) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200435 | ((data->fan_div[1] & 0x04) << 4);
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 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200439 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200440 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200441 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
442 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200443 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200444 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200445 break;
446 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200447 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200448 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200449 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
450 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200451 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200452 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200453 break;
454 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200455 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700456 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200457 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200458 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200459 break;
460 }
461}
462
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400463static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
464{
465 int i;
466
467 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
468 data->fan_div[0] = (i >> 4) & 0x03;
469 data->fan_div[1] = (i >> 6) & 0x03;
470 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
471 data->fan_div[2] = (i >> 6) & 0x03;
472 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
473 data->fan_div[0] |= (i >> 3) & 0x04;
474 data->fan_div[1] |= (i >> 4) & 0x04;
475 data->fan_div[2] |= (i >> 5) & 0x04;
476 if (data->has_fan & ((1 << 3) | (1 << 4))) {
477 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
478 data->fan_div[3] = i & 0x03;
479 data->fan_div[4] = ((i >> 2) & 0x03)
480 | ((i >> 5) & 0x04);
481 }
482 if (data->has_fan & (1 << 3)) {
483 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
484 data->fan_div[3] |= (i >> 5) & 0x04;
485 }
486}
487
Jean Delvare08e7e272005-04-25 22:43:25 +0200488static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
489{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200490 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200491 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200492 int i;
493
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100494 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200495
Jean Delvare6b3e4642007-06-24 11:19:01 +0200496 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200497 || !data->valid) {
498 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400499 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200500
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100501 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200502 for (i = 0; i < data->in_num; i++) {
503 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100504 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200505 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100506 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200507 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100508 W83627EHF_REG_IN_MAX(i));
509 }
510
Jean Delvare08e7e272005-04-25 22:43:25 +0200511 /* Measured fan speeds and limits */
512 for (i = 0; i < 5; i++) {
513 if (!(data->has_fan & (1 << i)))
514 continue;
515
David Hubbard1ea6dd32007-06-24 11:16:15 +0200516 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200517 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200518 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200519 W83627EHF_REG_FAN_MIN[i]);
520
521 /* If we failed to measure the fan speed and clock
522 divider can be increased, let's try that for next
523 time */
524 if (data->fan[i] == 0xff
525 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200526 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200527 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700528 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200529 div_from_reg(data->fan_div[i] + 1));
530 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200531 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200532 /* Preserve min limit if possible */
533 if (data->fan_min[i] >= 2
534 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200535 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200536 W83627EHF_REG_FAN_MIN[i],
537 (data->fan_min[i] /= 2));
538 }
539 }
540
Guenter Roeckda2e0252010-08-14 21:08:55 +0200541 for (i = 0; i < data->pwm_num; i++) {
542 if (!(data->has_fan & (1 << i)))
543 continue;
544
Jean Delvare77fa49d2009-01-07 16:37:35 +0100545 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200546 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200547 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200548 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200549 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200550 W83627EHF_REG_TOLERANCE[i]);
551 }
552 data->pwm_mode[i] =
553 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
554 ? 0 : 1;
555 data->pwm_enable[i] =
556 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
557 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200558 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200559 W83627EHF_REG_PWM[i]);
Daniel J Blueman41e9a062009-12-14 18:01:37 -0800560 data->fan_start_output[i] = w83627ehf_read_value(data,
561 W83627EHF_REG_FAN_START_OUTPUT[i]);
562 data->fan_stop_output[i] = w83627ehf_read_value(data,
563 W83627EHF_REG_FAN_STOP_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200564 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200565 W83627EHF_REG_FAN_STOP_TIME[i]);
Guenter Roeckda2e0252010-08-14 21:08:55 +0200566
567 if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
568 data->fan_max_output[i] =
569 w83627ehf_read_value(data,
570 data->REG_FAN_MAX_OUTPUT[i]);
571
572 if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
573 data->fan_step_output[i] =
574 w83627ehf_read_value(data,
575 data->REG_FAN_STEP_OUTPUT[i]);
576
Rudolf Marek08c79952006-07-05 18:14:31 +0200577 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200578 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200579 W83627EHF_REG_TARGET[i]) &
580 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
581 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
582 & 0x0f;
583 }
584
Jean Delvare08e7e272005-04-25 22:43:25 +0200585 /* Measured temperatures and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200586 data->temp1 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200587 W83627EHF_REG_TEMP1);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200588 data->temp1_max = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200589 W83627EHF_REG_TEMP1_OVER);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200590 data->temp1_max_hyst = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200591 W83627EHF_REG_TEMP1_HYST);
592 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200593 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200594 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200595 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200596 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200597 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200598 W83627EHF_REG_TEMP_HYST[i]);
599 }
600
David Hubbard1ea6dd32007-06-24 11:16:15 +0200601 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100602 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200603 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100604 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200605 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100606 W83627EHF_REG_ALARM3) << 16);
607
Jean Delvare08e7e272005-04-25 22:43:25 +0200608 data->last_updated = jiffies;
609 data->valid = 1;
610 }
611
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100612 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200613 return data;
614}
615
616/*
617 * Sysfs callback functions
618 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100619#define show_in_reg(reg) \
620static ssize_t \
621show_##reg(struct device *dev, struct device_attribute *attr, \
622 char *buf) \
623{ \
624 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
625 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
626 int nr = sensor_attr->index; \
627 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
628}
629show_in_reg(in)
630show_in_reg(in_min)
631show_in_reg(in_max)
632
633#define store_in_reg(REG, reg) \
634static ssize_t \
635store_in_##reg (struct device *dev, struct device_attribute *attr, \
636 const char *buf, size_t count) \
637{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200638 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100639 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
640 int nr = sensor_attr->index; \
641 u32 val = simple_strtoul(buf, NULL, 10); \
642 \
643 mutex_lock(&data->update_lock); \
644 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200645 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100646 data->in_##reg[nr]); \
647 mutex_unlock(&data->update_lock); \
648 return count; \
649}
650
651store_in_reg(MIN, min)
652store_in_reg(MAX, max)
653
Jean Delvarea4589db2006-03-23 16:30:29 +0100654static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
655{
656 struct w83627ehf_data *data = w83627ehf_update_device(dev);
657 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
658 int nr = sensor_attr->index;
659 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
660}
661
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100662static struct sensor_device_attribute sda_in_input[] = {
663 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
664 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
665 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
666 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
667 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
668 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
669 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
670 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
671 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
672 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
673};
674
Jean Delvarea4589db2006-03-23 16:30:29 +0100675static struct sensor_device_attribute sda_in_alarm[] = {
676 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
677 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
678 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
679 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
680 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
681 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
682 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
683 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
684 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
685 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
686};
687
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100688static struct sensor_device_attribute sda_in_min[] = {
689 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
690 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
691 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
692 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
693 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
694 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
695 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
696 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
697 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
698 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
699};
700
701static struct sensor_device_attribute sda_in_max[] = {
702 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
703 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
704 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
705 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
706 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
707 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
708 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
709 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
710 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
711 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
712};
713
Jean Delvare08e7e272005-04-25 22:43:25 +0200714#define show_fan_reg(reg) \
715static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100716show_##reg(struct device *dev, struct device_attribute *attr, \
717 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200718{ \
719 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100720 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
721 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200722 return sprintf(buf, "%d\n", \
723 fan_from_reg(data->reg[nr], \
724 div_from_reg(data->fan_div[nr]))); \
725}
726show_fan_reg(fan);
727show_fan_reg(fan_min);
728
729static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100730show_fan_div(struct device *dev, struct device_attribute *attr,
731 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200732{
733 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100734 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
735 int nr = sensor_attr->index;
736 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200737}
738
739static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100740store_fan_min(struct device *dev, struct device_attribute *attr,
741 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200742{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200743 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100744 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
745 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200746 unsigned int val = simple_strtoul(buf, NULL, 10);
747 unsigned int reg;
748 u8 new_div;
749
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100750 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200751 if (!val) {
752 /* No min limit, alarm disabled */
753 data->fan_min[nr] = 255;
754 new_div = data->fan_div[nr]; /* No change */
755 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
756 } else if ((reg = 1350000U / val) >= 128 * 255) {
757 /* Speed below this value cannot possibly be represented,
758 even with the highest divider (128) */
759 data->fan_min[nr] = 254;
760 new_div = 7; /* 128 == (1 << 7) */
761 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
762 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
763 } else if (!reg) {
764 /* Speed above this value cannot possibly be represented,
765 even with the lowest divider (1) */
766 data->fan_min[nr] = 1;
767 new_div = 0; /* 1 == (1 << 0) */
768 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200769 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200770 } else {
771 /* Automatically pick the best divider, i.e. the one such
772 that the min limit will correspond to a register value
773 in the 96..192 range */
774 new_div = 0;
775 while (reg > 192 && new_div < 7) {
776 reg >>= 1;
777 new_div++;
778 }
779 data->fan_min[nr] = reg;
780 }
781
782 /* Write both the fan clock divider (if it changed) and the new
783 fan min (unconditionally) */
784 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200785 /* Preserve the fan speed reading */
786 if (data->fan[nr] != 0xff) {
787 if (new_div > data->fan_div[nr])
788 data->fan[nr] >>= new_div - data->fan_div[nr];
789 else if (data->fan[nr] & 0x80)
790 data->fan[nr] = 0xff;
791 else
792 data->fan[nr] <<= data->fan_div[nr] - new_div;
793 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200794
795 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
796 nr + 1, div_from_reg(data->fan_div[nr]),
797 div_from_reg(new_div));
798 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200799 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200800 /* Give the chip time to sample a new speed value */
801 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200802 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200803 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200804 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100805 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200806
807 return count;
808}
809
Yuan Mu412fec82006-02-05 23:24:16 +0100810static struct sensor_device_attribute sda_fan_input[] = {
811 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
812 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
813 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
814 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
815 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
816};
Jean Delvare08e7e272005-04-25 22:43:25 +0200817
Jean Delvarea4589db2006-03-23 16:30:29 +0100818static struct sensor_device_attribute sda_fan_alarm[] = {
819 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
820 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
821 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
822 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
823 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
824};
825
Yuan Mu412fec82006-02-05 23:24:16 +0100826static struct sensor_device_attribute sda_fan_min[] = {
827 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
828 store_fan_min, 0),
829 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
830 store_fan_min, 1),
831 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
832 store_fan_min, 2),
833 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
834 store_fan_min, 3),
835 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
836 store_fan_min, 4),
837};
Jean Delvare08e7e272005-04-25 22:43:25 +0200838
Yuan Mu412fec82006-02-05 23:24:16 +0100839static struct sensor_device_attribute sda_fan_div[] = {
840 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
841 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
842 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
843 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
844 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
845};
Jean Delvare08e7e272005-04-25 22:43:25 +0200846
Jean Delvare08e7e272005-04-25 22:43:25 +0200847#define show_temp1_reg(reg) \
848static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700849show_##reg(struct device *dev, struct device_attribute *attr, \
850 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200851{ \
852 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
853 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
854}
855show_temp1_reg(temp1);
856show_temp1_reg(temp1_max);
857show_temp1_reg(temp1_max_hyst);
858
859#define store_temp1_reg(REG, reg) \
860static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700861store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
862 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200863{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200864 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200865 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200866 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100867 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200868 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200869 w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
Jean Delvare08e7e272005-04-25 22:43:25 +0200870 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100871 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200872 return count; \
873}
874store_temp1_reg(OVER, max);
875store_temp1_reg(HYST, max_hyst);
876
Jean Delvare08e7e272005-04-25 22:43:25 +0200877#define show_temp_reg(reg) \
878static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100879show_##reg(struct device *dev, struct device_attribute *attr, \
880 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200881{ \
882 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100883 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
884 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200885 return sprintf(buf, "%d\n", \
886 LM75_TEMP_FROM_REG(data->reg[nr])); \
887}
888show_temp_reg(temp);
889show_temp_reg(temp_max);
890show_temp_reg(temp_max_hyst);
891
892#define store_temp_reg(REG, reg) \
893static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100894store_##reg(struct device *dev, struct device_attribute *attr, \
895 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200896{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200897 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100898 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
899 int nr = sensor_attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200900 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200901 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100902 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200903 data->reg[nr] = LM75_TEMP_TO_REG(val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200904 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200905 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100906 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200907 return count; \
908}
909store_temp_reg(OVER, temp_max);
910store_temp_reg(HYST, temp_max_hyst);
911
Jean Delvareda667362007-06-24 11:21:02 +0200912static ssize_t
913show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
914{
915 struct w83627ehf_data *data = w83627ehf_update_device(dev);
916 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
917 int nr = sensor_attr->index;
918 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
919}
920
Gong Juna157d062009-03-30 21:46:43 +0200921static struct sensor_device_attribute sda_temp_input[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100922 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
923 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
924 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
Gong Juna157d062009-03-30 21:46:43 +0200925};
926
927static struct sensor_device_attribute sda_temp_max[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100928 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
929 store_temp1_max, 0),
930 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
931 store_temp_max, 0),
932 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
933 store_temp_max, 1),
Gong Juna157d062009-03-30 21:46:43 +0200934};
935
936static struct sensor_device_attribute sda_temp_max_hyst[] = {
Yuan Mu412fec82006-02-05 23:24:16 +0100937 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
938 store_temp1_max_hyst, 0),
939 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
940 store_temp_max_hyst, 0),
941 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
942 store_temp_max_hyst, 1),
Gong Juna157d062009-03-30 21:46:43 +0200943};
944
945static struct sensor_device_attribute sda_temp_alarm[] = {
Jean Delvarea4589db2006-03-23 16:30:29 +0100946 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
947 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
948 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Gong Juna157d062009-03-30 21:46:43 +0200949};
950
951static struct sensor_device_attribute sda_temp_type[] = {
Jean Delvareda667362007-06-24 11:21:02 +0200952 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
953 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
954 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100955};
Jean Delvare08e7e272005-04-25 22:43:25 +0200956
Rudolf Marek08c79952006-07-05 18:14:31 +0200957#define show_pwm_reg(reg) \
958static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
959 char *buf) \
960{ \
961 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
962 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
963 int nr = sensor_attr->index; \
964 return sprintf(buf, "%d\n", data->reg[nr]); \
965}
966
967show_pwm_reg(pwm_mode)
968show_pwm_reg(pwm_enable)
969show_pwm_reg(pwm)
970
971static ssize_t
972store_pwm_mode(struct device *dev, struct device_attribute *attr,
973 const char *buf, size_t count)
974{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200975 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200976 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
977 int nr = sensor_attr->index;
978 u32 val = simple_strtoul(buf, NULL, 10);
979 u16 reg;
980
981 if (val > 1)
982 return -EINVAL;
983 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200984 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200985 data->pwm_mode[nr] = val;
986 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
987 if (!val)
988 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200989 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200990 mutex_unlock(&data->update_lock);
991 return count;
992}
993
994static ssize_t
995store_pwm(struct device *dev, struct device_attribute *attr,
996 const char *buf, size_t count)
997{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200998 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200999 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1000 int nr = sensor_attr->index;
1001 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
1002
1003 mutex_lock(&data->update_lock);
1004 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001005 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001006 mutex_unlock(&data->update_lock);
1007 return count;
1008}
1009
1010static ssize_t
1011store_pwm_enable(struct device *dev, struct device_attribute *attr,
1012 const char *buf, size_t count)
1013{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001014 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001015 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1016 int nr = sensor_attr->index;
1017 u32 val = simple_strtoul(buf, NULL, 10);
1018 u16 reg;
1019
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001020 if (!val || (val > 4))
Rudolf Marek08c79952006-07-05 18:14:31 +02001021 return -EINVAL;
1022 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001023 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001024 data->pwm_enable[nr] = val;
1025 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
1026 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +02001027 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001028 mutex_unlock(&data->update_lock);
1029 return count;
1030}
1031
1032
1033#define show_tol_temp(reg) \
1034static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1035 char *buf) \
1036{ \
1037 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1038 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1039 int nr = sensor_attr->index; \
1040 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
1041}
1042
1043show_tol_temp(tolerance)
1044show_tol_temp(target_temp)
1045
1046static ssize_t
1047store_target_temp(struct device *dev, struct device_attribute *attr,
1048 const char *buf, size_t count)
1049{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001050 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001051 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1052 int nr = sensor_attr->index;
1053 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
1054
1055 mutex_lock(&data->update_lock);
1056 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001057 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +02001058 mutex_unlock(&data->update_lock);
1059 return count;
1060}
1061
1062static ssize_t
1063store_tolerance(struct device *dev, struct device_attribute *attr,
1064 const char *buf, size_t count)
1065{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001066 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001067 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1068 int nr = sensor_attr->index;
1069 u16 reg;
1070 /* Limit the temp to 0C - 15C */
1071 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
1072
1073 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001074 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001075 data->tolerance[nr] = val;
1076 if (nr == 1)
1077 reg = (reg & 0x0f) | (val << 4);
1078 else
1079 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001080 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001081 mutex_unlock(&data->update_lock);
1082 return count;
1083}
1084
1085static struct sensor_device_attribute sda_pwm[] = {
1086 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1087 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1088 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1089 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1090};
1091
1092static struct sensor_device_attribute sda_pwm_mode[] = {
1093 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1094 store_pwm_mode, 0),
1095 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1096 store_pwm_mode, 1),
1097 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1098 store_pwm_mode, 2),
1099 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1100 store_pwm_mode, 3),
1101};
1102
1103static struct sensor_device_attribute sda_pwm_enable[] = {
1104 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1105 store_pwm_enable, 0),
1106 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1107 store_pwm_enable, 1),
1108 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1109 store_pwm_enable, 2),
1110 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1111 store_pwm_enable, 3),
1112};
1113
1114static struct sensor_device_attribute sda_target_temp[] = {
1115 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1116 store_target_temp, 0),
1117 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1118 store_target_temp, 1),
1119 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1120 store_target_temp, 2),
1121 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1122 store_target_temp, 3),
1123};
1124
1125static struct sensor_device_attribute sda_tolerance[] = {
1126 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1127 store_tolerance, 0),
1128 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1129 store_tolerance, 1),
1130 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1131 store_tolerance, 2),
1132 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1133 store_tolerance, 3),
1134};
1135
Rudolf Marek08c79952006-07-05 18:14:31 +02001136/* Smart Fan registers */
1137
1138#define fan_functions(reg, REG) \
1139static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1140 char *buf) \
1141{ \
1142 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1143 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1144 int nr = sensor_attr->index; \
1145 return sprintf(buf, "%d\n", data->reg[nr]); \
1146}\
1147static ssize_t \
1148store_##reg(struct device *dev, struct device_attribute *attr, \
1149 const char *buf, size_t count) \
1150{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001151 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001152 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1153 int nr = sensor_attr->index; \
1154 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1155 mutex_lock(&data->update_lock); \
1156 data->reg[nr] = val; \
Guenter Roeckda2e0252010-08-14 21:08:55 +02001157 w83627ehf_write_value(data, data->REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001158 mutex_unlock(&data->update_lock); \
1159 return count; \
1160}
1161
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001162fan_functions(fan_start_output, FAN_START_OUTPUT)
1163fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
1164fan_functions(fan_max_output, FAN_MAX_OUTPUT)
1165fan_functions(fan_step_output, FAN_STEP_OUTPUT)
Rudolf Marek08c79952006-07-05 18:14:31 +02001166
1167#define fan_time_functions(reg, REG) \
1168static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1169 char *buf) \
1170{ \
1171 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1172 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1173 int nr = sensor_attr->index; \
1174 return sprintf(buf, "%d\n", \
1175 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1176} \
1177\
1178static ssize_t \
1179store_##reg(struct device *dev, struct device_attribute *attr, \
1180 const char *buf, size_t count) \
1181{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001182 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001183 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1184 int nr = sensor_attr->index; \
1185 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1186 data->pwm_mode[nr]); \
1187 mutex_lock(&data->update_lock); \
1188 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001189 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001190 mutex_unlock(&data->update_lock); \
1191 return count; \
1192} \
1193
1194fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1195
David Hubbard1ea6dd32007-06-24 11:16:15 +02001196static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1197 char *buf)
1198{
1199 struct w83627ehf_data *data = dev_get_drvdata(dev);
1200
1201 return sprintf(buf, "%s\n", data->name);
1202}
1203static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001204
1205static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1206 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1207 store_fan_stop_time, 3),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001208 SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1209 store_fan_start_output, 3),
1210 SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1211 store_fan_stop_output, 3),
1212 SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1213 store_fan_max_output, 3),
1214 SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1215 store_fan_step_output, 3),
Rudolf Marek08c79952006-07-05 18:14:31 +02001216};
1217
1218static struct sensor_device_attribute sda_sf3_arrays[] = {
1219 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1220 store_fan_stop_time, 0),
1221 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1222 store_fan_stop_time, 1),
1223 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1224 store_fan_stop_time, 2),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001225 SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1226 store_fan_start_output, 0),
1227 SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1228 store_fan_start_output, 1),
1229 SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
1230 store_fan_start_output, 2),
1231 SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1232 store_fan_stop_output, 0),
1233 SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1234 store_fan_stop_output, 1),
1235 SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
1236 store_fan_stop_output, 2),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001237};
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001238
Guenter Roeckda2e0252010-08-14 21:08:55 +02001239
1240/*
1241 * pwm1 and pwm3 don't support max and step settings on all chips.
1242 * Need to check support while generating/removing attribute files.
1243 */
1244static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1245 SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1246 store_fan_max_output, 0),
1247 SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1248 store_fan_step_output, 0),
Daniel J Blueman41e9a062009-12-14 18:01:37 -08001249 SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1250 store_fan_max_output, 1),
1251 SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1252 store_fan_step_output, 1),
Guenter Roeckda2e0252010-08-14 21:08:55 +02001253 SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1254 store_fan_max_output, 2),
1255 SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1256 store_fan_step_output, 2),
Rudolf Marek08c79952006-07-05 18:14:31 +02001257};
1258
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001259static ssize_t
1260show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1261{
1262 struct w83627ehf_data *data = dev_get_drvdata(dev);
1263 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1264}
1265static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1266
Jean Delvare08e7e272005-04-25 22:43:25 +02001267/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001268 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001269 */
1270
David Hubbardc18beb52006-09-24 21:04:38 +02001271static void w83627ehf_device_remove_files(struct device *dev)
1272{
1273 /* some entries in the following arrays may not have been used in
1274 * device_create_file(), but device_remove_file() will ignore them */
1275 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001276 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001277
1278 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1279 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
Guenter Roeckda2e0252010-08-14 21:08:55 +02001280 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1281 struct sensor_device_attribute *attr =
1282 &sda_sf3_max_step_arrays[i];
1283 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1284 device_remove_file(dev, &attr->dev_attr);
1285 }
David Hubbardc18beb52006-09-24 21:04:38 +02001286 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1287 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001288 for (i = 0; i < data->in_num; i++) {
Gong Juna157d062009-03-30 21:46:43 +02001289 if ((i == 6) && data->in6_skip)
1290 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001291 device_remove_file(dev, &sda_in_input[i].dev_attr);
1292 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1293 device_remove_file(dev, &sda_in_min[i].dev_attr);
1294 device_remove_file(dev, &sda_in_max[i].dev_attr);
1295 }
1296 for (i = 0; i < 5; i++) {
1297 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1298 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1299 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1300 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1301 }
Gong Jun237c8d22009-03-30 21:46:42 +02001302 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001303 device_remove_file(dev, &sda_pwm[i].dev_attr);
1304 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1305 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1306 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1307 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1308 }
Gong Juna157d062009-03-30 21:46:43 +02001309 for (i = 0; i < 3; i++) {
1310 if ((i == 2) && data->temp3_disable)
1311 continue;
1312 device_remove_file(dev, &sda_temp_input[i].dev_attr);
1313 device_remove_file(dev, &sda_temp_max[i].dev_attr);
1314 device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1315 device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1316 device_remove_file(dev, &sda_temp_type[i].dev_attr);
1317 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001318
1319 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001320 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001321}
1322
David Hubbard1ea6dd32007-06-24 11:16:15 +02001323/* Get the monitoring functions started */
1324static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001325{
1326 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001327 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001328
1329 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001330 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001331 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001332 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001333 tmp | 0x01);
1334
1335 /* Enable temp2 and temp3 if needed */
1336 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001337 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001338 W83627EHF_REG_TEMP_CONFIG[i]);
Gong Juna157d062009-03-30 21:46:43 +02001339 if ((i == 1) && data->temp3_disable)
1340 continue;
Jean Delvare08e7e272005-04-25 22:43:25 +02001341 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001342 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001343 W83627EHF_REG_TEMP_CONFIG[i],
1344 tmp & 0xfe);
1345 }
Jean Delvared3130f02007-06-24 11:20:13 +02001346
1347 /* Enable VBAT monitoring if needed */
1348 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1349 if (!(tmp & 0x01))
1350 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001351
1352 /* Get thermal sensor types */
1353 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1354 for (i = 0; i < 3; i++) {
1355 if ((tmp & (0x02 << i)))
1356 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1357 else
1358 data->temp_type[i] = 4; /* thermistor */
1359 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001360}
1361
David Hubbard1ea6dd32007-06-24 11:16:15 +02001362static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001363{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001364 struct device *dev = &pdev->dev;
1365 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001366 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001367 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001368 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001369 int i, err = 0;
1370
David Hubbard1ea6dd32007-06-24 11:16:15 +02001371 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1372 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001373 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001374 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1375 (unsigned long)res->start,
1376 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001377 goto exit;
1378 }
1379
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001380 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001381 err = -ENOMEM;
1382 goto exit_release;
1383 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001384
David Hubbard1ea6dd32007-06-24 11:16:15 +02001385 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001386 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001387 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001388 data->name = w83627ehf_device_names[sio_data->kind];
1389 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001390
Gong Jun237c8d22009-03-30 21:46:42 +02001391 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1392 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1393 /* 667HG has 3 pwms */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001394 data->pwm_num = (sio_data->kind == w83667hg
1395 || sio_data->kind == w83667hg_b) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001396
Gong Juna157d062009-03-30 21:46:43 +02001397 /* Check temp3 configuration bit for 667HG */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001398 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Juna157d062009-03-30 21:46:43 +02001399 data->temp3_disable = w83627ehf_read_value(data,
1400 W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
1401 data->in6_skip = !data->temp3_disable;
1402 }
1403
Guenter Roeckda2e0252010-08-14 21:08:55 +02001404 data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
1405 data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001406 if (sio_data->kind == w83667hg_b) {
1407 data->REG_FAN_MAX_OUTPUT =
1408 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1409 data->REG_FAN_STEP_OUTPUT =
1410 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1411 } else {
1412 data->REG_FAN_MAX_OUTPUT =
1413 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1414 data->REG_FAN_STEP_OUTPUT =
1415 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1416 }
Guenter Roeckda2e0252010-08-14 21:08:55 +02001417
Jean Delvare08e7e272005-04-25 22:43:25 +02001418 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001419 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001420
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001421 data->vrm = vid_which_vrm();
1422 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001423 /* Read VID value */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001424 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d22009-03-30 21:46:42 +02001425 /* W83667HG has different pins for VID input and output, so
1426 we can get the VID input values directly at logical device D
1427 0xe3. */
1428 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1429 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001430 err = device_create_file(dev, &dev_attr_cpu0_vid);
1431 if (err)
1432 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001433 } else {
Gong Jun237c8d22009-03-30 21:46:42 +02001434 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1435 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1436 /* Set VID input sensibility if needed. In theory the
1437 BIOS should have set it, but in practice it's not
1438 always the case. We only do it for the W83627EHF/EHG
1439 because the W83627DHG is more complex in this
1440 respect. */
1441 if (sio_data->kind == w83627ehf) {
1442 en_vrm10 = superio_inb(sio_data->sioreg,
1443 SIO_REG_EN_VRM10);
1444 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1445 dev_warn(dev, "Setting VID input "
1446 "voltage to TTL\n");
1447 superio_outb(sio_data->sioreg,
1448 SIO_REG_EN_VRM10,
1449 en_vrm10 & ~0x08);
1450 } else if (!(en_vrm10 & 0x08)
1451 && data->vrm == 100) {
1452 dev_warn(dev, "Setting VID input "
1453 "voltage to VRM10\n");
1454 superio_outb(sio_data->sioreg,
1455 SIO_REG_EN_VRM10,
1456 en_vrm10 | 0x08);
1457 }
1458 }
1459
1460 data->vid = superio_inb(sio_data->sioreg,
1461 SIO_REG_VID_DATA);
1462 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1463 data->vid &= 0x3f;
1464
1465 err = device_create_file(dev, &dev_attr_cpu0_vid);
1466 if (err)
1467 goto exit_release;
1468 } else {
1469 dev_info(dev, "VID pins in output mode, CPU VID not "
1470 "available\n");
1471 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001472 }
1473
Rudolf Marek08c79952006-07-05 18:14:31 +02001474 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001475 if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
Gong Jun237c8d22009-03-30 21:46:42 +02001476 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1477 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1478 } else {
1479 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1480 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1481 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001482 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001483
Jean Delvare08e7e272005-04-25 22:43:25 +02001484 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001485 as fan on/off switches, but fan5 control is write only :/
1486 We assume that if the serial interface is disabled, designers
1487 connected fan5 as input unless they are emitting log 1, which
1488 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001489
Jean Delvare08e7e272005-04-25 22:43:25 +02001490 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001491 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001492 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001493 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001494 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001495 data->has_fan |= (1 << 4);
1496
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001497 /* Read fan clock dividers immediately */
1498 w83627ehf_update_fan_div(data);
1499
Jean Delvare08e7e272005-04-25 22:43:25 +02001500 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001501 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001502 if ((err = device_create_file(dev,
1503 &sda_sf3_arrays[i].dev_attr)))
1504 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001505
Guenter Roeckda2e0252010-08-14 21:08:55 +02001506 for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1507 struct sensor_device_attribute *attr =
1508 &sda_sf3_max_step_arrays[i];
1509 if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
1510 err = device_create_file(dev, &attr->dev_attr);
1511 if (err)
1512 goto exit_remove;
1513 }
1514 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001515 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d22009-03-30 21:46:42 +02001516 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001517 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1518 if ((err = device_create_file(dev,
1519 &sda_sf3_arrays_fan4[i].dev_attr)))
1520 goto exit_remove;
1521 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001522
Gong Juna157d062009-03-30 21:46:43 +02001523 for (i = 0; i < data->in_num; i++) {
1524 if ((i == 6) && data->in6_skip)
1525 continue;
David Hubbardc18beb52006-09-24 21:04:38 +02001526 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1527 || (err = device_create_file(dev,
1528 &sda_in_alarm[i].dev_attr))
1529 || (err = device_create_file(dev,
1530 &sda_in_min[i].dev_attr))
1531 || (err = device_create_file(dev,
1532 &sda_in_max[i].dev_attr)))
1533 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001534 }
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001535
Yuan Mu412fec82006-02-05 23:24:16 +01001536 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001537 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001538 if ((err = device_create_file(dev,
1539 &sda_fan_input[i].dev_attr))
1540 || (err = device_create_file(dev,
1541 &sda_fan_alarm[i].dev_attr))
1542 || (err = device_create_file(dev,
1543 &sda_fan_div[i].dev_attr))
1544 || (err = device_create_file(dev,
1545 &sda_fan_min[i].dev_attr)))
1546 goto exit_remove;
Gong Jun237c8d22009-03-30 21:46:42 +02001547 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001548 ((err = device_create_file(dev,
1549 &sda_pwm[i].dev_attr))
1550 || (err = device_create_file(dev,
1551 &sda_pwm_mode[i].dev_attr))
1552 || (err = device_create_file(dev,
1553 &sda_pwm_enable[i].dev_attr))
1554 || (err = device_create_file(dev,
1555 &sda_target_temp[i].dev_attr))
1556 || (err = device_create_file(dev,
1557 &sda_tolerance[i].dev_attr))))
1558 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001559 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001560 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001561
Gong Juna157d062009-03-30 21:46:43 +02001562 for (i = 0; i < 3; i++) {
1563 if ((i == 2) && data->temp3_disable)
1564 continue;
1565 if ((err = device_create_file(dev,
1566 &sda_temp_input[i].dev_attr))
1567 || (err = device_create_file(dev,
1568 &sda_temp_max[i].dev_attr))
1569 || (err = device_create_file(dev,
1570 &sda_temp_max_hyst[i].dev_attr))
1571 || (err = device_create_file(dev,
1572 &sda_temp_alarm[i].dev_attr))
1573 || (err = device_create_file(dev,
1574 &sda_temp_type[i].dev_attr)))
David Hubbardc18beb52006-09-24 21:04:38 +02001575 goto exit_remove;
Gong Juna157d062009-03-30 21:46:43 +02001576 }
David Hubbardc18beb52006-09-24 21:04:38 +02001577
David Hubbard1ea6dd32007-06-24 11:16:15 +02001578 err = device_create_file(dev, &dev_attr_name);
1579 if (err)
1580 goto exit_remove;
1581
Tony Jones1beeffe2007-08-20 13:46:20 -07001582 data->hwmon_dev = hwmon_device_register(dev);
1583 if (IS_ERR(data->hwmon_dev)) {
1584 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001585 goto exit_remove;
1586 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001587
1588 return 0;
1589
David Hubbardc18beb52006-09-24 21:04:38 +02001590exit_remove:
1591 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001592 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001593 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001594exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001595 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001596exit:
1597 return err;
1598}
1599
David Hubbard1ea6dd32007-06-24 11:16:15 +02001600static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001601{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001602 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001603
Tony Jones1beeffe2007-08-20 13:46:20 -07001604 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001605 w83627ehf_device_remove_files(&pdev->dev);
1606 release_region(data->addr, IOREGION_LENGTH);
1607 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001608 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001609
1610 return 0;
1611}
1612
David Hubbard1ea6dd32007-06-24 11:16:15 +02001613static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001614 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001615 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001616 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001617 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001618 .probe = w83627ehf_probe,
1619 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001620};
1621
David Hubbard1ea6dd32007-06-24 11:16:15 +02001622/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1623static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1624 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001625{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001626 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1627 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1628 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001629 static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
Gong Jun237c8d22009-03-30 21:46:42 +02001630 static const char __initdata sio_name_W83667HG[] = "W83667HG";
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001631 static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001632
Jean Delvare08e7e272005-04-25 22:43:25 +02001633 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001634 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001635
David Hubbard1ea6dd32007-06-24 11:16:15 +02001636 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001637
Jean Delvare67b671b2007-12-06 23:13:42 +01001638 if (force_id)
1639 val = force_id;
1640 else
1641 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1642 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001643 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001644 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001645 sio_data->kind = w83627ehf;
1646 sio_name = sio_name_W83627EHF;
1647 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001648 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001649 sio_data->kind = w83627ehf;
1650 sio_name = sio_name_W83627EHG;
1651 break;
1652 case SIO_W83627DHG_ID:
1653 sio_data->kind = w83627dhg;
1654 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001655 break;
Jean Delvarec1e48dc2009-06-15 18:39:50 +02001656 case SIO_W83627DHG_P_ID:
1657 sio_data->kind = w83627dhg_p;
1658 sio_name = sio_name_W83627DHG_P;
1659 break;
Gong Jun237c8d22009-03-30 21:46:42 +02001660 case SIO_W83667HG_ID:
1661 sio_data->kind = w83667hg;
1662 sio_name = sio_name_W83667HG;
1663 break;
Guenter Roeckc39aeda2010-08-14 21:08:55 +02001664 case SIO_W83667HG_B_ID:
1665 sio_data->kind = w83667hg_b;
1666 sio_name = sio_name_W83667HG_B;
1667 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001668 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001669 if (val != 0xffff)
1670 pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
1671 val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001672 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001673 return -ENODEV;
1674 }
1675
David Hubbard1ea6dd32007-06-24 11:16:15 +02001676 /* We have a known chip, find the HWM I/O address */
1677 superio_select(sioaddr, W83627EHF_LD_HWM);
1678 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1679 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001680 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001681 if (*addr == 0) {
David Hubbard475ef852007-06-24 11:17:09 +02001682 printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
1683 "device with a base I/O port 0.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001684 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001685 return -ENODEV;
1686 }
1687
1688 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001689 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001690 if (!(val & 0x01)) {
1691 printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
1692 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001693 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001694 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001695
David Hubbard1ea6dd32007-06-24 11:16:15 +02001696 superio_exit(sioaddr);
1697 pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
1698 sio_data->sioreg = sioaddr;
1699
Jean Delvare08e7e272005-04-25 22:43:25 +02001700 return 0;
1701}
1702
David Hubbard1ea6dd32007-06-24 11:16:15 +02001703/* when Super-I/O functions move to a separate file, the Super-I/O
1704 * bus will manage the lifetime of the device and this module will only keep
1705 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1706 * must keep track of the device */
1707static struct platform_device *pdev;
1708
Jean Delvare08e7e272005-04-25 22:43:25 +02001709static int __init sensors_w83627ehf_init(void)
1710{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001711 int err;
1712 unsigned short address;
1713 struct resource res;
1714 struct w83627ehf_sio_data sio_data;
1715
1716 /* initialize sio_data->kind and sio_data->sioreg.
1717 *
1718 * when Super-I/O functions move to a separate file, the Super-I/O
1719 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1720 * w83627ehf hardware monitor, and call probe() */
1721 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1722 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001723 return -ENODEV;
1724
David Hubbard1ea6dd32007-06-24 11:16:15 +02001725 err = platform_driver_register(&w83627ehf_driver);
1726 if (err)
1727 goto exit;
1728
1729 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1730 err = -ENOMEM;
1731 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1732 goto exit_unregister;
1733 }
1734
1735 err = platform_device_add_data(pdev, &sio_data,
1736 sizeof(struct w83627ehf_sio_data));
1737 if (err) {
1738 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1739 goto exit_device_put;
1740 }
1741
1742 memset(&res, 0, sizeof(res));
1743 res.name = DRVNAME;
1744 res.start = address + IOREGION_OFFSET;
1745 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1746 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001747
1748 err = acpi_check_resource_conflict(&res);
1749 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001750 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001751
David Hubbard1ea6dd32007-06-24 11:16:15 +02001752 err = platform_device_add_resources(pdev, &res, 1);
1753 if (err) {
1754 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1755 "(%d)\n", err);
1756 goto exit_device_put;
1757 }
1758
1759 /* platform_device_add calls probe() */
1760 err = platform_device_add(pdev);
1761 if (err) {
1762 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1763 err);
1764 goto exit_device_put;
1765 }
1766
1767 return 0;
1768
1769exit_device_put:
1770 platform_device_put(pdev);
1771exit_unregister:
1772 platform_driver_unregister(&w83627ehf_driver);
1773exit:
1774 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001775}
1776
1777static void __exit sensors_w83627ehf_exit(void)
1778{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001779 platform_device_unregister(pdev);
1780 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001781}
1782
1783MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1784MODULE_DESCRIPTION("W83627EHF driver");
1785MODULE_LICENSE("GPL");
1786
1787module_init(sensors_w83627ehf_init);
1788module_exit(sensors_w83627ehf_exit);