blob: 20a9332959bb2643981cbe3989cea9c065caffc7 [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>
Jean Delvare08e7e272005-04-25 22:43:25 +02008
9 Shamelessly ripped from the w83627hf driver
10 Copyright (C) 2003 Mark Studebaker
11
12 Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
13 in testing and debugging this driver.
14
Jean Delvare8dd2d2c2005-07-27 21:33:15 +020015 This driver also supports the W83627EHG, which is the lead-free
16 version of the W83627EHF.
17
Jean Delvare08e7e272005-04-25 22:43:25 +020018 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
32
33 Supports the following chips:
34
David Hubbard657c93b2007-02-14 21:15:04 +010035 Chip #vin #fan #pwm #temp chip IDs man ID
36 w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
37 0x8860 0xa1
38 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
Gong Jun237c8d2f2009-03-30 21:46:42 +020039 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
Jean Delvare08e7e272005-04-25 22:43:25 +020040*/
41
42#include <linux/module.h>
43#include <linux/init.h>
44#include <linux/slab.h>
David Hubbard1ea6dd32007-06-24 11:16:15 +020045#include <linux/jiffies.h>
46#include <linux/platform_device.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040047#include <linux/hwmon.h>
Yuan Mu412fec82006-02-05 23:24:16 +010048#include <linux/hwmon-sysfs.h>
Jean Delvarefc18d6c2007-06-24 11:19:42 +020049#include <linux/hwmon-vid.h>
Mark M. Hoffman943b0832005-07-15 21:39:18 -040050#include <linux/err.h>
Ingo Molnar9a61bf62006-01-18 23:19:26 +010051#include <linux/mutex.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010052#include <linux/acpi.h>
Jean Delvare08e7e272005-04-25 22:43:25 +020053#include <asm/io.h>
54#include "lm75.h"
55
Gong Jun237c8d2f2009-03-30 21:46:42 +020056enum kinds { w83627ehf, w83627dhg, w83667hg };
David Hubbard1ea6dd32007-06-24 11:16:15 +020057
58/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
59static const char * w83627ehf_device_names[] = {
60 "w83627ehf",
61 "w83627dhg",
Gong Jun237c8d2f2009-03-30 21:46:42 +020062 "w83667hg",
David Hubbard1ea6dd32007-06-24 11:16:15 +020063};
64
Jean Delvare67b671b2007-12-06 23:13:42 +010065static unsigned short force_id;
66module_param(force_id, ushort, 0);
67MODULE_PARM_DESC(force_id, "Override the detected device ID");
68
David Hubbard1ea6dd32007-06-24 11:16:15 +020069#define DRVNAME "w83627ehf"
Jean Delvare08e7e272005-04-25 22:43:25 +020070
71/*
72 * Super-I/O constants and functions
73 */
74
Jean Delvare08e7e272005-04-25 22:43:25 +020075#define W83627EHF_LD_HWM 0x0b
Gong Jun237c8d2f2009-03-30 21:46:42 +020076#define W83667HG_LD_VID 0x0d
Jean Delvare08e7e272005-04-25 22:43:25 +020077
78#define SIO_REG_LDSEL 0x07 /* Logical device select */
79#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020080#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
Jean Delvare08e7e272005-04-25 22:43:25 +020081#define SIO_REG_ENABLE 0x30 /* Logical device enable */
82#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
Jean Delvarefc18d6c2007-06-24 11:19:42 +020083#define SIO_REG_VID_CTRL 0xF0 /* VID control */
84#define SIO_REG_VID_DATA 0xF1 /* VID data */
Jean Delvare08e7e272005-04-25 22:43:25 +020085
David Hubbard657c93b2007-02-14 21:15:04 +010086#define SIO_W83627EHF_ID 0x8850
87#define SIO_W83627EHG_ID 0x8860
88#define SIO_W83627DHG_ID 0xa020
Gong Jun237c8d2f2009-03-30 21:46:42 +020089#define SIO_W83667HG_ID 0xa510
David Hubbard657c93b2007-02-14 21:15:04 +010090#define SIO_ID_MASK 0xFFF0
Jean Delvare08e7e272005-04-25 22:43:25 +020091
92static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +020093superio_outb(int ioreg, int reg, int val)
Jean Delvare08e7e272005-04-25 22:43:25 +020094{
David Hubbard1ea6dd32007-06-24 11:16:15 +020095 outb(reg, ioreg);
96 outb(val, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +020097}
98
99static inline int
David Hubbard1ea6dd32007-06-24 11:16:15 +0200100superio_inb(int ioreg, int reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200101{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200102 outb(reg, ioreg);
103 return inb(ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200104}
105
106static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200107superio_select(int ioreg, int ld)
Jean Delvare08e7e272005-04-25 22:43:25 +0200108{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200109 outb(SIO_REG_LDSEL, ioreg);
110 outb(ld, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200111}
112
113static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200114superio_enter(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200115{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200116 outb(0x87, ioreg);
117 outb(0x87, ioreg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200118}
119
120static inline void
David Hubbard1ea6dd32007-06-24 11:16:15 +0200121superio_exit(int ioreg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200122{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200123 outb(0x02, ioreg);
124 outb(0x02, ioreg + 1);
Jean Delvare08e7e272005-04-25 22:43:25 +0200125}
126
127/*
128 * ISA constants
129 */
130
Jean Delvare1a641fc2007-04-23 14:41:16 -0700131#define IOREGION_ALIGNMENT ~7
132#define IOREGION_OFFSET 5
133#define IOREGION_LENGTH 2
David Hubbard1ea6dd32007-06-24 11:16:15 +0200134#define ADDR_REG_OFFSET 0
135#define DATA_REG_OFFSET 1
Jean Delvare08e7e272005-04-25 22:43:25 +0200136
137#define W83627EHF_REG_BANK 0x4E
138#define W83627EHF_REG_CONFIG 0x40
David Hubbard657c93b2007-02-14 21:15:04 +0100139
140/* Not currently used:
141 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
142 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
143 * REG_MAN_ID is at port 0x4f
144 * REG_CHIP_ID is at port 0x58 */
Jean Delvare08e7e272005-04-25 22:43:25 +0200145
146static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
147static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
148
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100149/* The W83627EHF registers for nr=7,8,9 are in bank 5 */
150#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
151 (0x554 + (((nr) - 7) * 2)))
152#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
153 (0x555 + (((nr) - 7) * 2)))
154#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
155 (0x550 + (nr) - 7))
156
Jean Delvare08e7e272005-04-25 22:43:25 +0200157#define W83627EHF_REG_TEMP1 0x27
158#define W83627EHF_REG_TEMP1_HYST 0x3a
159#define W83627EHF_REG_TEMP1_OVER 0x39
160static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
161static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
162static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
163static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
164
165/* Fan clock dividers are spread over the following five registers */
166#define W83627EHF_REG_FANDIV1 0x47
167#define W83627EHF_REG_FANDIV2 0x4B
168#define W83627EHF_REG_VBAT 0x5D
169#define W83627EHF_REG_DIODE 0x59
170#define W83627EHF_REG_SMI_OVT 0x4C
171
Jean Delvarea4589db2006-03-23 16:30:29 +0100172#define W83627EHF_REG_ALARM1 0x459
173#define W83627EHF_REG_ALARM2 0x45A
174#define W83627EHF_REG_ALARM3 0x45B
175
Rudolf Marek08c79952006-07-05 18:14:31 +0200176/* SmartFan registers */
177/* DC or PWM output fan configuration */
178static const u8 W83627EHF_REG_PWM_ENABLE[] = {
179 0x04, /* SYS FAN0 output mode and PWM mode */
180 0x04, /* CPU FAN0 output mode and PWM mode */
181 0x12, /* AUX FAN mode */
182 0x62, /* CPU fan1 mode */
183};
184
185static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
186static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
187
188/* FAN Duty Cycle, be used to control */
189static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
190static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
191static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
192
193
194/* Advanced Fan control, some values are common for all fans */
195static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
196static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
197
Jean Delvare08e7e272005-04-25 22:43:25 +0200198/*
199 * Conversions
200 */
201
Rudolf Marek08c79952006-07-05 18:14:31 +0200202/* 1 is PWM mode, output in ms */
203static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
204{
205 return mode ? 100 * reg : 400 * reg;
206}
207
208static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
209{
210 return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
211 (msec + 200) / 400), 1, 255);
212}
213
Jean Delvare08e7e272005-04-25 22:43:25 +0200214static inline unsigned int
215fan_from_reg(u8 reg, unsigned int div)
216{
217 if (reg == 0 || reg == 255)
218 return 0;
219 return 1350000U / (reg * div);
220}
221
222static inline unsigned int
223div_from_reg(u8 reg)
224{
225 return 1 << reg;
226}
227
228static inline int
229temp1_from_reg(s8 reg)
230{
231 return reg * 1000;
232}
233
234static inline s8
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200235temp1_to_reg(long temp, int min, int max)
Jean Delvare08e7e272005-04-25 22:43:25 +0200236{
Rudolf Marek08c79952006-07-05 18:14:31 +0200237 if (temp <= min)
238 return min / 1000;
239 if (temp >= max)
240 return max / 1000;
Jean Delvare08e7e272005-04-25 22:43:25 +0200241 if (temp < 0)
242 return (temp - 500) / 1000;
243 return (temp + 500) / 1000;
244}
245
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100246/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
247
248static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
249
250static inline long in_from_reg(u8 reg, u8 nr)
251{
252 return reg * scale_in[nr];
253}
254
255static inline u8 in_to_reg(u32 val, u8 nr)
256{
257 return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
258}
259
Jean Delvare08e7e272005-04-25 22:43:25 +0200260/*
261 * Data structures and manipulation thereof
262 */
263
264struct w83627ehf_data {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200265 int addr; /* IO base of hw monitor block */
266 const char *name;
267
Tony Jones1beeffe2007-08-20 13:46:20 -0700268 struct device *hwmon_dev;
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100269 struct mutex lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200270
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100271 struct mutex update_lock;
Jean Delvare08e7e272005-04-25 22:43:25 +0200272 char valid; /* !=0 if following fields are valid */
273 unsigned long last_updated; /* In jiffies */
274
275 /* Register values */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200276 u8 in_num; /* number of in inputs we have */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100277 u8 in[10]; /* Register value */
278 u8 in_max[10]; /* Register value */
279 u8 in_min[10]; /* Register value */
Jean Delvare08e7e272005-04-25 22:43:25 +0200280 u8 fan[5];
281 u8 fan_min[5];
282 u8 fan_div[5];
283 u8 has_fan; /* some fan inputs can be disabled */
Jean Delvareda667362007-06-24 11:21:02 +0200284 u8 temp_type[3];
Jean Delvare08e7e272005-04-25 22:43:25 +0200285 s8 temp1;
286 s8 temp1_max;
287 s8 temp1_max_hyst;
288 s16 temp[2];
289 s16 temp_max[2];
290 s16 temp_max_hyst[2];
Jean Delvarea4589db2006-03-23 16:30:29 +0100291 u32 alarms;
Rudolf Marek08c79952006-07-05 18:14:31 +0200292
293 u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
294 u8 pwm_enable[4]; /* 1->manual
295 2->thermal cruise (also called SmartFan I) */
Gong Jun237c8d2f2009-03-30 21:46:42 +0200296 u8 pwm_num; /* number of pwm */
Rudolf Marek08c79952006-07-05 18:14:31 +0200297 u8 pwm[4];
298 u8 target_temp[4];
299 u8 tolerance[4];
300
301 u8 fan_min_output[4]; /* minimum fan speed */
302 u8 fan_stop_time[4];
Jean Delvarefc18d6c2007-06-24 11:19:42 +0200303
304 u8 vid;
305 u8 vrm;
Jean Delvare08e7e272005-04-25 22:43:25 +0200306};
307
David Hubbard1ea6dd32007-06-24 11:16:15 +0200308struct w83627ehf_sio_data {
309 int sioreg;
310 enum kinds kind;
311};
312
Jean Delvare08e7e272005-04-25 22:43:25 +0200313static inline int is_word_sized(u16 reg)
314{
315 return (((reg & 0xff00) == 0x100
316 || (reg & 0xff00) == 0x200)
317 && ((reg & 0x00ff) == 0x50
318 || (reg & 0x00ff) == 0x53
319 || (reg & 0x00ff) == 0x55));
320}
321
Jean Delvare09568952007-08-11 13:57:05 +0200322/* Registers 0x50-0x5f are banked */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200323static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200324{
Jean Delvare09568952007-08-11 13:57:05 +0200325 if ((reg & 0x00f0) == 0x50) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200326 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
327 outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200328 }
329}
330
Jean Delvare09568952007-08-11 13:57:05 +0200331/* Not strictly necessary, but play it safe for now */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200332static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200333{
334 if (reg & 0xff00) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200335 outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
336 outb_p(0, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200337 }
338}
339
David Hubbard1ea6dd32007-06-24 11:16:15 +0200340static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
Jean Delvare08e7e272005-04-25 22:43:25 +0200341{
Jean Delvare08e7e272005-04-25 22:43:25 +0200342 int res, word_sized = is_word_sized(reg);
343
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100344 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200345
David Hubbard1ea6dd32007-06-24 11:16:15 +0200346 w83627ehf_set_bank(data, reg);
347 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
348 res = inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200349 if (word_sized) {
350 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200351 data->addr + ADDR_REG_OFFSET);
352 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200353 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200354 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200355
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100356 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200357
358 return res;
359}
360
David Hubbard1ea6dd32007-06-24 11:16:15 +0200361static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
Jean Delvare08e7e272005-04-25 22:43:25 +0200362{
Jean Delvare08e7e272005-04-25 22:43:25 +0200363 int word_sized = is_word_sized(reg);
364
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100365 mutex_lock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200366
David Hubbard1ea6dd32007-06-24 11:16:15 +0200367 w83627ehf_set_bank(data, reg);
368 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200369 if (word_sized) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200370 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200371 outb_p((reg & 0xff) + 1,
David Hubbard1ea6dd32007-06-24 11:16:15 +0200372 data->addr + ADDR_REG_OFFSET);
Jean Delvare08e7e272005-04-25 22:43:25 +0200373 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200374 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
375 w83627ehf_reset_bank(data, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200376
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100377 mutex_unlock(&data->lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200378 return 0;
379}
380
381/* This function assumes that the caller holds data->update_lock */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200382static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
Jean Delvare08e7e272005-04-25 22:43:25 +0200383{
Jean Delvare08e7e272005-04-25 22:43:25 +0200384 u8 reg;
385
386 switch (nr) {
387 case 0:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200388 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200389 | ((data->fan_div[0] & 0x03) << 4);
Rudolf Marek14992c72006-10-08 22:02:09 +0200390 /* fan5 input control bit is write only, compute the value */
391 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200392 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
393 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200394 | ((data->fan_div[0] & 0x04) << 3);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200395 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200396 break;
397 case 1:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200398 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200399 | ((data->fan_div[1] & 0x03) << 6);
Rudolf Marek14992c72006-10-08 22:02:09 +0200400 /* fan5 input control bit is write only, compute the value */
401 reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200402 w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
403 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200404 | ((data->fan_div[1] & 0x04) << 4);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200405 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200406 break;
407 case 2:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200408 reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200409 | ((data->fan_div[2] & 0x03) << 6);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200410 w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
411 reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200412 | ((data->fan_div[2] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200413 w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200414 break;
415 case 3:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200416 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
Jean Delvare08e7e272005-04-25 22:43:25 +0200417 | (data->fan_div[3] & 0x03);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200418 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
419 reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
Jean Delvare08e7e272005-04-25 22:43:25 +0200420 | ((data->fan_div[3] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200421 w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200422 break;
423 case 4:
David Hubbard1ea6dd32007-06-24 11:16:15 +0200424 reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
Jean Delvare33725ad2007-04-17 00:32:27 -0700425 | ((data->fan_div[4] & 0x03) << 2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200426 | ((data->fan_div[4] & 0x04) << 5);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200427 w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
Jean Delvare08e7e272005-04-25 22:43:25 +0200428 break;
429 }
430}
431
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400432static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
433{
434 int i;
435
436 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
437 data->fan_div[0] = (i >> 4) & 0x03;
438 data->fan_div[1] = (i >> 6) & 0x03;
439 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
440 data->fan_div[2] = (i >> 6) & 0x03;
441 i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
442 data->fan_div[0] |= (i >> 3) & 0x04;
443 data->fan_div[1] |= (i >> 4) & 0x04;
444 data->fan_div[2] |= (i >> 5) & 0x04;
445 if (data->has_fan & ((1 << 3) | (1 << 4))) {
446 i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
447 data->fan_div[3] = i & 0x03;
448 data->fan_div[4] = ((i >> 2) & 0x03)
449 | ((i >> 5) & 0x04);
450 }
451 if (data->has_fan & (1 << 3)) {
452 i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
453 data->fan_div[3] |= (i >> 5) & 0x04;
454 }
455}
456
Jean Delvare08e7e272005-04-25 22:43:25 +0200457static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
458{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200459 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200460 int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
Jean Delvare08e7e272005-04-25 22:43:25 +0200461 int i;
462
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100463 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200464
Jean Delvare6b3e4642007-06-24 11:19:01 +0200465 if (time_after(jiffies, data->last_updated + HZ + HZ/2)
Jean Delvare08e7e272005-04-25 22:43:25 +0200466 || !data->valid) {
467 /* Fan clock dividers */
Mark M. Hoffmanea7be662007-08-05 12:19:01 -0400468 w83627ehf_update_fan_div(data);
Jean Delvare08e7e272005-04-25 22:43:25 +0200469
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100470 /* Measured voltages and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200471 for (i = 0; i < data->in_num; i++) {
472 data->in[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100473 W83627EHF_REG_IN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200474 data->in_min[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100475 W83627EHF_REG_IN_MIN(i));
David Hubbard1ea6dd32007-06-24 11:16:15 +0200476 data->in_max[i] = w83627ehf_read_value(data,
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100477 W83627EHF_REG_IN_MAX(i));
478 }
479
Jean Delvare08e7e272005-04-25 22:43:25 +0200480 /* Measured fan speeds and limits */
481 for (i = 0; i < 5; i++) {
482 if (!(data->has_fan & (1 << i)))
483 continue;
484
David Hubbard1ea6dd32007-06-24 11:16:15 +0200485 data->fan[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200486 W83627EHF_REG_FAN[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200487 data->fan_min[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200488 W83627EHF_REG_FAN_MIN[i]);
489
490 /* If we failed to measure the fan speed and clock
491 divider can be increased, let's try that for next
492 time */
493 if (data->fan[i] == 0xff
494 && data->fan_div[i] < 0x07) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200495 dev_dbg(dev, "Increasing fan%d "
Jean Delvare08e7e272005-04-25 22:43:25 +0200496 "clock divider from %u to %u\n",
Jean Delvare33725ad2007-04-17 00:32:27 -0700497 i + 1, div_from_reg(data->fan_div[i]),
Jean Delvare08e7e272005-04-25 22:43:25 +0200498 div_from_reg(data->fan_div[i] + 1));
499 data->fan_div[i]++;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200500 w83627ehf_write_fan_div(data, i);
Jean Delvare08e7e272005-04-25 22:43:25 +0200501 /* Preserve min limit if possible */
502 if (data->fan_min[i] >= 2
503 && data->fan_min[i] != 255)
David Hubbard1ea6dd32007-06-24 11:16:15 +0200504 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200505 W83627EHF_REG_FAN_MIN[i],
506 (data->fan_min[i] /= 2));
507 }
508 }
509
Rudolf Marek08c79952006-07-05 18:14:31 +0200510 for (i = 0; i < 4; i++) {
Jean Delvare77fa49d2009-01-07 16:37:35 +0100511 /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
Rudolf Marek08c79952006-07-05 18:14:31 +0200512 if (i != 1) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200513 pwmcfg = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200514 W83627EHF_REG_PWM_ENABLE[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200515 tolerance = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200516 W83627EHF_REG_TOLERANCE[i]);
517 }
518 data->pwm_mode[i] =
519 ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
520 ? 0 : 1;
521 data->pwm_enable[i] =
522 ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
523 & 3) + 1;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200524 data->pwm[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200525 W83627EHF_REG_PWM[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200526 data->fan_min_output[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200527 W83627EHF_REG_FAN_MIN_OUTPUT[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200528 data->fan_stop_time[i] = w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200529 W83627EHF_REG_FAN_STOP_TIME[i]);
530 data->target_temp[i] =
David Hubbard1ea6dd32007-06-24 11:16:15 +0200531 w83627ehf_read_value(data,
Rudolf Marek08c79952006-07-05 18:14:31 +0200532 W83627EHF_REG_TARGET[i]) &
533 (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
534 data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
535 & 0x0f;
536 }
537
Jean Delvare08e7e272005-04-25 22:43:25 +0200538 /* Measured temperatures and limits */
David Hubbard1ea6dd32007-06-24 11:16:15 +0200539 data->temp1 = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200540 W83627EHF_REG_TEMP1);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200541 data->temp1_max = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200542 W83627EHF_REG_TEMP1_OVER);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200543 data->temp1_max_hyst = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200544 W83627EHF_REG_TEMP1_HYST);
545 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +0200546 data->temp[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200547 W83627EHF_REG_TEMP[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200548 data->temp_max[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200549 W83627EHF_REG_TEMP_OVER[i]);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200550 data->temp_max_hyst[i] = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +0200551 W83627EHF_REG_TEMP_HYST[i]);
552 }
553
David Hubbard1ea6dd32007-06-24 11:16:15 +0200554 data->alarms = w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100555 W83627EHF_REG_ALARM1) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200556 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100557 W83627EHF_REG_ALARM2) << 8) |
David Hubbard1ea6dd32007-06-24 11:16:15 +0200558 (w83627ehf_read_value(data,
Jean Delvarea4589db2006-03-23 16:30:29 +0100559 W83627EHF_REG_ALARM3) << 16);
560
Jean Delvare08e7e272005-04-25 22:43:25 +0200561 data->last_updated = jiffies;
562 data->valid = 1;
563 }
564
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100565 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200566 return data;
567}
568
569/*
570 * Sysfs callback functions
571 */
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100572#define show_in_reg(reg) \
573static ssize_t \
574show_##reg(struct device *dev, struct device_attribute *attr, \
575 char *buf) \
576{ \
577 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
578 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
579 int nr = sensor_attr->index; \
580 return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
581}
582show_in_reg(in)
583show_in_reg(in_min)
584show_in_reg(in_max)
585
586#define store_in_reg(REG, reg) \
587static ssize_t \
588store_in_##reg (struct device *dev, struct device_attribute *attr, \
589 const char *buf, size_t count) \
590{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200591 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100592 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
593 int nr = sensor_attr->index; \
594 u32 val = simple_strtoul(buf, NULL, 10); \
595 \
596 mutex_lock(&data->update_lock); \
597 data->in_##reg[nr] = in_to_reg(val, nr); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200598 w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100599 data->in_##reg[nr]); \
600 mutex_unlock(&data->update_lock); \
601 return count; \
602}
603
604store_in_reg(MIN, min)
605store_in_reg(MAX, max)
606
Jean Delvarea4589db2006-03-23 16:30:29 +0100607static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
608{
609 struct w83627ehf_data *data = w83627ehf_update_device(dev);
610 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
611 int nr = sensor_attr->index;
612 return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
613}
614
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100615static struct sensor_device_attribute sda_in_input[] = {
616 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
617 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
618 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
619 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
620 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
621 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
622 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
623 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
624 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
625 SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
626};
627
Jean Delvarea4589db2006-03-23 16:30:29 +0100628static struct sensor_device_attribute sda_in_alarm[] = {
629 SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
630 SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
631 SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
632 SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
633 SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
634 SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
635 SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
636 SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
637 SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
638 SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
639};
640
Rudolf Marekcf0676f2006-03-23 16:25:22 +0100641static struct sensor_device_attribute sda_in_min[] = {
642 SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
643 SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
644 SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
645 SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
646 SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
647 SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
648 SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
649 SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
650 SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
651 SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
652};
653
654static struct sensor_device_attribute sda_in_max[] = {
655 SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
656 SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
657 SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
658 SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
659 SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
660 SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
661 SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
662 SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
663 SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
664 SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
665};
666
Jean Delvare08e7e272005-04-25 22:43:25 +0200667#define show_fan_reg(reg) \
668static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100669show_##reg(struct device *dev, struct device_attribute *attr, \
670 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200671{ \
672 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100673 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
674 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200675 return sprintf(buf, "%d\n", \
676 fan_from_reg(data->reg[nr], \
677 div_from_reg(data->fan_div[nr]))); \
678}
679show_fan_reg(fan);
680show_fan_reg(fan_min);
681
682static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100683show_fan_div(struct device *dev, struct device_attribute *attr,
684 char *buf)
Jean Delvare08e7e272005-04-25 22:43:25 +0200685{
686 struct w83627ehf_data *data = w83627ehf_update_device(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100687 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
688 int nr = sensor_attr->index;
689 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
Jean Delvare08e7e272005-04-25 22:43:25 +0200690}
691
692static ssize_t
Yuan Mu412fec82006-02-05 23:24:16 +0100693store_fan_min(struct device *dev, struct device_attribute *attr,
694 const char *buf, size_t count)
Jean Delvare08e7e272005-04-25 22:43:25 +0200695{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200696 struct w83627ehf_data *data = dev_get_drvdata(dev);
Yuan Mu412fec82006-02-05 23:24:16 +0100697 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
698 int nr = sensor_attr->index;
Jean Delvare08e7e272005-04-25 22:43:25 +0200699 unsigned int val = simple_strtoul(buf, NULL, 10);
700 unsigned int reg;
701 u8 new_div;
702
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100703 mutex_lock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200704 if (!val) {
705 /* No min limit, alarm disabled */
706 data->fan_min[nr] = 255;
707 new_div = data->fan_div[nr]; /* No change */
708 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
709 } else if ((reg = 1350000U / val) >= 128 * 255) {
710 /* Speed below this value cannot possibly be represented,
711 even with the highest divider (128) */
712 data->fan_min[nr] = 254;
713 new_div = 7; /* 128 == (1 << 7) */
714 dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
715 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
716 } else if (!reg) {
717 /* Speed above this value cannot possibly be represented,
718 even with the lowest divider (1) */
719 data->fan_min[nr] = 1;
720 new_div = 0; /* 1 == (1 << 0) */
721 dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
Jean Delvareb9110b12005-05-02 23:08:22 +0200722 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
Jean Delvare08e7e272005-04-25 22:43:25 +0200723 } else {
724 /* Automatically pick the best divider, i.e. the one such
725 that the min limit will correspond to a register value
726 in the 96..192 range */
727 new_div = 0;
728 while (reg > 192 && new_div < 7) {
729 reg >>= 1;
730 new_div++;
731 }
732 data->fan_min[nr] = reg;
733 }
734
735 /* Write both the fan clock divider (if it changed) and the new
736 fan min (unconditionally) */
737 if (new_div != data->fan_div[nr]) {
Jean Delvare158ce072007-06-17 16:09:12 +0200738 /* Preserve the fan speed reading */
739 if (data->fan[nr] != 0xff) {
740 if (new_div > data->fan_div[nr])
741 data->fan[nr] >>= new_div - data->fan_div[nr];
742 else if (data->fan[nr] & 0x80)
743 data->fan[nr] = 0xff;
744 else
745 data->fan[nr] <<= data->fan_div[nr] - new_div;
746 }
Jean Delvare08e7e272005-04-25 22:43:25 +0200747
748 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
749 nr + 1, div_from_reg(data->fan_div[nr]),
750 div_from_reg(new_div));
751 data->fan_div[nr] = new_div;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200752 w83627ehf_write_fan_div(data, nr);
Jean Delvare6b3e4642007-06-24 11:19:01 +0200753 /* Give the chip time to sample a new speed value */
754 data->last_updated = jiffies;
Jean Delvare08e7e272005-04-25 22:43:25 +0200755 }
David Hubbard1ea6dd32007-06-24 11:16:15 +0200756 w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
Jean Delvare08e7e272005-04-25 22:43:25 +0200757 data->fan_min[nr]);
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100758 mutex_unlock(&data->update_lock);
Jean Delvare08e7e272005-04-25 22:43:25 +0200759
760 return count;
761}
762
Yuan Mu412fec82006-02-05 23:24:16 +0100763static struct sensor_device_attribute sda_fan_input[] = {
764 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
765 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
766 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
767 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
768 SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
769};
Jean Delvare08e7e272005-04-25 22:43:25 +0200770
Jean Delvarea4589db2006-03-23 16:30:29 +0100771static struct sensor_device_attribute sda_fan_alarm[] = {
772 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
773 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
774 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
775 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
776 SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
777};
778
Yuan Mu412fec82006-02-05 23:24:16 +0100779static struct sensor_device_attribute sda_fan_min[] = {
780 SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
781 store_fan_min, 0),
782 SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
783 store_fan_min, 1),
784 SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
785 store_fan_min, 2),
786 SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
787 store_fan_min, 3),
788 SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
789 store_fan_min, 4),
790};
Jean Delvare08e7e272005-04-25 22:43:25 +0200791
Yuan Mu412fec82006-02-05 23:24:16 +0100792static struct sensor_device_attribute sda_fan_div[] = {
793 SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
794 SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
795 SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
796 SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
797 SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
798};
Jean Delvare08e7e272005-04-25 22:43:25 +0200799
Jean Delvare08e7e272005-04-25 22:43:25 +0200800#define show_temp1_reg(reg) \
801static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700802show_##reg(struct device *dev, struct device_attribute *attr, \
803 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200804{ \
805 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
806 return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
807}
808show_temp1_reg(temp1);
809show_temp1_reg(temp1_max);
810show_temp1_reg(temp1_max_hyst);
811
812#define store_temp1_reg(REG, reg) \
813static ssize_t \
Greg Kroah-Hartman6f637a62005-06-21 21:01:59 -0700814store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
815 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200816{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200817 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200818 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200819 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100820 mutex_lock(&data->update_lock); \
Rudolf Marek08c79952006-07-05 18:14:31 +0200821 data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200822 w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
Jean Delvare08e7e272005-04-25 22:43:25 +0200823 data->temp1_##reg); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100824 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200825 return count; \
826}
827store_temp1_reg(OVER, max);
828store_temp1_reg(HYST, max_hyst);
829
Jean Delvare08e7e272005-04-25 22:43:25 +0200830#define show_temp_reg(reg) \
831static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100832show_##reg(struct device *dev, struct device_attribute *attr, \
833 char *buf) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200834{ \
835 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100836 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
837 int nr = sensor_attr->index; \
Jean Delvare08e7e272005-04-25 22:43:25 +0200838 return sprintf(buf, "%d\n", \
839 LM75_TEMP_FROM_REG(data->reg[nr])); \
840}
841show_temp_reg(temp);
842show_temp_reg(temp_max);
843show_temp_reg(temp_max_hyst);
844
845#define store_temp_reg(REG, reg) \
846static ssize_t \
Yuan Mu412fec82006-02-05 23:24:16 +0100847store_##reg(struct device *dev, struct device_attribute *attr, \
848 const char *buf, size_t count) \
Jean Delvare08e7e272005-04-25 22:43:25 +0200849{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200850 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Yuan Mu412fec82006-02-05 23:24:16 +0100851 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
852 int nr = sensor_attr->index; \
Christian Hohnstaedt5bfedac2007-08-16 11:40:10 +0200853 long val = simple_strtol(buf, NULL, 10); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200854 \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100855 mutex_lock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200856 data->reg[nr] = LM75_TEMP_TO_REG(val); \
David Hubbard1ea6dd32007-06-24 11:16:15 +0200857 w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
Jean Delvare08e7e272005-04-25 22:43:25 +0200858 data->reg[nr]); \
Ingo Molnar9a61bf62006-01-18 23:19:26 +0100859 mutex_unlock(&data->update_lock); \
Jean Delvare08e7e272005-04-25 22:43:25 +0200860 return count; \
861}
862store_temp_reg(OVER, temp_max);
863store_temp_reg(HYST, temp_max_hyst);
864
Jean Delvareda667362007-06-24 11:21:02 +0200865static ssize_t
866show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
867{
868 struct w83627ehf_data *data = w83627ehf_update_device(dev);
869 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
870 int nr = sensor_attr->index;
871 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
872}
873
Yuan Mu412fec82006-02-05 23:24:16 +0100874static struct sensor_device_attribute sda_temp[] = {
875 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
876 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
877 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
878 SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
879 store_temp1_max, 0),
880 SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
881 store_temp_max, 0),
882 SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
883 store_temp_max, 1),
884 SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
885 store_temp1_max_hyst, 0),
886 SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
887 store_temp_max_hyst, 0),
888 SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
889 store_temp_max_hyst, 1),
Jean Delvarea4589db2006-03-23 16:30:29 +0100890 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
891 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
892 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
Jean Delvareda667362007-06-24 11:21:02 +0200893 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
894 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
895 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
Yuan Mu412fec82006-02-05 23:24:16 +0100896};
Jean Delvare08e7e272005-04-25 22:43:25 +0200897
Rudolf Marek08c79952006-07-05 18:14:31 +0200898#define show_pwm_reg(reg) \
899static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
900 char *buf) \
901{ \
902 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
903 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
904 int nr = sensor_attr->index; \
905 return sprintf(buf, "%d\n", data->reg[nr]); \
906}
907
908show_pwm_reg(pwm_mode)
909show_pwm_reg(pwm_enable)
910show_pwm_reg(pwm)
911
912static ssize_t
913store_pwm_mode(struct device *dev, struct device_attribute *attr,
914 const char *buf, size_t count)
915{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200916 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200917 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
918 int nr = sensor_attr->index;
919 u32 val = simple_strtoul(buf, NULL, 10);
920 u16 reg;
921
922 if (val > 1)
923 return -EINVAL;
924 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200925 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200926 data->pwm_mode[nr] = val;
927 reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
928 if (!val)
929 reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200930 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200931 mutex_unlock(&data->update_lock);
932 return count;
933}
934
935static ssize_t
936store_pwm(struct device *dev, struct device_attribute *attr,
937 const char *buf, size_t count)
938{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200939 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200940 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
941 int nr = sensor_attr->index;
942 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
943
944 mutex_lock(&data->update_lock);
945 data->pwm[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200946 w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200947 mutex_unlock(&data->update_lock);
948 return count;
949}
950
951static ssize_t
952store_pwm_enable(struct device *dev, struct device_attribute *attr,
953 const char *buf, size_t count)
954{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200955 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200956 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
957 int nr = sensor_attr->index;
958 u32 val = simple_strtoul(buf, NULL, 10);
959 u16 reg;
960
961 if (!val || (val > 2)) /* only modes 1 and 2 are supported */
962 return -EINVAL;
963 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +0200964 reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +0200965 data->pwm_enable[nr] = val;
966 reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
967 reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
David Hubbard1ea6dd32007-06-24 11:16:15 +0200968 w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +0200969 mutex_unlock(&data->update_lock);
970 return count;
971}
972
973
974#define show_tol_temp(reg) \
975static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
976 char *buf) \
977{ \
978 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
979 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
980 int nr = sensor_attr->index; \
981 return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
982}
983
984show_tol_temp(tolerance)
985show_tol_temp(target_temp)
986
987static ssize_t
988store_target_temp(struct device *dev, struct device_attribute *attr,
989 const char *buf, size_t count)
990{
David Hubbard1ea6dd32007-06-24 11:16:15 +0200991 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +0200992 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
993 int nr = sensor_attr->index;
994 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
995
996 mutex_lock(&data->update_lock);
997 data->target_temp[nr] = val;
David Hubbard1ea6dd32007-06-24 11:16:15 +0200998 w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
Rudolf Marek08c79952006-07-05 18:14:31 +0200999 mutex_unlock(&data->update_lock);
1000 return count;
1001}
1002
1003static ssize_t
1004store_tolerance(struct device *dev, struct device_attribute *attr,
1005 const char *buf, size_t count)
1006{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001007 struct w83627ehf_data *data = dev_get_drvdata(dev);
Rudolf Marek08c79952006-07-05 18:14:31 +02001008 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1009 int nr = sensor_attr->index;
1010 u16 reg;
1011 /* Limit the temp to 0C - 15C */
1012 u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
1013
1014 mutex_lock(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001015 reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
Rudolf Marek08c79952006-07-05 18:14:31 +02001016 data->tolerance[nr] = val;
1017 if (nr == 1)
1018 reg = (reg & 0x0f) | (val << 4);
1019 else
1020 reg = (reg & 0xf0) | val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001021 w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001022 mutex_unlock(&data->update_lock);
1023 return count;
1024}
1025
1026static struct sensor_device_attribute sda_pwm[] = {
1027 SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
1028 SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
1029 SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
1030 SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
1031};
1032
1033static struct sensor_device_attribute sda_pwm_mode[] = {
1034 SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1035 store_pwm_mode, 0),
1036 SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1037 store_pwm_mode, 1),
1038 SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1039 store_pwm_mode, 2),
1040 SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
1041 store_pwm_mode, 3),
1042};
1043
1044static struct sensor_device_attribute sda_pwm_enable[] = {
1045 SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1046 store_pwm_enable, 0),
1047 SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1048 store_pwm_enable, 1),
1049 SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1050 store_pwm_enable, 2),
1051 SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
1052 store_pwm_enable, 3),
1053};
1054
1055static struct sensor_device_attribute sda_target_temp[] = {
1056 SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
1057 store_target_temp, 0),
1058 SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
1059 store_target_temp, 1),
1060 SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
1061 store_target_temp, 2),
1062 SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
1063 store_target_temp, 3),
1064};
1065
1066static struct sensor_device_attribute sda_tolerance[] = {
1067 SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1068 store_tolerance, 0),
1069 SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1070 store_tolerance, 1),
1071 SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1072 store_tolerance, 2),
1073 SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
1074 store_tolerance, 3),
1075};
1076
Rudolf Marek08c79952006-07-05 18:14:31 +02001077/* Smart Fan registers */
1078
1079#define fan_functions(reg, REG) \
1080static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1081 char *buf) \
1082{ \
1083 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1084 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1085 int nr = sensor_attr->index; \
1086 return sprintf(buf, "%d\n", data->reg[nr]); \
1087}\
1088static ssize_t \
1089store_##reg(struct device *dev, struct device_attribute *attr, \
1090 const char *buf, size_t count) \
1091{\
David Hubbard1ea6dd32007-06-24 11:16:15 +02001092 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001093 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1094 int nr = sensor_attr->index; \
1095 u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
1096 mutex_lock(&data->update_lock); \
1097 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001098 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001099 mutex_unlock(&data->update_lock); \
1100 return count; \
1101}
1102
1103fan_functions(fan_min_output, FAN_MIN_OUTPUT)
1104
1105#define fan_time_functions(reg, REG) \
1106static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
1107 char *buf) \
1108{ \
1109 struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1110 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1111 int nr = sensor_attr->index; \
1112 return sprintf(buf, "%d\n", \
1113 step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
1114} \
1115\
1116static ssize_t \
1117store_##reg(struct device *dev, struct device_attribute *attr, \
1118 const char *buf, size_t count) \
1119{ \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001120 struct w83627ehf_data *data = dev_get_drvdata(dev); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001121 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
1122 int nr = sensor_attr->index; \
1123 u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
1124 data->pwm_mode[nr]); \
1125 mutex_lock(&data->update_lock); \
1126 data->reg[nr] = val; \
David Hubbard1ea6dd32007-06-24 11:16:15 +02001127 w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
Rudolf Marek08c79952006-07-05 18:14:31 +02001128 mutex_unlock(&data->update_lock); \
1129 return count; \
1130} \
1131
1132fan_time_functions(fan_stop_time, FAN_STOP_TIME)
1133
David Hubbard1ea6dd32007-06-24 11:16:15 +02001134static ssize_t show_name(struct device *dev, struct device_attribute *attr,
1135 char *buf)
1136{
1137 struct w83627ehf_data *data = dev_get_drvdata(dev);
1138
1139 return sprintf(buf, "%s\n", data->name);
1140}
1141static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Rudolf Marek08c79952006-07-05 18:14:31 +02001142
1143static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
1144 SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1145 store_fan_stop_time, 3),
1146 SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1147 store_fan_min_output, 3),
1148};
1149
1150static struct sensor_device_attribute sda_sf3_arrays[] = {
1151 SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1152 store_fan_stop_time, 0),
1153 SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1154 store_fan_stop_time, 1),
1155 SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
1156 store_fan_stop_time, 2),
1157 SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1158 store_fan_min_output, 0),
1159 SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1160 store_fan_min_output, 1),
1161 SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
1162 store_fan_min_output, 2),
1163};
1164
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001165static ssize_t
1166show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1167{
1168 struct w83627ehf_data *data = dev_get_drvdata(dev);
1169 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1170}
1171static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1172
Jean Delvare08e7e272005-04-25 22:43:25 +02001173/*
David Hubbard1ea6dd32007-06-24 11:16:15 +02001174 * Driver and device management
Jean Delvare08e7e272005-04-25 22:43:25 +02001175 */
1176
David Hubbardc18beb52006-09-24 21:04:38 +02001177static void w83627ehf_device_remove_files(struct device *dev)
1178{
1179 /* some entries in the following arrays may not have been used in
1180 * device_create_file(), but device_remove_file() will ignore them */
1181 int i;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001182 struct w83627ehf_data *data = dev_get_drvdata(dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001183
1184 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1185 device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
1186 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1187 device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001188 for (i = 0; i < data->in_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001189 device_remove_file(dev, &sda_in_input[i].dev_attr);
1190 device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1191 device_remove_file(dev, &sda_in_min[i].dev_attr);
1192 device_remove_file(dev, &sda_in_max[i].dev_attr);
1193 }
1194 for (i = 0; i < 5; i++) {
1195 device_remove_file(dev, &sda_fan_input[i].dev_attr);
1196 device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1197 device_remove_file(dev, &sda_fan_div[i].dev_attr);
1198 device_remove_file(dev, &sda_fan_min[i].dev_attr);
1199 }
Gong Jun237c8d2f2009-03-30 21:46:42 +02001200 for (i = 0; i < data->pwm_num; i++) {
David Hubbardc18beb52006-09-24 21:04:38 +02001201 device_remove_file(dev, &sda_pwm[i].dev_attr);
1202 device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1203 device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1204 device_remove_file(dev, &sda_target_temp[i].dev_attr);
1205 device_remove_file(dev, &sda_tolerance[i].dev_attr);
1206 }
1207 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
1208 device_remove_file(dev, &sda_temp[i].dev_attr);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001209
1210 device_remove_file(dev, &dev_attr_name);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001211 device_remove_file(dev, &dev_attr_cpu0_vid);
David Hubbardc18beb52006-09-24 21:04:38 +02001212}
1213
David Hubbard1ea6dd32007-06-24 11:16:15 +02001214/* Get the monitoring functions started */
1215static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001216{
1217 int i;
Jean Delvareda667362007-06-24 11:21:02 +02001218 u8 tmp, diode;
Jean Delvare08e7e272005-04-25 22:43:25 +02001219
1220 /* Start monitoring is needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001221 tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
Jean Delvare08e7e272005-04-25 22:43:25 +02001222 if (!(tmp & 0x01))
David Hubbard1ea6dd32007-06-24 11:16:15 +02001223 w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
Jean Delvare08e7e272005-04-25 22:43:25 +02001224 tmp | 0x01);
1225
1226 /* Enable temp2 and temp3 if needed */
1227 for (i = 0; i < 2; i++) {
David Hubbard1ea6dd32007-06-24 11:16:15 +02001228 tmp = w83627ehf_read_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001229 W83627EHF_REG_TEMP_CONFIG[i]);
1230 if (tmp & 0x01)
David Hubbard1ea6dd32007-06-24 11:16:15 +02001231 w83627ehf_write_value(data,
Jean Delvare08e7e272005-04-25 22:43:25 +02001232 W83627EHF_REG_TEMP_CONFIG[i],
1233 tmp & 0xfe);
1234 }
Jean Delvared3130f02007-06-24 11:20:13 +02001235
1236 /* Enable VBAT monitoring if needed */
1237 tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1238 if (!(tmp & 0x01))
1239 w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
Jean Delvareda667362007-06-24 11:21:02 +02001240
1241 /* Get thermal sensor types */
1242 diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1243 for (i = 0; i < 3; i++) {
1244 if ((tmp & (0x02 << i)))
1245 data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
1246 else
1247 data->temp_type[i] = 4; /* thermistor */
1248 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001249}
1250
David Hubbard1ea6dd32007-06-24 11:16:15 +02001251static int __devinit w83627ehf_probe(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001252{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001253 struct device *dev = &pdev->dev;
1254 struct w83627ehf_sio_data *sio_data = dev->platform_data;
Jean Delvare08e7e272005-04-25 22:43:25 +02001255 struct w83627ehf_data *data;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001256 struct resource *res;
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001257 u8 fan4pin, fan5pin, en_vrm10;
Jean Delvare08e7e272005-04-25 22:43:25 +02001258 int i, err = 0;
1259
David Hubbard1ea6dd32007-06-24 11:16:15 +02001260 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1261 if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001262 err = -EBUSY;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001263 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1264 (unsigned long)res->start,
1265 (unsigned long)res->start + IOREGION_LENGTH - 1);
Jean Delvare08e7e272005-04-25 22:43:25 +02001266 goto exit;
1267 }
1268
Deepak Saxenaba9c2e82005-10-17 23:08:32 +02001269 if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
Jean Delvare08e7e272005-04-25 22:43:25 +02001270 err = -ENOMEM;
1271 goto exit_release;
1272 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001273
David Hubbard1ea6dd32007-06-24 11:16:15 +02001274 data->addr = res->start;
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001275 mutex_init(&data->lock);
Ingo Molnar9a61bf62006-01-18 23:19:26 +01001276 mutex_init(&data->update_lock);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001277 data->name = w83627ehf_device_names[sio_data->kind];
1278 platform_set_drvdata(pdev, data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001279
Gong Jun237c8d2f2009-03-30 21:46:42 +02001280 /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1281 data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1282 /* 667HG has 3 pwms */
1283 data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4;
Jean Delvare08e7e272005-04-25 22:43:25 +02001284
1285 /* Initialize the chip */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001286 w83627ehf_init_device(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001287
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001288 data->vrm = vid_which_vrm();
1289 superio_enter(sio_data->sioreg);
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001290 /* Read VID value */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001291 if (sio_data->kind == w83667hg) {
1292 /* W83667HG has different pins for VID input and output, so
1293 we can get the VID input values directly at logical device D
1294 0xe3. */
1295 superio_select(sio_data->sioreg, W83667HG_LD_VID);
1296 data->vid = superio_inb(sio_data->sioreg, 0xe3);
Jean Delvarecbe311f2008-01-03 21:22:44 +01001297 err = device_create_file(dev, &dev_attr_cpu0_vid);
1298 if (err)
1299 goto exit_release;
Jean Delvare58e6e782008-01-03 07:33:31 -05001300 } else {
Gong Jun237c8d2f2009-03-30 21:46:42 +02001301 superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
1302 if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
1303 /* Set VID input sensibility if needed. In theory the
1304 BIOS should have set it, but in practice it's not
1305 always the case. We only do it for the W83627EHF/EHG
1306 because the W83627DHG is more complex in this
1307 respect. */
1308 if (sio_data->kind == w83627ehf) {
1309 en_vrm10 = superio_inb(sio_data->sioreg,
1310 SIO_REG_EN_VRM10);
1311 if ((en_vrm10 & 0x08) && data->vrm == 90) {
1312 dev_warn(dev, "Setting VID input "
1313 "voltage to TTL\n");
1314 superio_outb(sio_data->sioreg,
1315 SIO_REG_EN_VRM10,
1316 en_vrm10 & ~0x08);
1317 } else if (!(en_vrm10 & 0x08)
1318 && data->vrm == 100) {
1319 dev_warn(dev, "Setting VID input "
1320 "voltage to VRM10\n");
1321 superio_outb(sio_data->sioreg,
1322 SIO_REG_EN_VRM10,
1323 en_vrm10 | 0x08);
1324 }
1325 }
1326
1327 data->vid = superio_inb(sio_data->sioreg,
1328 SIO_REG_VID_DATA);
1329 if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1330 data->vid &= 0x3f;
1331
1332 err = device_create_file(dev, &dev_attr_cpu0_vid);
1333 if (err)
1334 goto exit_release;
1335 } else {
1336 dev_info(dev, "VID pins in output mode, CPU VID not "
1337 "available\n");
1338 }
Jean Delvarefc18d6c2007-06-24 11:19:42 +02001339 }
1340
Rudolf Marek08c79952006-07-05 18:14:31 +02001341 /* fan4 and fan5 share some pins with the GPIO and serial flash */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001342 if (sio_data->kind == w83667hg) {
1343 fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
1344 fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
1345 } else {
1346 fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
1347 fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
1348 }
David Hubbard1ea6dd32007-06-24 11:16:15 +02001349 superio_exit(sio_data->sioreg);
Rudolf Marek08c79952006-07-05 18:14:31 +02001350
Jean Delvare08e7e272005-04-25 22:43:25 +02001351 /* It looks like fan4 and fan5 pins can be alternatively used
Rudolf Marek14992c72006-10-08 22:02:09 +02001352 as fan on/off switches, but fan5 control is write only :/
1353 We assume that if the serial interface is disabled, designers
1354 connected fan5 as input unless they are emitting log 1, which
1355 is not the default. */
Rudolf Marek08c79952006-07-05 18:14:31 +02001356
Jean Delvare08e7e272005-04-25 22:43:25 +02001357 data->has_fan = 0x07; /* fan1, fan2 and fan3 */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001358 i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
Jean Delvare1704b262009-03-30 21:46:42 +02001359 if ((i & (1 << 2)) && fan4pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001360 data->has_fan |= (1 << 3);
Jean Delvare1704b262009-03-30 21:46:42 +02001361 if (!(i & (1 << 1)) && fan5pin)
Jean Delvare08e7e272005-04-25 22:43:25 +02001362 data->has_fan |= (1 << 4);
1363
Mark M. Hoffmanea7be662007-08-05 12:19:01 -04001364 /* Read fan clock dividers immediately */
1365 w83627ehf_update_fan_div(data);
1366
Jean Delvare08e7e272005-04-25 22:43:25 +02001367 /* Register sysfs hooks */
Rudolf Marek08c79952006-07-05 18:14:31 +02001368 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001369 if ((err = device_create_file(dev,
1370 &sda_sf3_arrays[i].dev_attr)))
1371 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001372
1373 /* if fan4 is enabled create the sf3 files for it */
Gong Jun237c8d2f2009-03-30 21:46:42 +02001374 if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
David Hubbardc18beb52006-09-24 21:04:38 +02001375 for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
1376 if ((err = device_create_file(dev,
1377 &sda_sf3_arrays_fan4[i].dev_attr)))
1378 goto exit_remove;
1379 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001380
David Hubbard1ea6dd32007-06-24 11:16:15 +02001381 for (i = 0; i < data->in_num; i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001382 if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
1383 || (err = device_create_file(dev,
1384 &sda_in_alarm[i].dev_attr))
1385 || (err = device_create_file(dev,
1386 &sda_in_min[i].dev_attr))
1387 || (err = device_create_file(dev,
1388 &sda_in_max[i].dev_attr)))
1389 goto exit_remove;
Rudolf Marekcf0676f2006-03-23 16:25:22 +01001390
Yuan Mu412fec82006-02-05 23:24:16 +01001391 for (i = 0; i < 5; i++) {
Rudolf Marek08c79952006-07-05 18:14:31 +02001392 if (data->has_fan & (1 << i)) {
David Hubbardc18beb52006-09-24 21:04:38 +02001393 if ((err = device_create_file(dev,
1394 &sda_fan_input[i].dev_attr))
1395 || (err = device_create_file(dev,
1396 &sda_fan_alarm[i].dev_attr))
1397 || (err = device_create_file(dev,
1398 &sda_fan_div[i].dev_attr))
1399 || (err = device_create_file(dev,
1400 &sda_fan_min[i].dev_attr)))
1401 goto exit_remove;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001402 if (i < data->pwm_num &&
David Hubbardc18beb52006-09-24 21:04:38 +02001403 ((err = device_create_file(dev,
1404 &sda_pwm[i].dev_attr))
1405 || (err = device_create_file(dev,
1406 &sda_pwm_mode[i].dev_attr))
1407 || (err = device_create_file(dev,
1408 &sda_pwm_enable[i].dev_attr))
1409 || (err = device_create_file(dev,
1410 &sda_target_temp[i].dev_attr))
1411 || (err = device_create_file(dev,
1412 &sda_tolerance[i].dev_attr))))
1413 goto exit_remove;
Rudolf Marek08c79952006-07-05 18:14:31 +02001414 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001415 }
Rudolf Marek08c79952006-07-05 18:14:31 +02001416
Yuan Mu412fec82006-02-05 23:24:16 +01001417 for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
David Hubbardc18beb52006-09-24 21:04:38 +02001418 if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
1419 goto exit_remove;
1420
David Hubbard1ea6dd32007-06-24 11:16:15 +02001421 err = device_create_file(dev, &dev_attr_name);
1422 if (err)
1423 goto exit_remove;
1424
Tony Jones1beeffe2007-08-20 13:46:20 -07001425 data->hwmon_dev = hwmon_device_register(dev);
1426 if (IS_ERR(data->hwmon_dev)) {
1427 err = PTR_ERR(data->hwmon_dev);
David Hubbardc18beb52006-09-24 21:04:38 +02001428 goto exit_remove;
1429 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001430
1431 return 0;
1432
David Hubbardc18beb52006-09-24 21:04:38 +02001433exit_remove:
1434 w83627ehf_device_remove_files(dev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001435 kfree(data);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001436 platform_set_drvdata(pdev, NULL);
Jean Delvare08e7e272005-04-25 22:43:25 +02001437exit_release:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001438 release_region(res->start, IOREGION_LENGTH);
Jean Delvare08e7e272005-04-25 22:43:25 +02001439exit:
1440 return err;
1441}
1442
David Hubbard1ea6dd32007-06-24 11:16:15 +02001443static int __devexit w83627ehf_remove(struct platform_device *pdev)
Jean Delvare08e7e272005-04-25 22:43:25 +02001444{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001445 struct w83627ehf_data *data = platform_get_drvdata(pdev);
Jean Delvare08e7e272005-04-25 22:43:25 +02001446
Tony Jones1beeffe2007-08-20 13:46:20 -07001447 hwmon_device_unregister(data->hwmon_dev);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001448 w83627ehf_device_remove_files(&pdev->dev);
1449 release_region(data->addr, IOREGION_LENGTH);
1450 platform_set_drvdata(pdev, NULL);
Mark M. Hoffman943b0832005-07-15 21:39:18 -04001451 kfree(data);
Jean Delvare08e7e272005-04-25 22:43:25 +02001452
1453 return 0;
1454}
1455
David Hubbard1ea6dd32007-06-24 11:16:15 +02001456static struct platform_driver w83627ehf_driver = {
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001457 .driver = {
Jean Delvare87218842006-09-03 22:36:14 +02001458 .owner = THIS_MODULE,
David Hubbard1ea6dd32007-06-24 11:16:15 +02001459 .name = DRVNAME,
Laurent Riffardcdaf7932005-11-26 20:37:41 +01001460 },
David Hubbard1ea6dd32007-06-24 11:16:15 +02001461 .probe = w83627ehf_probe,
1462 .remove = __devexit_p(w83627ehf_remove),
Jean Delvare08e7e272005-04-25 22:43:25 +02001463};
1464
David Hubbard1ea6dd32007-06-24 11:16:15 +02001465/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
1466static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
1467 struct w83627ehf_sio_data *sio_data)
Jean Delvare08e7e272005-04-25 22:43:25 +02001468{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001469 static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
1470 static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
1471 static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
Gong Jun237c8d2f2009-03-30 21:46:42 +02001472 static const char __initdata sio_name_W83667HG[] = "W83667HG";
David Hubbard1ea6dd32007-06-24 11:16:15 +02001473
Jean Delvare08e7e272005-04-25 22:43:25 +02001474 u16 val;
David Hubbard1ea6dd32007-06-24 11:16:15 +02001475 const char *sio_name;
Jean Delvare08e7e272005-04-25 22:43:25 +02001476
David Hubbard1ea6dd32007-06-24 11:16:15 +02001477 superio_enter(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001478
Jean Delvare67b671b2007-12-06 23:13:42 +01001479 if (force_id)
1480 val = force_id;
1481 else
1482 val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
1483 | superio_inb(sioaddr, SIO_REG_DEVID + 1);
David Hubbard657c93b2007-02-14 21:15:04 +01001484 switch (val & SIO_ID_MASK) {
David Hubbard657c93b2007-02-14 21:15:04 +01001485 case SIO_W83627EHF_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001486 sio_data->kind = w83627ehf;
1487 sio_name = sio_name_W83627EHF;
1488 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001489 case SIO_W83627EHG_ID:
David Hubbard1ea6dd32007-06-24 11:16:15 +02001490 sio_data->kind = w83627ehf;
1491 sio_name = sio_name_W83627EHG;
1492 break;
1493 case SIO_W83627DHG_ID:
1494 sio_data->kind = w83627dhg;
1495 sio_name = sio_name_W83627DHG;
David Hubbard657c93b2007-02-14 21:15:04 +01001496 break;
Gong Jun237c8d2f2009-03-30 21:46:42 +02001497 case SIO_W83667HG_ID:
1498 sio_data->kind = w83667hg;
1499 sio_name = sio_name_W83667HG;
1500 break;
David Hubbard657c93b2007-02-14 21:15:04 +01001501 default:
Jean Delvare9f660362007-06-24 11:23:41 +02001502 if (val != 0xffff)
1503 pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
1504 val);
David Hubbard1ea6dd32007-06-24 11:16:15 +02001505 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001506 return -ENODEV;
1507 }
1508
David Hubbard1ea6dd32007-06-24 11:16:15 +02001509 /* We have a known chip, find the HWM I/O address */
1510 superio_select(sioaddr, W83627EHF_LD_HWM);
1511 val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
1512 | superio_inb(sioaddr, SIO_REG_ADDR + 1);
Jean Delvare1a641fc2007-04-23 14:41:16 -07001513 *addr = val & IOREGION_ALIGNMENT;
Jean Delvare2d8672c2005-07-19 23:56:35 +02001514 if (*addr == 0) {
David Hubbard475ef852007-06-24 11:17:09 +02001515 printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
1516 "device with a base I/O port 0.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001517 superio_exit(sioaddr);
Jean Delvare08e7e272005-04-25 22:43:25 +02001518 return -ENODEV;
1519 }
1520
1521 /* Activate logical device if needed */
David Hubbard1ea6dd32007-06-24 11:16:15 +02001522 val = superio_inb(sioaddr, SIO_REG_ENABLE);
David Hubbard475ef852007-06-24 11:17:09 +02001523 if (!(val & 0x01)) {
1524 printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
1525 "Sensor is probably unusable.\n");
David Hubbard1ea6dd32007-06-24 11:16:15 +02001526 superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
David Hubbard475ef852007-06-24 11:17:09 +02001527 }
Jean Delvare08e7e272005-04-25 22:43:25 +02001528
David Hubbard1ea6dd32007-06-24 11:16:15 +02001529 superio_exit(sioaddr);
1530 pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
1531 sio_data->sioreg = sioaddr;
1532
Jean Delvare08e7e272005-04-25 22:43:25 +02001533 return 0;
1534}
1535
David Hubbard1ea6dd32007-06-24 11:16:15 +02001536/* when Super-I/O functions move to a separate file, the Super-I/O
1537 * bus will manage the lifetime of the device and this module will only keep
1538 * track of the w83627ehf driver. But since we platform_device_alloc(), we
1539 * must keep track of the device */
1540static struct platform_device *pdev;
1541
Jean Delvare08e7e272005-04-25 22:43:25 +02001542static int __init sensors_w83627ehf_init(void)
1543{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001544 int err;
1545 unsigned short address;
1546 struct resource res;
1547 struct w83627ehf_sio_data sio_data;
1548
1549 /* initialize sio_data->kind and sio_data->sioreg.
1550 *
1551 * when Super-I/O functions move to a separate file, the Super-I/O
1552 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1553 * w83627ehf hardware monitor, and call probe() */
1554 if (w83627ehf_find(0x2e, &address, &sio_data) &&
1555 w83627ehf_find(0x4e, &address, &sio_data))
Jean Delvare08e7e272005-04-25 22:43:25 +02001556 return -ENODEV;
1557
David Hubbard1ea6dd32007-06-24 11:16:15 +02001558 err = platform_driver_register(&w83627ehf_driver);
1559 if (err)
1560 goto exit;
1561
1562 if (!(pdev = platform_device_alloc(DRVNAME, address))) {
1563 err = -ENOMEM;
1564 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
1565 goto exit_unregister;
1566 }
1567
1568 err = platform_device_add_data(pdev, &sio_data,
1569 sizeof(struct w83627ehf_sio_data));
1570 if (err) {
1571 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1572 goto exit_device_put;
1573 }
1574
1575 memset(&res, 0, sizeof(res));
1576 res.name = DRVNAME;
1577 res.start = address + IOREGION_OFFSET;
1578 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1579 res.flags = IORESOURCE_IO;
Jean Delvareb9acb642009-01-07 16:37:35 +01001580
1581 err = acpi_check_resource_conflict(&res);
1582 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001583 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001584
David Hubbard1ea6dd32007-06-24 11:16:15 +02001585 err = platform_device_add_resources(pdev, &res, 1);
1586 if (err) {
1587 printk(KERN_ERR DRVNAME ": Device resource addition failed "
1588 "(%d)\n", err);
1589 goto exit_device_put;
1590 }
1591
1592 /* platform_device_add calls probe() */
1593 err = platform_device_add(pdev);
1594 if (err) {
1595 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1596 err);
1597 goto exit_device_put;
1598 }
1599
1600 return 0;
1601
1602exit_device_put:
1603 platform_device_put(pdev);
1604exit_unregister:
1605 platform_driver_unregister(&w83627ehf_driver);
1606exit:
1607 return err;
Jean Delvare08e7e272005-04-25 22:43:25 +02001608}
1609
1610static void __exit sensors_w83627ehf_exit(void)
1611{
David Hubbard1ea6dd32007-06-24 11:16:15 +02001612 platform_device_unregister(pdev);
1613 platform_driver_unregister(&w83627ehf_driver);
Jean Delvare08e7e272005-04-25 22:43:25 +02001614}
1615
1616MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1617MODULE_DESCRIPTION("W83627EHF driver");
1618MODULE_LICENSE("GPL");
1619
1620module_init(sensors_w83627ehf_init);
1621module_exit(sensors_w83627ehf_exit);