174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
208e7e278SJean Delvare /*
38969e84dSGuenter Roeck * w83627ehf - Driver for the hardware monitoring functionality of
48969e84dSGuenter Roeck * the Winbond W83627EHF Super-I/O chip
57c81c60fSJean Delvare * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
68969e84dSGuenter Roeck * Copyright (C) 2006 Yuan Mu (Winbond),
78969e84dSGuenter Roeck * Rudolf Marek <r.marek@assembler.cz>
88969e84dSGuenter Roeck * David Hubbard <david.c.hubbard@gmail.com>
98969e84dSGuenter Roeck * Daniel J Blueman <daniel.blueman@gmail.com>
108969e84dSGuenter Roeck * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
118969e84dSGuenter Roeck *
128969e84dSGuenter Roeck * Shamelessly ripped from the w83627hf driver
138969e84dSGuenter Roeck * Copyright (C) 2003 Mark Studebaker
148969e84dSGuenter Roeck *
158969e84dSGuenter Roeck * Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
168969e84dSGuenter Roeck * in testing and debugging this driver.
178969e84dSGuenter Roeck *
188969e84dSGuenter Roeck * This driver also supports the W83627EHG, which is the lead-free
198969e84dSGuenter Roeck * version of the W83627EHF.
208969e84dSGuenter Roeck *
218969e84dSGuenter Roeck * Supports the following chips:
228969e84dSGuenter Roeck *
238969e84dSGuenter Roeck * Chip #vin #fan #pwm #temp chip IDs man ID
248969e84dSGuenter Roeck * w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
258969e84dSGuenter Roeck * 0x8860 0xa1
268969e84dSGuenter Roeck * w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
278969e84dSGuenter Roeck * w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
288969e84dSGuenter Roeck * w83627uhg 8 2 2 3 0xa230 0xc1 0x5ca3
298969e84dSGuenter Roeck * w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
308969e84dSGuenter Roeck * w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
3108e7e278SJean Delvare */
3208e7e278SJean Delvare
33abdc6fd1SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34abdc6fd1SJoe Perches
3508e7e278SJean Delvare #include <linux/module.h>
3608e7e278SJean Delvare #include <linux/init.h>
3708e7e278SJean Delvare #include <linux/slab.h>
381ea6dd38SDavid Hubbard #include <linux/jiffies.h>
391ea6dd38SDavid Hubbard #include <linux/platform_device.h>
40943b0830SMark M. Hoffman #include <linux/hwmon.h>
41412fec82SYuan Mu #include <linux/hwmon-sysfs.h>
42fc18d6c0SJean Delvare #include <linux/hwmon-vid.h>
43943b0830SMark M. Hoffman #include <linux/err.h>
449a61bf63SIngo Molnar #include <linux/mutex.h>
45b9acb64aSJean Delvare #include <linux/acpi.h>
466055fae8SH Hartley Sweeten #include <linux/io.h>
4708e7e278SJean Delvare #include "lm75.h"
4808e7e278SJean Delvare
49eff7687dSJean Delvare enum kinds {
50eff7687dSJean Delvare w83627ehf, w83627dhg, w83627dhg_p, w83627uhg,
513207408aSDr. David Alan Gilbert w83667hg, w83667hg_b,
52eff7687dSJean Delvare };
531ea6dd38SDavid Hubbard
541ea6dd38SDavid Hubbard /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
55e7e1ca6eSGuenter Roeck static const char * const w83627ehf_device_names[] = {
561ea6dd38SDavid Hubbard "w83627ehf",
571ea6dd38SDavid Hubbard "w83627dhg",
58c1e48dceSJean Delvare "w83627dhg",
59eff7687dSJean Delvare "w83627uhg",
60237c8d2fSGong Jun "w83667hg",
61c39aedafSGuenter Roeck "w83667hg",
621ea6dd38SDavid Hubbard };
631ea6dd38SDavid Hubbard
6467b671bcSJean Delvare static unsigned short force_id;
6567b671bcSJean Delvare module_param(force_id, ushort, 0);
6667b671bcSJean Delvare MODULE_PARM_DESC(force_id, "Override the detected device ID");
6767b671bcSJean Delvare
681ea6dd38SDavid Hubbard #define DRVNAME "w83627ehf"
6908e7e278SJean Delvare
7008e7e278SJean Delvare /*
7108e7e278SJean Delvare * Super-I/O constants and functions
7208e7e278SJean Delvare */
7308e7e278SJean Delvare
7408e7e278SJean Delvare #define W83627EHF_LD_HWM 0x0b
75237c8d2fSGong Jun #define W83667HG_LD_VID 0x0d
7608e7e278SJean Delvare
7708e7e278SJean Delvare #define SIO_REG_LDSEL 0x07 /* Logical device select */
7808e7e278SJean Delvare #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
79fc18d6c0SJean Delvare #define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
8008e7e278SJean Delvare #define SIO_REG_ENABLE 0x30 /* Logical device enable */
8108e7e278SJean Delvare #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
82fc18d6c0SJean Delvare #define SIO_REG_VID_CTRL 0xF0 /* VID control */
83fc18d6c0SJean Delvare #define SIO_REG_VID_DATA 0xF1 /* VID data */
8408e7e278SJean Delvare
85657c93b1SDavid Hubbard #define SIO_W83627EHF_ID 0x8850
86657c93b1SDavid Hubbard #define SIO_W83627EHG_ID 0x8860
87657c93b1SDavid Hubbard #define SIO_W83627DHG_ID 0xa020
88c1e48dceSJean Delvare #define SIO_W83627DHG_P_ID 0xb070
89eff7687dSJean Delvare #define SIO_W83627UHG_ID 0xa230
90237c8d2fSGong Jun #define SIO_W83667HG_ID 0xa510
91c39aedafSGuenter Roeck #define SIO_W83667HG_B_ID 0xb350
92657c93b1SDavid Hubbard #define SIO_ID_MASK 0xFFF0
9308e7e278SJean Delvare
9408e7e278SJean Delvare static inline void
superio_outb(int ioreg,int reg,int val)951ea6dd38SDavid Hubbard superio_outb(int ioreg, int reg, int val)
9608e7e278SJean Delvare {
971ea6dd38SDavid Hubbard outb(reg, ioreg);
981ea6dd38SDavid Hubbard outb(val, ioreg + 1);
9908e7e278SJean Delvare }
10008e7e278SJean Delvare
10108e7e278SJean Delvare static inline int
superio_inb(int ioreg,int reg)1021ea6dd38SDavid Hubbard superio_inb(int ioreg, int reg)
10308e7e278SJean Delvare {
1041ea6dd38SDavid Hubbard outb(reg, ioreg);
1051ea6dd38SDavid Hubbard return inb(ioreg + 1);
10608e7e278SJean Delvare }
10708e7e278SJean Delvare
10808e7e278SJean Delvare static inline void
superio_select(int ioreg,int ld)1091ea6dd38SDavid Hubbard superio_select(int ioreg, int ld)
11008e7e278SJean Delvare {
1111ea6dd38SDavid Hubbard outb(SIO_REG_LDSEL, ioreg);
1121ea6dd38SDavid Hubbard outb(ld, ioreg + 1);
11308e7e278SJean Delvare }
11408e7e278SJean Delvare
1150d023530SKatsumi Sato static inline int
superio_enter(int ioreg)1161ea6dd38SDavid Hubbard superio_enter(int ioreg)
11708e7e278SJean Delvare {
1180d023530SKatsumi Sato if (!request_muxed_region(ioreg, 2, DRVNAME))
1190d023530SKatsumi Sato return -EBUSY;
1200d023530SKatsumi Sato
1211ea6dd38SDavid Hubbard outb(0x87, ioreg);
1221ea6dd38SDavid Hubbard outb(0x87, ioreg);
1230d023530SKatsumi Sato
1240d023530SKatsumi Sato return 0;
12508e7e278SJean Delvare }
12608e7e278SJean Delvare
12708e7e278SJean Delvare static inline void
superio_exit(int ioreg)1281ea6dd38SDavid Hubbard superio_exit(int ioreg)
12908e7e278SJean Delvare {
130022b75a3SJonas Jonsson outb(0xaa, ioreg);
1311ea6dd38SDavid Hubbard outb(0x02, ioreg);
1321ea6dd38SDavid Hubbard outb(0x02, ioreg + 1);
1330d023530SKatsumi Sato release_region(ioreg, 2);
13408e7e278SJean Delvare }
13508e7e278SJean Delvare
13608e7e278SJean Delvare /*
13708e7e278SJean Delvare * ISA constants
13808e7e278SJean Delvare */
13908e7e278SJean Delvare
140e7e1ca6eSGuenter Roeck #define IOREGION_ALIGNMENT (~7)
1411a641fceSJean Delvare #define IOREGION_OFFSET 5
1421a641fceSJean Delvare #define IOREGION_LENGTH 2
1431ea6dd38SDavid Hubbard #define ADDR_REG_OFFSET 0
1441ea6dd38SDavid Hubbard #define DATA_REG_OFFSET 1
14508e7e278SJean Delvare
14608e7e278SJean Delvare #define W83627EHF_REG_BANK 0x4E
14708e7e278SJean Delvare #define W83627EHF_REG_CONFIG 0x40
148657c93b1SDavid Hubbard
1498969e84dSGuenter Roeck /*
1508969e84dSGuenter Roeck * Not currently used:
151657c93b1SDavid Hubbard * REG_MAN_ID has the value 0x5ca3 for all supported chips.
152657c93b1SDavid Hubbard * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
153657c93b1SDavid Hubbard * REG_MAN_ID is at port 0x4f
1548969e84dSGuenter Roeck * REG_CHIP_ID is at port 0x58
1558969e84dSGuenter Roeck */
15608e7e278SJean Delvare
15708e7e278SJean Delvare static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
15808e7e278SJean Delvare static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
15908e7e278SJean Delvare
160cf0676feSRudolf Marek /* The W83627EHF registers for nr=7,8,9 are in bank 5 */
161cf0676feSRudolf Marek #define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
162cf0676feSRudolf Marek (0x554 + (((nr) - 7) * 2)))
163cf0676feSRudolf Marek #define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
164cf0676feSRudolf Marek (0x555 + (((nr) - 7) * 2)))
165cf0676feSRudolf Marek #define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
166cf0676feSRudolf Marek (0x550 + (nr) - 7))
167cf0676feSRudolf Marek
168d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
169d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
170d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
171d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
17208e7e278SJean Delvare
17308e7e278SJean Delvare /* Fan clock dividers are spread over the following five registers */
17408e7e278SJean Delvare #define W83627EHF_REG_FANDIV1 0x47
17508e7e278SJean Delvare #define W83627EHF_REG_FANDIV2 0x4B
17608e7e278SJean Delvare #define W83627EHF_REG_VBAT 0x5D
17708e7e278SJean Delvare #define W83627EHF_REG_DIODE 0x59
17808e7e278SJean Delvare #define W83627EHF_REG_SMI_OVT 0x4C
17908e7e278SJean Delvare
180a4589dbbSJean Delvare #define W83627EHF_REG_ALARM1 0x459
181a4589dbbSJean Delvare #define W83627EHF_REG_ALARM2 0x45A
182a4589dbbSJean Delvare #define W83627EHF_REG_ALARM3 0x45B
183a4589dbbSJean Delvare
184363a12a4SDmitry Artamonow #define W83627EHF_REG_CASEOPEN_DET 0x42 /* SMI STATUS #2 */
185363a12a4SDmitry Artamonow #define W83627EHF_REG_CASEOPEN_CLR 0x46 /* SMI MASK #3 */
186363a12a4SDmitry Artamonow
18708c79950SRudolf Marek /* SmartFan registers */
18841e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
18941e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
19041e9a062SDaniel J Blueman
19108c79950SRudolf Marek /* DC or PWM output fan configuration */
19208c79950SRudolf Marek static const u8 W83627EHF_REG_PWM_ENABLE[] = {
19308c79950SRudolf Marek 0x04, /* SYS FAN0 output mode and PWM mode */
19408c79950SRudolf Marek 0x04, /* CPU FAN0 output mode and PWM mode */
19508c79950SRudolf Marek 0x12, /* AUX FAN mode */
19641e9a062SDaniel J Blueman 0x62, /* CPU FAN1 mode */
19708c79950SRudolf Marek };
19808c79950SRudolf Marek
19908c79950SRudolf Marek static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
20008c79950SRudolf Marek static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
20108c79950SRudolf Marek
20208c79950SRudolf Marek /* FAN Duty Cycle, be used to control */
203279af1a9SGuenter Roeck static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
204279af1a9SGuenter Roeck static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
20508c79950SRudolf Marek static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
20608c79950SRudolf Marek
20708c79950SRudolf Marek /* Advanced Fan control, some values are common for all fans */
208279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
209279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
210279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
211c39aedafSGuenter Roeck
212279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
213c39aedafSGuenter Roeck = { 0xff, 0x67, 0xff, 0x69 };
214279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
215c39aedafSGuenter Roeck = { 0xff, 0x68, 0xff, 0x6a };
216c39aedafSGuenter Roeck
217279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
218279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
219279af1a9SGuenter Roeck = { 0x68, 0x6a, 0x6c };
22008c79950SRudolf Marek
221840e191dSGuenter Roeck static const u16 W83627EHF_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
222840e191dSGuenter Roeck
223d36cf32cSGuenter Roeck static const char *const w83667hg_b_temp_label[] = {
224d36cf32cSGuenter Roeck "SYSTIN",
225d36cf32cSGuenter Roeck "CPUTIN",
226d36cf32cSGuenter Roeck "AUXTIN",
227d36cf32cSGuenter Roeck "AMDTSI",
228d36cf32cSGuenter Roeck "PECI Agent 1",
229d36cf32cSGuenter Roeck "PECI Agent 2",
230d36cf32cSGuenter Roeck "PECI Agent 3",
231d36cf32cSGuenter Roeck "PECI Agent 4"
232d36cf32cSGuenter Roeck };
233d36cf32cSGuenter Roeck
2343207408aSDr. David Alan Gilbert #define NUM_REG_TEMP ARRAY_SIZE(W83627EHF_REG_TEMP)
235d36cf32cSGuenter Roeck
is_word_sized(u16 reg)23617296febSJean Delvare static int is_word_sized(u16 reg)
237bce26c58SGuenter Roeck {
238ec3e5a16SGuenter Roeck return ((((reg & 0xff00) == 0x100
239bce26c58SGuenter Roeck || (reg & 0xff00) == 0x200)
240bce26c58SGuenter Roeck && ((reg & 0x00ff) == 0x50
241bce26c58SGuenter Roeck || (reg & 0x00ff) == 0x53
242ec3e5a16SGuenter Roeck || (reg & 0x00ff) == 0x55))
243ec3e5a16SGuenter Roeck || (reg & 0xfff0) == 0x630
244ec3e5a16SGuenter Roeck || reg == 0x640 || reg == 0x642
245ec3e5a16SGuenter Roeck || ((reg & 0xfff0) == 0x650
246ec3e5a16SGuenter Roeck && (reg & 0x000f) >= 0x06)
247ec3e5a16SGuenter Roeck || reg == 0x73 || reg == 0x75 || reg == 0x77
248ec3e5a16SGuenter Roeck );
249bce26c58SGuenter Roeck }
250bce26c58SGuenter Roeck
25108e7e278SJean Delvare /*
25208e7e278SJean Delvare * Conversions
25308e7e278SJean Delvare */
25408e7e278SJean Delvare
25508c79950SRudolf Marek /* 1 is PWM mode, output in ms */
step_time_from_reg(u8 reg,u8 mode)25608c79950SRudolf Marek static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
25708c79950SRudolf Marek {
25808c79950SRudolf Marek return mode ? 100 * reg : 400 * reg;
25908c79950SRudolf Marek }
26008c79950SRudolf Marek
step_time_to_reg(unsigned int msec,u8 mode)26108c79950SRudolf Marek static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
26208c79950SRudolf Marek {
2632a844c14SGuenter Roeck return clamp_val((mode ? (msec + 50) / 100 : (msec + 200) / 400),
2642a844c14SGuenter Roeck 1, 255);
26508c79950SRudolf Marek }
26608c79950SRudolf Marek
fan_from_reg8(u16 reg,unsigned int divreg)26726bc440eSGuenter Roeck static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
26808e7e278SJean Delvare {
26926bc440eSGuenter Roeck if (reg == 0 || reg == 255)
27008e7e278SJean Delvare return 0;
27126bc440eSGuenter Roeck return 1350000U / (reg << divreg);
272ec3e5a16SGuenter Roeck }
27326bc440eSGuenter Roeck
27408e7e278SJean Delvare static inline unsigned int
div_from_reg(u8 reg)27508e7e278SJean Delvare div_from_reg(u8 reg)
27608e7e278SJean Delvare {
27708e7e278SJean Delvare return 1 << reg;
27808e7e278SJean Delvare }
27908e7e278SJean Delvare
2808969e84dSGuenter Roeck /*
2818969e84dSGuenter Roeck * Some of the voltage inputs have internal scaling, the tables below
2828969e84dSGuenter Roeck * contain 8 (the ADC LSB in mV) * scaling factor * 100
2838969e84dSGuenter Roeck */
284eff7687dSJean Delvare static const u16 scale_in_common[10] = {
285eff7687dSJean Delvare 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800
286eff7687dSJean Delvare };
287eff7687dSJean Delvare static const u16 scale_in_w83627uhg[9] = {
288eff7687dSJean Delvare 800, 800, 3328, 3424, 800, 800, 0, 3328, 3400
289eff7687dSJean Delvare };
290cf0676feSRudolf Marek
in_from_reg(u8 reg,u8 nr,const u16 * scale_in)291eff7687dSJean Delvare static inline long in_from_reg(u8 reg, u8 nr, const u16 *scale_in)
292cf0676feSRudolf Marek {
293eff7687dSJean Delvare return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
294cf0676feSRudolf Marek }
295cf0676feSRudolf Marek
in_to_reg(u32 val,u8 nr,const u16 * scale_in)296eff7687dSJean Delvare static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in)
297cf0676feSRudolf Marek {
2982a844c14SGuenter Roeck return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
299cf0676feSRudolf Marek }
300cf0676feSRudolf Marek
30108e7e278SJean Delvare /*
30208e7e278SJean Delvare * Data structures and manipulation thereof
30308e7e278SJean Delvare */
30408e7e278SJean Delvare
30508e7e278SJean Delvare struct w83627ehf_data {
3061ea6dd38SDavid Hubbard int addr; /* IO base of hw monitor block */
3071ea6dd38SDavid Hubbard const char *name;
3081ea6dd38SDavid Hubbard
3099a61bf63SIngo Molnar struct mutex lock;
31008e7e278SJean Delvare
311ec3e5a16SGuenter Roeck u16 reg_temp[NUM_REG_TEMP];
312ec3e5a16SGuenter Roeck u16 reg_temp_over[NUM_REG_TEMP];
313ec3e5a16SGuenter Roeck u16 reg_temp_hyst[NUM_REG_TEMP];
314ec3e5a16SGuenter Roeck u16 reg_temp_config[NUM_REG_TEMP];
315d36cf32cSGuenter Roeck u8 temp_src[NUM_REG_TEMP];
316d36cf32cSGuenter Roeck const char * const *temp_label;
317d36cf32cSGuenter Roeck
318279af1a9SGuenter Roeck const u16 *REG_FAN_MAX_OUTPUT;
319279af1a9SGuenter Roeck const u16 *REG_FAN_STEP_OUTPUT;
320eff7687dSJean Delvare const u16 *scale_in;
321da2e0255SGuenter Roeck
3229a61bf63SIngo Molnar struct mutex update_lock;
323952a11caSPaul Fertser bool valid; /* true if following fields are valid */
32408e7e278SJean Delvare unsigned long last_updated; /* In jiffies */
32508e7e278SJean Delvare
32608e7e278SJean Delvare /* Register values */
32783cc8985SGuenter Roeck u8 bank; /* current register bank */
3281ea6dd38SDavid Hubbard u8 in_num; /* number of in inputs we have */
329cf0676feSRudolf Marek u8 in[10]; /* Register value */
330cf0676feSRudolf Marek u8 in_max[10]; /* Register value */
331cf0676feSRudolf Marek u8 in_min[10]; /* Register value */
3323382a918SGuenter Roeck unsigned int rpm[5];
333ec3e5a16SGuenter Roeck u16 fan_min[5];
33408e7e278SJean Delvare u8 fan_div[5];
33508e7e278SJean Delvare u8 has_fan; /* some fan inputs can be disabled */
336ec3e5a16SGuenter Roeck u8 has_fan_min; /* some fans don't have min register */
337da667365SJean Delvare u8 temp_type[3];
338840e191dSGuenter Roeck s8 temp_offset[3];
339ec3e5a16SGuenter Roeck s16 temp[9];
340ec3e5a16SGuenter Roeck s16 temp_max[9];
341ec3e5a16SGuenter Roeck s16 temp_max_hyst[9];
342a4589dbbSJean Delvare u32 alarms;
343363a12a4SDmitry Artamonow u8 caseopen;
34408c79950SRudolf Marek
34508c79950SRudolf Marek u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
34608c79950SRudolf Marek u8 pwm_enable[4]; /* 1->manual
3478969e84dSGuenter Roeck * 2->thermal cruise mode (also called SmartFan I)
3488969e84dSGuenter Roeck * 3->fan speed cruise mode
3498969e84dSGuenter Roeck * 4->variable thermal cruise (also called
3508969e84dSGuenter Roeck * SmartFan III)
3518969e84dSGuenter Roeck * 5->enhanced variable thermal cruise (also called
3528969e84dSGuenter Roeck * SmartFan IV)
3538969e84dSGuenter Roeck */
354b84bb518SGuenter Roeck u8 pwm_enable_orig[4]; /* original value of pwm_enable */
355237c8d2fSGong Jun u8 pwm_num; /* number of pwm */
35608c79950SRudolf Marek u8 pwm[4];
35708c79950SRudolf Marek u8 target_temp[4];
35808c79950SRudolf Marek u8 tolerance[4];
35908c79950SRudolf Marek
36041e9a062SDaniel J Blueman u8 fan_start_output[4]; /* minimum fan speed when spinning up */
36141e9a062SDaniel J Blueman u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
36241e9a062SDaniel J Blueman u8 fan_stop_time[4]; /* time at minimum before disabling fan */
36341e9a062SDaniel J Blueman u8 fan_max_output[4]; /* maximum fan speed */
36441e9a062SDaniel J Blueman u8 fan_step_output[4]; /* rate of change output value */
365fc18d6c0SJean Delvare
366fc18d6c0SJean Delvare u8 vid;
367fc18d6c0SJean Delvare u8 vrm;
368a157d06dSGong Jun
369ec3e5a16SGuenter Roeck u16 have_temp;
370840e191dSGuenter Roeck u16 have_temp_offset;
371eff7687dSJean Delvare u8 in6_skip:1;
372eff7687dSJean Delvare u8 temp3_val_only:1;
373266cd583SDr. David Alan Gilbert u8 have_vid:1;
3747e630bb5SJean Delvare
3757e630bb5SJean Delvare /* Remember extra register values over suspend/resume */
3767e630bb5SJean Delvare u8 vbat;
3777e630bb5SJean Delvare u8 fandiv1;
3787e630bb5SJean Delvare u8 fandiv2;
37908e7e278SJean Delvare };
38008e7e278SJean Delvare
3811ea6dd38SDavid Hubbard struct w83627ehf_sio_data {
3821ea6dd38SDavid Hubbard int sioreg;
3831ea6dd38SDavid Hubbard enum kinds kind;
3841ea6dd38SDavid Hubbard };
3851ea6dd38SDavid Hubbard
38683cc8985SGuenter Roeck /*
38783cc8985SGuenter Roeck * On older chips, only registers 0x50-0x5f are banked.
38883cc8985SGuenter Roeck * On more recent chips, all registers are banked.
38983cc8985SGuenter Roeck * Assume that is the case and set the bank number for each access.
39083cc8985SGuenter Roeck * Cache the bank number so it only needs to be set if it changes.
39183cc8985SGuenter Roeck */
w83627ehf_set_bank(struct w83627ehf_data * data,u16 reg)3921ea6dd38SDavid Hubbard static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
39308e7e278SJean Delvare {
39483cc8985SGuenter Roeck u8 bank = reg >> 8;
39583cc8985SGuenter Roeck if (data->bank != bank) {
3961ea6dd38SDavid Hubbard outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
39783cc8985SGuenter Roeck outb_p(bank, data->addr + DATA_REG_OFFSET);
39883cc8985SGuenter Roeck data->bank = bank;
39908e7e278SJean Delvare }
40008e7e278SJean Delvare }
40108e7e278SJean Delvare
w83627ehf_read_value(struct w83627ehf_data * data,u16 reg)4021ea6dd38SDavid Hubbard static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
40308e7e278SJean Delvare {
40408e7e278SJean Delvare int res, word_sized = is_word_sized(reg);
40508e7e278SJean Delvare
4069a61bf63SIngo Molnar mutex_lock(&data->lock);
40708e7e278SJean Delvare
4081ea6dd38SDavid Hubbard w83627ehf_set_bank(data, reg);
4091ea6dd38SDavid Hubbard outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
4101ea6dd38SDavid Hubbard res = inb_p(data->addr + DATA_REG_OFFSET);
41108e7e278SJean Delvare if (word_sized) {
41208e7e278SJean Delvare outb_p((reg & 0xff) + 1,
4131ea6dd38SDavid Hubbard data->addr + ADDR_REG_OFFSET);
4141ea6dd38SDavid Hubbard res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
41508e7e278SJean Delvare }
41608e7e278SJean Delvare
4179a61bf63SIngo Molnar mutex_unlock(&data->lock);
41808e7e278SJean Delvare return res;
41908e7e278SJean Delvare }
42008e7e278SJean Delvare
w83627ehf_write_value(struct w83627ehf_data * data,u16 reg,u16 value)421e7e1ca6eSGuenter Roeck static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
422e7e1ca6eSGuenter Roeck u16 value)
42308e7e278SJean Delvare {
42408e7e278SJean Delvare int word_sized = is_word_sized(reg);
42508e7e278SJean Delvare
4269a61bf63SIngo Molnar mutex_lock(&data->lock);
42708e7e278SJean Delvare
4281ea6dd38SDavid Hubbard w83627ehf_set_bank(data, reg);
4291ea6dd38SDavid Hubbard outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
43008e7e278SJean Delvare if (word_sized) {
4311ea6dd38SDavid Hubbard outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
43208e7e278SJean Delvare outb_p((reg & 0xff) + 1,
4331ea6dd38SDavid Hubbard data->addr + ADDR_REG_OFFSET);
43408e7e278SJean Delvare }
4351ea6dd38SDavid Hubbard outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
43608e7e278SJean Delvare
4379a61bf63SIngo Molnar mutex_unlock(&data->lock);
43808e7e278SJean Delvare return 0;
43908e7e278SJean Delvare }
44008e7e278SJean Delvare
441c5794cfaSJean Delvare /* We left-align 8-bit temperature values to make the code simpler */
w83627ehf_read_temp(struct w83627ehf_data * data,u16 reg)442c5794cfaSJean Delvare static u16 w83627ehf_read_temp(struct w83627ehf_data *data, u16 reg)
443c5794cfaSJean Delvare {
444c5794cfaSJean Delvare u16 res;
445c5794cfaSJean Delvare
446c5794cfaSJean Delvare res = w83627ehf_read_value(data, reg);
447c5794cfaSJean Delvare if (!is_word_sized(reg))
448c5794cfaSJean Delvare res <<= 8;
449c5794cfaSJean Delvare
450c5794cfaSJean Delvare return res;
451c5794cfaSJean Delvare }
452c5794cfaSJean Delvare
w83627ehf_write_temp(struct w83627ehf_data * data,u16 reg,u16 value)453c5794cfaSJean Delvare static int w83627ehf_write_temp(struct w83627ehf_data *data, u16 reg,
454c5794cfaSJean Delvare u16 value)
455c5794cfaSJean Delvare {
456c5794cfaSJean Delvare if (!is_word_sized(reg))
457c5794cfaSJean Delvare value >>= 8;
458c5794cfaSJean Delvare return w83627ehf_write_value(data, reg, value);
459c5794cfaSJean Delvare }
460c5794cfaSJean Delvare
46108e7e278SJean Delvare /* This function assumes that the caller holds data->update_lock */
w83627ehf_write_fan_div(struct w83627ehf_data * data,int nr)4621ea6dd38SDavid Hubbard static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
46308e7e278SJean Delvare {
46408e7e278SJean Delvare u8 reg;
46508e7e278SJean Delvare
46608e7e278SJean Delvare switch (nr) {
46708e7e278SJean Delvare case 0:
4681ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
46908e7e278SJean Delvare | ((data->fan_div[0] & 0x03) << 4);
47014992c7eSRudolf Marek /* fan5 input control bit is write only, compute the value */
47114992c7eSRudolf Marek reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
4721ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
4731ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
47408e7e278SJean Delvare | ((data->fan_div[0] & 0x04) << 3);
4751ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
47608e7e278SJean Delvare break;
47708e7e278SJean Delvare case 1:
4781ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
47908e7e278SJean Delvare | ((data->fan_div[1] & 0x03) << 6);
48014992c7eSRudolf Marek /* fan5 input control bit is write only, compute the value */
48114992c7eSRudolf Marek reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
4821ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
4831ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
48408e7e278SJean Delvare | ((data->fan_div[1] & 0x04) << 4);
4851ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
48608e7e278SJean Delvare break;
48708e7e278SJean Delvare case 2:
4881ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
48908e7e278SJean Delvare | ((data->fan_div[2] & 0x03) << 6);
4901ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
4911ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
49208e7e278SJean Delvare | ((data->fan_div[2] & 0x04) << 5);
4931ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
49408e7e278SJean Delvare break;
49508e7e278SJean Delvare case 3:
4961ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
49708e7e278SJean Delvare | (data->fan_div[3] & 0x03);
4981ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
4991ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
50008e7e278SJean Delvare | ((data->fan_div[3] & 0x04) << 5);
5011ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
50208e7e278SJean Delvare break;
50308e7e278SJean Delvare case 4:
5041ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
50533725ad3SJean Delvare | ((data->fan_div[4] & 0x03) << 2)
50608e7e278SJean Delvare | ((data->fan_div[4] & 0x04) << 5);
5071ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
50808e7e278SJean Delvare break;
50908e7e278SJean Delvare }
51008e7e278SJean Delvare }
51108e7e278SJean Delvare
w83627ehf_update_fan_div(struct w83627ehf_data * data)512ea7be66cSMark M. Hoffman static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
51308e7e278SJean Delvare {
51408e7e278SJean Delvare int i;
51508e7e278SJean Delvare
5161ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
51708e7e278SJean Delvare data->fan_div[0] = (i >> 4) & 0x03;
51808e7e278SJean Delvare data->fan_div[1] = (i >> 6) & 0x03;
5191ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
52008e7e278SJean Delvare data->fan_div[2] = (i >> 6) & 0x03;
5211ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
52208e7e278SJean Delvare data->fan_div[0] |= (i >> 3) & 0x04;
52308e7e278SJean Delvare data->fan_div[1] |= (i >> 4) & 0x04;
52408e7e278SJean Delvare data->fan_div[2] |= (i >> 5) & 0x04;
52508e7e278SJean Delvare if (data->has_fan & ((1 << 3) | (1 << 4))) {
5261ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
52708e7e278SJean Delvare data->fan_div[3] = i & 0x03;
52808e7e278SJean Delvare data->fan_div[4] = ((i >> 2) & 0x03)
52908e7e278SJean Delvare | ((i >> 5) & 0x04);
53008e7e278SJean Delvare }
53108e7e278SJean Delvare if (data->has_fan & (1 << 3)) {
5321ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
53308e7e278SJean Delvare data->fan_div[3] |= (i >> 5) & 0x04;
53408e7e278SJean Delvare }
535ea7be66cSMark M. Hoffman }
536ea7be66cSMark M. Hoffman
w83627ehf_update_pwm(struct w83627ehf_data * data)537ec3e5a16SGuenter Roeck static void w83627ehf_update_pwm(struct w83627ehf_data *data)
538ec3e5a16SGuenter Roeck {
539ec3e5a16SGuenter Roeck int i;
540ec3e5a16SGuenter Roeck int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
541ec3e5a16SGuenter Roeck
542ec3e5a16SGuenter Roeck for (i = 0; i < data->pwm_num; i++) {
543ec3e5a16SGuenter Roeck if (!(data->has_fan & (1 << i)))
544ec3e5a16SGuenter Roeck continue;
545ec3e5a16SGuenter Roeck
546ec3e5a16SGuenter Roeck /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
547ec3e5a16SGuenter Roeck if (i != 1) {
548ec3e5a16SGuenter Roeck pwmcfg = w83627ehf_read_value(data,
549ec3e5a16SGuenter Roeck W83627EHF_REG_PWM_ENABLE[i]);
550ec3e5a16SGuenter Roeck tolerance = w83627ehf_read_value(data,
551ec3e5a16SGuenter Roeck W83627EHF_REG_TOLERANCE[i]);
552ec3e5a16SGuenter Roeck }
553ec3e5a16SGuenter Roeck data->pwm_mode[i] =
554ec3e5a16SGuenter Roeck ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
555ec3e5a16SGuenter Roeck data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
556ec3e5a16SGuenter Roeck & 3) + 1;
55769595502SDr. David Alan Gilbert data->pwm[i] = w83627ehf_read_value(data, W83627EHF_REG_PWM[i]);
558ec3e5a16SGuenter Roeck
559ec3e5a16SGuenter Roeck data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
560ec3e5a16SGuenter Roeck }
561ec3e5a16SGuenter Roeck }
562ec3e5a16SGuenter Roeck
w83627ehf_update_device(struct device * dev)563ea7be66cSMark M. Hoffman static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
564ea7be66cSMark M. Hoffman {
565ea7be66cSMark M. Hoffman struct w83627ehf_data *data = dev_get_drvdata(dev);
566ea7be66cSMark M. Hoffman int i;
567ea7be66cSMark M. Hoffman
568ea7be66cSMark M. Hoffman mutex_lock(&data->update_lock);
569ea7be66cSMark M. Hoffman
570ea7be66cSMark M. Hoffman if (time_after(jiffies, data->last_updated + HZ + HZ/2)
571ea7be66cSMark M. Hoffman || !data->valid) {
572ea7be66cSMark M. Hoffman /* Fan clock dividers */
57369595502SDr. David Alan Gilbert w83627ehf_update_fan_div(data);
57408e7e278SJean Delvare
575cf0676feSRudolf Marek /* Measured voltages and limits */
5761ea6dd38SDavid Hubbard for (i = 0; i < data->in_num; i++) {
577389ef65dSJean Delvare if ((i == 6) && data->in6_skip)
578389ef65dSJean Delvare continue;
579389ef65dSJean Delvare
5801ea6dd38SDavid Hubbard data->in[i] = w83627ehf_read_value(data,
581cf0676feSRudolf Marek W83627EHF_REG_IN(i));
5821ea6dd38SDavid Hubbard data->in_min[i] = w83627ehf_read_value(data,
583cf0676feSRudolf Marek W83627EHF_REG_IN_MIN(i));
5841ea6dd38SDavid Hubbard data->in_max[i] = w83627ehf_read_value(data,
585cf0676feSRudolf Marek W83627EHF_REG_IN_MAX(i));
586cf0676feSRudolf Marek }
587cf0676feSRudolf Marek
58808e7e278SJean Delvare /* Measured fan speeds and limits */
58908e7e278SJean Delvare for (i = 0; i < 5; i++) {
5903382a918SGuenter Roeck u16 reg;
5913382a918SGuenter Roeck
59208e7e278SJean Delvare if (!(data->has_fan & (1 << i)))
59308e7e278SJean Delvare continue;
59408e7e278SJean Delvare
59569595502SDr. David Alan Gilbert reg = w83627ehf_read_value(data, W83627EHF_REG_FAN[i]);
59669595502SDr. David Alan Gilbert data->rpm[i] = fan_from_reg8(reg, data->fan_div[i]);
597ec3e5a16SGuenter Roeck
598ec3e5a16SGuenter Roeck if (data->has_fan_min & (1 << i))
5991ea6dd38SDavid Hubbard data->fan_min[i] = w83627ehf_read_value(data,
60069595502SDr. David Alan Gilbert W83627EHF_REG_FAN_MIN[i]);
60108e7e278SJean Delvare
6028969e84dSGuenter Roeck /*
6038969e84dSGuenter Roeck * If we failed to measure the fan speed and clock
6048969e84dSGuenter Roeck * divider can be increased, let's try that for next
6058969e84dSGuenter Roeck * time
6068969e84dSGuenter Roeck */
60769595502SDr. David Alan Gilbert if (reg >= 0xff && data->fan_div[i] < 0x07) {
608b55f3757SGuenter Roeck dev_dbg(dev,
609b55f3757SGuenter Roeck "Increasing fan%d clock divider from %u to %u\n",
61033725ad3SJean Delvare i + 1, div_from_reg(data->fan_div[i]),
61108e7e278SJean Delvare div_from_reg(data->fan_div[i] + 1));
61208e7e278SJean Delvare data->fan_div[i]++;
61369595502SDr. David Alan Gilbert w83627ehf_write_fan_div(data, i);
61408e7e278SJean Delvare /* Preserve min limit if possible */
615ec3e5a16SGuenter Roeck if ((data->has_fan_min & (1 << i))
616ec3e5a16SGuenter Roeck && data->fan_min[i] >= 2
61708e7e278SJean Delvare && data->fan_min[i] != 255)
6181ea6dd38SDavid Hubbard w83627ehf_write_value(data,
61969595502SDr. David Alan Gilbert W83627EHF_REG_FAN_MIN[i],
62008e7e278SJean Delvare (data->fan_min[i] /= 2));
62108e7e278SJean Delvare }
62208e7e278SJean Delvare }
62308e7e278SJean Delvare
62469595502SDr. David Alan Gilbert w83627ehf_update_pwm(data);
625ec3e5a16SGuenter Roeck
626da2e0255SGuenter Roeck for (i = 0; i < data->pwm_num; i++) {
627da2e0255SGuenter Roeck if (!(data->has_fan & (1 << i)))
628da2e0255SGuenter Roeck continue;
629da2e0255SGuenter Roeck
630ec3e5a16SGuenter Roeck data->fan_start_output[i] =
631ec3e5a16SGuenter Roeck w83627ehf_read_value(data,
63269595502SDr. David Alan Gilbert W83627EHF_REG_FAN_START_OUTPUT[i]);
633ec3e5a16SGuenter Roeck data->fan_stop_output[i] =
634ec3e5a16SGuenter Roeck w83627ehf_read_value(data,
63569595502SDr. David Alan Gilbert W83627EHF_REG_FAN_STOP_OUTPUT[i]);
636ec3e5a16SGuenter Roeck data->fan_stop_time[i] =
637ec3e5a16SGuenter Roeck w83627ehf_read_value(data,
63869595502SDr. David Alan Gilbert W83627EHF_REG_FAN_STOP_TIME[i]);
639da2e0255SGuenter Roeck
640ec3e5a16SGuenter Roeck if (data->REG_FAN_MAX_OUTPUT &&
641ec3e5a16SGuenter Roeck data->REG_FAN_MAX_OUTPUT[i] != 0xff)
642da2e0255SGuenter Roeck data->fan_max_output[i] =
643da2e0255SGuenter Roeck w83627ehf_read_value(data,
644da2e0255SGuenter Roeck data->REG_FAN_MAX_OUTPUT[i]);
645da2e0255SGuenter Roeck
646ec3e5a16SGuenter Roeck if (data->REG_FAN_STEP_OUTPUT &&
647ec3e5a16SGuenter Roeck data->REG_FAN_STEP_OUTPUT[i] != 0xff)
648da2e0255SGuenter Roeck data->fan_step_output[i] =
649da2e0255SGuenter Roeck w83627ehf_read_value(data,
650da2e0255SGuenter Roeck data->REG_FAN_STEP_OUTPUT[i]);
651da2e0255SGuenter Roeck
65208c79950SRudolf Marek data->target_temp[i] =
6531ea6dd38SDavid Hubbard w83627ehf_read_value(data,
65469595502SDr. David Alan Gilbert W83627EHF_REG_TARGET[i]) &
65508c79950SRudolf Marek (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
65608c79950SRudolf Marek }
65708c79950SRudolf Marek
65808e7e278SJean Delvare /* Measured temperatures and limits */
659d36cf32cSGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) {
660d36cf32cSGuenter Roeck if (!(data->have_temp & (1 << i)))
661d36cf32cSGuenter Roeck continue;
662c5794cfaSJean Delvare data->temp[i] = w83627ehf_read_temp(data,
663ec3e5a16SGuenter Roeck data->reg_temp[i]);
664ec3e5a16SGuenter Roeck if (data->reg_temp_over[i])
665d36cf32cSGuenter Roeck data->temp_max[i]
666c5794cfaSJean Delvare = w83627ehf_read_temp(data,
667ec3e5a16SGuenter Roeck data->reg_temp_over[i]);
668ec3e5a16SGuenter Roeck if (data->reg_temp_hyst[i])
669d36cf32cSGuenter Roeck data->temp_max_hyst[i]
670c5794cfaSJean Delvare = w83627ehf_read_temp(data,
671ec3e5a16SGuenter Roeck data->reg_temp_hyst[i]);
67245633fb3SJean Delvare if (i > 2)
67345633fb3SJean Delvare continue;
674840e191dSGuenter Roeck if (data->have_temp_offset & (1 << i))
675840e191dSGuenter Roeck data->temp_offset[i]
676840e191dSGuenter Roeck = w83627ehf_read_value(data,
677840e191dSGuenter Roeck W83627EHF_REG_TEMP_OFFSET[i]);
67808e7e278SJean Delvare }
67908e7e278SJean Delvare
6801ea6dd38SDavid Hubbard data->alarms = w83627ehf_read_value(data,
681a4589dbbSJean Delvare W83627EHF_REG_ALARM1) |
6821ea6dd38SDavid Hubbard (w83627ehf_read_value(data,
683a4589dbbSJean Delvare W83627EHF_REG_ALARM2) << 8) |
6841ea6dd38SDavid Hubbard (w83627ehf_read_value(data,
685a4589dbbSJean Delvare W83627EHF_REG_ALARM3) << 16);
686a4589dbbSJean Delvare
687363a12a4SDmitry Artamonow data->caseopen = w83627ehf_read_value(data,
688363a12a4SDmitry Artamonow W83627EHF_REG_CASEOPEN_DET);
689363a12a4SDmitry Artamonow
69008e7e278SJean Delvare data->last_updated = jiffies;
691952a11caSPaul Fertser data->valid = true;
69208e7e278SJean Delvare }
69308e7e278SJean Delvare
6949a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
69508e7e278SJean Delvare return data;
69608e7e278SJean Delvare }
69708e7e278SJean Delvare
698cf0676feSRudolf Marek #define store_in_reg(REG, reg) \
699266cd583SDr. David Alan Gilbert static int \
700266cd583SDr. David Alan Gilbert store_in_##reg(struct device *dev, struct w83627ehf_data *data, int channel, \
701266cd583SDr. David Alan Gilbert long val) \
702cf0676feSRudolf Marek { \
703266cd583SDr. David Alan Gilbert if (val < 0) \
704266cd583SDr. David Alan Gilbert return -EINVAL; \
705cf0676feSRudolf Marek mutex_lock(&data->update_lock); \
706266cd583SDr. David Alan Gilbert data->in_##reg[channel] = in_to_reg(val, channel, data->scale_in); \
707266cd583SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(channel), \
708266cd583SDr. David Alan Gilbert data->in_##reg[channel]); \
709cf0676feSRudolf Marek mutex_unlock(&data->update_lock); \
710266cd583SDr. David Alan Gilbert return 0; \
711cf0676feSRudolf Marek }
712cf0676feSRudolf Marek
store_in_reg(MIN,min)713cf0676feSRudolf Marek store_in_reg(MIN, min)
714cf0676feSRudolf Marek store_in_reg(MAX, max)
715cf0676feSRudolf Marek
716266cd583SDr. David Alan Gilbert static int
717266cd583SDr. David Alan Gilbert store_fan_min(struct device *dev, struct w83627ehf_data *data, int channel,
718266cd583SDr. David Alan Gilbert long val)
719a4589dbbSJean Delvare {
72008e7e278SJean Delvare unsigned int reg;
72108e7e278SJean Delvare u8 new_div;
72208e7e278SJean Delvare
723266cd583SDr. David Alan Gilbert if (val < 0)
724266cd583SDr. David Alan Gilbert return -EINVAL;
725bce26c58SGuenter Roeck
7269a61bf63SIngo Molnar mutex_lock(&data->update_lock);
72708e7e278SJean Delvare if (!val) {
72808e7e278SJean Delvare /* No min limit, alarm disabled */
729266cd583SDr. David Alan Gilbert data->fan_min[channel] = 255;
730266cd583SDr. David Alan Gilbert new_div = data->fan_div[channel]; /* No change */
731266cd583SDr. David Alan Gilbert dev_info(dev, "fan%u low limit and alarm disabled\n",
732266cd583SDr. David Alan Gilbert channel + 1);
73308e7e278SJean Delvare } else if ((reg = 1350000U / val) >= 128 * 255) {
7348969e84dSGuenter Roeck /*
7358969e84dSGuenter Roeck * Speed below this value cannot possibly be represented,
7368969e84dSGuenter Roeck * even with the highest divider (128)
7378969e84dSGuenter Roeck */
738266cd583SDr. David Alan Gilbert data->fan_min[channel] = 254;
73908e7e278SJean Delvare new_div = 7; /* 128 == (1 << 7) */
740b55f3757SGuenter Roeck dev_warn(dev,
741b55f3757SGuenter Roeck "fan%u low limit %lu below minimum %u, set to minimum\n",
74269595502SDr. David Alan Gilbert channel + 1, val, fan_from_reg8(254, 7));
74308e7e278SJean Delvare } else if (!reg) {
7448969e84dSGuenter Roeck /*
7458969e84dSGuenter Roeck * Speed above this value cannot possibly be represented,
7468969e84dSGuenter Roeck * even with the lowest divider (1)
7478969e84dSGuenter Roeck */
748266cd583SDr. David Alan Gilbert data->fan_min[channel] = 1;
74908e7e278SJean Delvare new_div = 0; /* 1 == (1 << 0) */
750b55f3757SGuenter Roeck dev_warn(dev,
751b55f3757SGuenter Roeck "fan%u low limit %lu above maximum %u, set to maximum\n",
75269595502SDr. David Alan Gilbert channel + 1, val, fan_from_reg8(1, 0));
75308e7e278SJean Delvare } else {
7548969e84dSGuenter Roeck /*
7558969e84dSGuenter Roeck * Automatically pick the best divider, i.e. the one such
7568969e84dSGuenter Roeck * that the min limit will correspond to a register value
7578969e84dSGuenter Roeck * in the 96..192 range
7588969e84dSGuenter Roeck */
75908e7e278SJean Delvare new_div = 0;
76008e7e278SJean Delvare while (reg > 192 && new_div < 7) {
76108e7e278SJean Delvare reg >>= 1;
76208e7e278SJean Delvare new_div++;
76308e7e278SJean Delvare }
764266cd583SDr. David Alan Gilbert data->fan_min[channel] = reg;
76508e7e278SJean Delvare }
76608e7e278SJean Delvare
7678969e84dSGuenter Roeck /*
7688969e84dSGuenter Roeck * Write both the fan clock divider (if it changed) and the new
7698969e84dSGuenter Roeck * fan min (unconditionally)
7708969e84dSGuenter Roeck */
771266cd583SDr. David Alan Gilbert if (new_div != data->fan_div[channel]) {
77208e7e278SJean Delvare dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
773266cd583SDr. David Alan Gilbert channel + 1, div_from_reg(data->fan_div[channel]),
77408e7e278SJean Delvare div_from_reg(new_div));
775266cd583SDr. David Alan Gilbert data->fan_div[channel] = new_div;
77669595502SDr. David Alan Gilbert w83627ehf_write_fan_div(data, channel);
7776b3e4645SJean Delvare /* Give the chip time to sample a new speed value */
7786b3e4645SJean Delvare data->last_updated = jiffies;
77908e7e278SJean Delvare }
78069595502SDr. David Alan Gilbert
78169595502SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[channel],
782266cd583SDr. David Alan Gilbert data->fan_min[channel]);
7839a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
78408e7e278SJean Delvare
785266cd583SDr. David Alan Gilbert return 0;
78608e7e278SJean Delvare }
78708e7e278SJean Delvare
788ec3e5a16SGuenter Roeck #define store_temp_reg(addr, reg) \
789266cd583SDr. David Alan Gilbert static int \
790266cd583SDr. David Alan Gilbert store_##reg(struct device *dev, struct w83627ehf_data *data, int channel, \
791266cd583SDr. David Alan Gilbert long val) \
79208e7e278SJean Delvare { \
7939a61bf63SIngo Molnar mutex_lock(&data->update_lock); \
794266cd583SDr. David Alan Gilbert data->reg[channel] = LM75_TEMP_TO_REG(val); \
795266cd583SDr. David Alan Gilbert w83627ehf_write_temp(data, data->addr[channel], data->reg[channel]); \
7969a61bf63SIngo Molnar mutex_unlock(&data->update_lock); \
797266cd583SDr. David Alan Gilbert return 0; \
79808e7e278SJean Delvare }
799ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_over, temp_max);
800ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_hyst, temp_max_hyst);
80108e7e278SJean Delvare
802266cd583SDr. David Alan Gilbert static int
store_temp_offset(struct device * dev,struct w83627ehf_data * data,int channel,long val)803266cd583SDr. David Alan Gilbert store_temp_offset(struct device *dev, struct w83627ehf_data *data, int channel,
804266cd583SDr. David Alan Gilbert long val)
805840e191dSGuenter Roeck {
8062a844c14SGuenter Roeck val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
807840e191dSGuenter Roeck
808840e191dSGuenter Roeck mutex_lock(&data->update_lock);
809266cd583SDr. David Alan Gilbert data->temp_offset[channel] = val;
810266cd583SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_TEMP_OFFSET[channel], val);
811840e191dSGuenter Roeck mutex_unlock(&data->update_lock);
812266cd583SDr. David Alan Gilbert return 0;
813840e191dSGuenter Roeck }
814840e191dSGuenter Roeck
815266cd583SDr. David Alan Gilbert static int
store_pwm_mode(struct device * dev,struct w83627ehf_data * data,int channel,long val)816266cd583SDr. David Alan Gilbert store_pwm_mode(struct device *dev, struct w83627ehf_data *data, int channel,
817266cd583SDr. David Alan Gilbert long val)
818da667365SJean Delvare {
81908c79950SRudolf Marek u16 reg;
82008c79950SRudolf Marek
821266cd583SDr. David Alan Gilbert if (val < 0 || val > 1)
82208c79950SRudolf Marek return -EINVAL;
823ad77c3e1SGuenter Roeck
82408c79950SRudolf Marek mutex_lock(&data->update_lock);
825266cd583SDr. David Alan Gilbert reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[channel]);
826266cd583SDr. David Alan Gilbert data->pwm_mode[channel] = val;
827266cd583SDr. David Alan Gilbert reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[channel]);
82808c79950SRudolf Marek if (!val)
829266cd583SDr. David Alan Gilbert reg |= 1 << W83627EHF_PWM_MODE_SHIFT[channel];
830266cd583SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[channel], reg);
83108c79950SRudolf Marek mutex_unlock(&data->update_lock);
832266cd583SDr. David Alan Gilbert return 0;
83308c79950SRudolf Marek }
83408c79950SRudolf Marek
835266cd583SDr. David Alan Gilbert static int
store_pwm(struct device * dev,struct w83627ehf_data * data,int channel,long val)836266cd583SDr. David Alan Gilbert store_pwm(struct device *dev, struct w83627ehf_data *data, int channel,
837266cd583SDr. David Alan Gilbert long val)
83808c79950SRudolf Marek {
8392a844c14SGuenter Roeck val = clamp_val(val, 0, 255);
84008c79950SRudolf Marek
84108c79950SRudolf Marek mutex_lock(&data->update_lock);
842266cd583SDr. David Alan Gilbert data->pwm[channel] = val;
84369595502SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_PWM[channel], val);
84408c79950SRudolf Marek mutex_unlock(&data->update_lock);
845266cd583SDr. David Alan Gilbert return 0;
84608c79950SRudolf Marek }
84708c79950SRudolf Marek
848266cd583SDr. David Alan Gilbert static int
store_pwm_enable(struct device * dev,struct w83627ehf_data * data,int channel,long val)849266cd583SDr. David Alan Gilbert store_pwm_enable(struct device *dev, struct w83627ehf_data *data, int channel,
850266cd583SDr. David Alan Gilbert long val)
85108c79950SRudolf Marek {
85208c79950SRudolf Marek u16 reg;
85308c79950SRudolf Marek
854266cd583SDr. David Alan Gilbert if (!val || val < 0 ||
855266cd583SDr. David Alan Gilbert (val > 4 && val != data->pwm_enable_orig[channel]))
85608c79950SRudolf Marek return -EINVAL;
857ec3e5a16SGuenter Roeck
85808c79950SRudolf Marek mutex_lock(&data->update_lock);
859266cd583SDr. David Alan Gilbert data->pwm_enable[channel] = val;
860266cd583SDr. David Alan Gilbert reg = w83627ehf_read_value(data,
861266cd583SDr. David Alan Gilbert W83627EHF_REG_PWM_ENABLE[channel]);
862266cd583SDr. David Alan Gilbert reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[channel]);
863266cd583SDr. David Alan Gilbert reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[channel];
864266cd583SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[channel],
865266cd583SDr. David Alan Gilbert reg);
86608c79950SRudolf Marek mutex_unlock(&data->update_lock);
867266cd583SDr. David Alan Gilbert return 0;
86808c79950SRudolf Marek }
86908c79950SRudolf Marek
87008c79950SRudolf Marek #define show_tol_temp(reg) \
87108c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
87208c79950SRudolf Marek char *buf) \
87308c79950SRudolf Marek { \
874266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = w83627ehf_update_device(dev->parent); \
875e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \
876e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \
87708c79950SRudolf Marek int nr = sensor_attr->index; \
878bce26c58SGuenter Roeck return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
87908c79950SRudolf Marek }
88008c79950SRudolf Marek
88108c79950SRudolf Marek show_tol_temp(tolerance)
show_tol_temp(target_temp)88208c79950SRudolf Marek show_tol_temp(target_temp)
88308c79950SRudolf Marek
88408c79950SRudolf Marek static ssize_t
88508c79950SRudolf Marek store_target_temp(struct device *dev, struct device_attribute *attr,
88608c79950SRudolf Marek const char *buf, size_t count)
88708c79950SRudolf Marek {
8881ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev);
88908c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
89008c79950SRudolf Marek int nr = sensor_attr->index;
891bce26c58SGuenter Roeck long val;
892bce26c58SGuenter Roeck int err;
893bce26c58SGuenter Roeck
894179c4fdbSFrans Meulenbroeks err = kstrtol(buf, 10, &val);
895bce26c58SGuenter Roeck if (err < 0)
896bce26c58SGuenter Roeck return err;
897bce26c58SGuenter Roeck
8982a844c14SGuenter Roeck val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
89908c79950SRudolf Marek
90008c79950SRudolf Marek mutex_lock(&data->update_lock);
90108c79950SRudolf Marek data->target_temp[nr] = val;
90269595502SDr. David Alan Gilbert w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
90308c79950SRudolf Marek mutex_unlock(&data->update_lock);
90408c79950SRudolf Marek return count;
90508c79950SRudolf Marek }
90608c79950SRudolf Marek
90708c79950SRudolf Marek static ssize_t
store_tolerance(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)90808c79950SRudolf Marek store_tolerance(struct device *dev, struct device_attribute *attr,
90908c79950SRudolf Marek const char *buf, size_t count)
91008c79950SRudolf Marek {
9111ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev);
91208c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
91308c79950SRudolf Marek int nr = sensor_attr->index;
91408c79950SRudolf Marek u16 reg;
915bce26c58SGuenter Roeck long val;
916bce26c58SGuenter Roeck int err;
917bce26c58SGuenter Roeck
918179c4fdbSFrans Meulenbroeks err = kstrtol(buf, 10, &val);
919bce26c58SGuenter Roeck if (err < 0)
920bce26c58SGuenter Roeck return err;
921bce26c58SGuenter Roeck
92208c79950SRudolf Marek /* Limit the temp to 0C - 15C */
9232a844c14SGuenter Roeck val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 15000), 1000);
92408c79950SRudolf Marek
92508c79950SRudolf Marek mutex_lock(&data->update_lock);
9261ea6dd38SDavid Hubbard reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
92708c79950SRudolf Marek if (nr == 1)
92808c79950SRudolf Marek reg = (reg & 0x0f) | (val << 4);
92908c79950SRudolf Marek else
93008c79950SRudolf Marek reg = (reg & 0xf0) | val;
9311ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
932ec3e5a16SGuenter Roeck data->tolerance[nr] = val;
93308c79950SRudolf Marek mutex_unlock(&data->update_lock);
93408c79950SRudolf Marek return count;
93508c79950SRudolf Marek }
93608c79950SRudolf Marek
9378f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_target, 0644, show_target_temp,
938266cd583SDr. David Alan Gilbert store_target_temp, 0);
9398f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_target, 0644, show_target_temp,
940266cd583SDr. David Alan Gilbert store_target_temp, 1);
9418f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_target, 0644, show_target_temp,
942266cd583SDr. David Alan Gilbert store_target_temp, 2);
9438f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_target, 0644, show_target_temp,
944266cd583SDr. David Alan Gilbert store_target_temp, 3);
94508c79950SRudolf Marek
9468f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_tolerance, 0644, show_tolerance,
947266cd583SDr. David Alan Gilbert store_tolerance, 0);
9488f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_tolerance, 0644, show_tolerance,
949266cd583SDr. David Alan Gilbert store_tolerance, 1);
9508f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_tolerance, 0644, show_tolerance,
951266cd583SDr. David Alan Gilbert store_tolerance, 2);
9528f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_tolerance, 0644, show_tolerance,
953266cd583SDr. David Alan Gilbert store_tolerance, 3);
95408c79950SRudolf Marek
95508c79950SRudolf Marek /* Smart Fan registers */
95608c79950SRudolf Marek
95708c79950SRudolf Marek #define fan_functions(reg, REG) \
95808c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
95908c79950SRudolf Marek char *buf) \
96008c79950SRudolf Marek { \
961266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = w83627ehf_update_device(dev->parent); \
962e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \
963e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \
96408c79950SRudolf Marek int nr = sensor_attr->index; \
96508c79950SRudolf Marek return sprintf(buf, "%d\n", data->reg[nr]); \
96608c79950SRudolf Marek } \
96708c79950SRudolf Marek static ssize_t \
96808c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \
96908c79950SRudolf Marek const char *buf, size_t count) \
97008c79950SRudolf Marek { \
9711ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); \
972e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \
973e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \
97408c79950SRudolf Marek int nr = sensor_attr->index; \
975bce26c58SGuenter Roeck unsigned long val; \
976bce26c58SGuenter Roeck int err; \
977179c4fdbSFrans Meulenbroeks err = kstrtoul(buf, 10, &val); \
978bce26c58SGuenter Roeck if (err < 0) \
979bce26c58SGuenter Roeck return err; \
9802a844c14SGuenter Roeck val = clamp_val(val, 1, 255); \
98108c79950SRudolf Marek mutex_lock(&data->update_lock); \
98208c79950SRudolf Marek data->reg[nr] = val; \
98369595502SDr. David Alan Gilbert w83627ehf_write_value(data, REG[nr], val); \
98408c79950SRudolf Marek mutex_unlock(&data->update_lock); \
98508c79950SRudolf Marek return count; \
98608c79950SRudolf Marek }
98708c79950SRudolf Marek
98869595502SDr. David Alan Gilbert fan_functions(fan_start_output, W83627EHF_REG_FAN_START_OUTPUT)
98969595502SDr. David Alan Gilbert fan_functions(fan_stop_output, W83627EHF_REG_FAN_STOP_OUTPUT)
99069595502SDr. David Alan Gilbert fan_functions(fan_max_output, data->REG_FAN_MAX_OUTPUT)
99169595502SDr. David Alan Gilbert fan_functions(fan_step_output, data->REG_FAN_STEP_OUTPUT)
99208c79950SRudolf Marek
99308c79950SRudolf Marek #define fan_time_functions(reg, REG) \
99408c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
99508c79950SRudolf Marek char *buf) \
99608c79950SRudolf Marek { \
997266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = w83627ehf_update_device(dev->parent); \
998e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \
999e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \
100008c79950SRudolf Marek int nr = sensor_attr->index; \
100108c79950SRudolf Marek return sprintf(buf, "%d\n", \
1002e7e1ca6eSGuenter Roeck step_time_from_reg(data->reg[nr], \
1003e7e1ca6eSGuenter Roeck data->pwm_mode[nr])); \
100408c79950SRudolf Marek } \
100508c79950SRudolf Marek \
100608c79950SRudolf Marek static ssize_t \
100708c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \
100808c79950SRudolf Marek const char *buf, size_t count) \
100908c79950SRudolf Marek { \
10101ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); \
1011e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \
1012e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \
101308c79950SRudolf Marek int nr = sensor_attr->index; \
1014bce26c58SGuenter Roeck unsigned long val; \
1015bce26c58SGuenter Roeck int err; \
1016179c4fdbSFrans Meulenbroeks err = kstrtoul(buf, 10, &val); \
1017bce26c58SGuenter Roeck if (err < 0) \
1018bce26c58SGuenter Roeck return err; \
1019bce26c58SGuenter Roeck val = step_time_to_reg(val, data->pwm_mode[nr]); \
102008c79950SRudolf Marek mutex_lock(&data->update_lock); \
102108c79950SRudolf Marek data->reg[nr] = val; \
102269595502SDr. David Alan Gilbert w83627ehf_write_value(data, REG[nr], val); \
102308c79950SRudolf Marek mutex_unlock(&data->update_lock); \
102408c79950SRudolf Marek return count; \
102508c79950SRudolf Marek } \
102608c79950SRudolf Marek
102769595502SDr. David Alan Gilbert fan_time_functions(fan_stop_time, W83627EHF_REG_FAN_STOP_TIME)
102808c79950SRudolf Marek
10298f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_stop_time, 0644, show_fan_stop_time,
1030266cd583SDr. David Alan Gilbert store_fan_stop_time, 3);
10318f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_start_output, 0644, show_fan_start_output,
1032266cd583SDr. David Alan Gilbert store_fan_start_output, 3);
10338f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_stop_output, 0644, show_fan_stop_output,
1034266cd583SDr. David Alan Gilbert store_fan_stop_output, 3);
10358f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_max_output, 0644, show_fan_max_output,
1036266cd583SDr. David Alan Gilbert store_fan_max_output, 3);
10378f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_step_output, 0644, show_fan_step_output,
1038266cd583SDr. David Alan Gilbert store_fan_step_output, 3);
10391ea6dd38SDavid Hubbard
10408f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_stop_time, 0644, show_fan_stop_time,
1041266cd583SDr. David Alan Gilbert store_fan_stop_time, 2);
10428f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_start_output, 0644, show_fan_start_output,
1043266cd583SDr. David Alan Gilbert store_fan_start_output, 2);
10448f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_stop_output, 0644, show_fan_stop_output,
1045266cd583SDr. David Alan Gilbert store_fan_stop_output, 2);
104608c79950SRudolf Marek
10478f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_stop_time, 0644, show_fan_stop_time,
1048266cd583SDr. David Alan Gilbert store_fan_stop_time, 0);
10498f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_stop_time, 0644, show_fan_stop_time,
1050266cd583SDr. David Alan Gilbert store_fan_stop_time, 1);
10518f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_start_output, 0644, show_fan_start_output,
1052266cd583SDr. David Alan Gilbert store_fan_start_output, 0);
10538f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_start_output, 0644, show_fan_start_output,
1054266cd583SDr. David Alan Gilbert store_fan_start_output, 1);
10558f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_stop_output, 0644, show_fan_stop_output,
1056266cd583SDr. David Alan Gilbert store_fan_stop_output, 0);
10578f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_stop_output, 0644, show_fan_stop_output,
1058266cd583SDr. David Alan Gilbert store_fan_stop_output, 1);
105941e9a062SDaniel J Blueman
1060da2e0255SGuenter Roeck
1061da2e0255SGuenter Roeck /*
1062da2e0255SGuenter Roeck * pwm1 and pwm3 don't support max and step settings on all chips.
1063da2e0255SGuenter Roeck * Need to check support while generating/removing attribute files.
1064da2e0255SGuenter Roeck */
10658f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_max_output, 0644, show_fan_max_output,
1066266cd583SDr. David Alan Gilbert store_fan_max_output, 0);
10678f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_step_output, 0644, show_fan_step_output,
1068266cd583SDr. David Alan Gilbert store_fan_step_output, 0);
10698f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_max_output, 0644, show_fan_max_output,
1070266cd583SDr. David Alan Gilbert store_fan_max_output, 1);
10718f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_step_output, 0644, show_fan_step_output,
1072266cd583SDr. David Alan Gilbert store_fan_step_output, 1);
10738f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_max_output, 0644, show_fan_max_output,
1074266cd583SDr. David Alan Gilbert store_fan_max_output, 2);
10758f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_step_output, 0644, show_fan_step_output,
1076266cd583SDr. David Alan Gilbert store_fan_step_output, 2);
107708c79950SRudolf Marek
1078fc18d6c0SJean Delvare static ssize_t
cpu0_vid_show(struct device * dev,struct device_attribute * attr,char * buf)10799bbacbfeSJulia Lawall cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
1080fc18d6c0SJean Delvare {
1081fc18d6c0SJean Delvare struct w83627ehf_data *data = dev_get_drvdata(dev);
1082fc18d6c0SJean Delvare return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1083fc18d6c0SJean Delvare }
10846f447ce0SArmin Wolf static DEVICE_ATTR_RO(cpu0_vid);
1085fc18d6c0SJean Delvare
1086363a12a4SDmitry Artamonow
1087363a12a4SDmitry Artamonow /* Case open detection */
1088266cd583SDr. David Alan Gilbert static int
clear_caseopen(struct device * dev,struct w83627ehf_data * data,int channel,long val)1089266cd583SDr. David Alan Gilbert clear_caseopen(struct device *dev, struct w83627ehf_data *data, int channel,
1090266cd583SDr. David Alan Gilbert long val)
1091363a12a4SDmitry Artamonow {
1092931f397bSDr. David Alan Gilbert const u16 mask = 0x80;
1093931f397bSDr. David Alan Gilbert u16 reg;
1094363a12a4SDmitry Artamonow
1095931f397bSDr. David Alan Gilbert if (val != 0 || channel != 0)
1096363a12a4SDmitry Artamonow return -EINVAL;
1097363a12a4SDmitry Artamonow
1098363a12a4SDmitry Artamonow mutex_lock(&data->update_lock);
1099363a12a4SDmitry Artamonow reg = w83627ehf_read_value(data, W83627EHF_REG_CASEOPEN_CLR);
1100363a12a4SDmitry Artamonow w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg | mask);
1101363a12a4SDmitry Artamonow w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg & ~mask);
1102952a11caSPaul Fertser data->valid = false; /* Force cache refresh */
1103363a12a4SDmitry Artamonow mutex_unlock(&data->update_lock);
1104363a12a4SDmitry Artamonow
1105266cd583SDr. David Alan Gilbert return 0;
1106363a12a4SDmitry Artamonow }
1107363a12a4SDmitry Artamonow
w83627ehf_attrs_visible(struct kobject * kobj,struct attribute * a,int n)1108266cd583SDr. David Alan Gilbert static umode_t w83627ehf_attrs_visible(struct kobject *kobj,
1109266cd583SDr. David Alan Gilbert struct attribute *a, int n)
1110266cd583SDr. David Alan Gilbert {
11115707c8dbSTian Tao struct device *dev = kobj_to_dev(kobj);
1112266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = dev_get_drvdata(dev);
1113266cd583SDr. David Alan Gilbert struct device_attribute *devattr;
1114266cd583SDr. David Alan Gilbert struct sensor_device_attribute *sda;
1115266cd583SDr. David Alan Gilbert
1116266cd583SDr. David Alan Gilbert devattr = container_of(a, struct device_attribute, attr);
1117266cd583SDr. David Alan Gilbert
1118266cd583SDr. David Alan Gilbert /* Not sensor */
1119266cd583SDr. David Alan Gilbert if (devattr->show == cpu0_vid_show && data->have_vid)
1120266cd583SDr. David Alan Gilbert return a->mode;
1121266cd583SDr. David Alan Gilbert
1122266cd583SDr. David Alan Gilbert sda = (struct sensor_device_attribute *)devattr;
1123266cd583SDr. David Alan Gilbert
1124266cd583SDr. David Alan Gilbert if (sda->index < 2 &&
1125266cd583SDr. David Alan Gilbert (devattr->show == show_fan_stop_time ||
1126266cd583SDr. David Alan Gilbert devattr->show == show_fan_start_output ||
1127266cd583SDr. David Alan Gilbert devattr->show == show_fan_stop_output))
1128266cd583SDr. David Alan Gilbert return a->mode;
1129266cd583SDr. David Alan Gilbert
1130266cd583SDr. David Alan Gilbert if (sda->index < 3 &&
1131266cd583SDr. David Alan Gilbert (devattr->show == show_fan_max_output ||
1132266cd583SDr. David Alan Gilbert devattr->show == show_fan_step_output) &&
1133266cd583SDr. David Alan Gilbert data->REG_FAN_STEP_OUTPUT &&
1134266cd583SDr. David Alan Gilbert data->REG_FAN_STEP_OUTPUT[sda->index] != 0xff)
1135266cd583SDr. David Alan Gilbert return a->mode;
1136266cd583SDr. David Alan Gilbert
1137266cd583SDr. David Alan Gilbert /* if fan3 and fan4 are enabled create the files for them */
1138266cd583SDr. David Alan Gilbert if (sda->index == 2 &&
1139266cd583SDr. David Alan Gilbert (data->has_fan & (1 << 2)) && data->pwm_num >= 3 &&
1140266cd583SDr. David Alan Gilbert (devattr->show == show_fan_stop_time ||
1141266cd583SDr. David Alan Gilbert devattr->show == show_fan_start_output ||
1142266cd583SDr. David Alan Gilbert devattr->show == show_fan_stop_output))
1143266cd583SDr. David Alan Gilbert return a->mode;
1144266cd583SDr. David Alan Gilbert
1145266cd583SDr. David Alan Gilbert if (sda->index == 3 &&
1146266cd583SDr. David Alan Gilbert (data->has_fan & (1 << 3)) && data->pwm_num >= 4 &&
1147266cd583SDr. David Alan Gilbert (devattr->show == show_fan_stop_time ||
1148266cd583SDr. David Alan Gilbert devattr->show == show_fan_start_output ||
1149266cd583SDr. David Alan Gilbert devattr->show == show_fan_stop_output ||
1150266cd583SDr. David Alan Gilbert devattr->show == show_fan_max_output ||
1151266cd583SDr. David Alan Gilbert devattr->show == show_fan_step_output))
1152266cd583SDr. David Alan Gilbert return a->mode;
1153266cd583SDr. David Alan Gilbert
1154266cd583SDr. David Alan Gilbert if ((devattr->show == show_target_temp ||
1155266cd583SDr. David Alan Gilbert devattr->show == show_tolerance) &&
1156266cd583SDr. David Alan Gilbert (data->has_fan & (1 << sda->index)) &&
1157266cd583SDr. David Alan Gilbert sda->index < data->pwm_num)
1158266cd583SDr. David Alan Gilbert return a->mode;
1159266cd583SDr. David Alan Gilbert
1160266cd583SDr. David Alan Gilbert return 0;
1161266cd583SDr. David Alan Gilbert }
1162266cd583SDr. David Alan Gilbert
1163266cd583SDr. David Alan Gilbert /* These groups handle non-standard attributes used in this device */
1164266cd583SDr. David Alan Gilbert static struct attribute *w83627ehf_attrs[] = {
1165266cd583SDr. David Alan Gilbert
1166266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
1167266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_start_output.dev_attr.attr,
1168266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_stop_output.dev_attr.attr,
1169266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_max_output.dev_attr.attr,
1170266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_step_output.dev_attr.attr,
1171266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_target.dev_attr.attr,
1172266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm1_tolerance.dev_attr.attr,
1173266cd583SDr. David Alan Gilbert
1174266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
1175266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_start_output.dev_attr.attr,
1176266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_stop_output.dev_attr.attr,
1177266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_max_output.dev_attr.attr,
1178266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_step_output.dev_attr.attr,
1179266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_target.dev_attr.attr,
1180266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm2_tolerance.dev_attr.attr,
1181266cd583SDr. David Alan Gilbert
1182266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
1183266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_start_output.dev_attr.attr,
1184266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_stop_output.dev_attr.attr,
1185266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_max_output.dev_attr.attr,
1186266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_step_output.dev_attr.attr,
1187266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_target.dev_attr.attr,
1188266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm3_tolerance.dev_attr.attr,
1189266cd583SDr. David Alan Gilbert
1190266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
1191266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_start_output.dev_attr.attr,
1192266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_stop_output.dev_attr.attr,
1193266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_max_output.dev_attr.attr,
1194266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_step_output.dev_attr.attr,
1195266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_target.dev_attr.attr,
1196266cd583SDr. David Alan Gilbert &sensor_dev_attr_pwm4_tolerance.dev_attr.attr,
1197266cd583SDr. David Alan Gilbert
1198266cd583SDr. David Alan Gilbert &dev_attr_cpu0_vid.attr,
1199266cd583SDr. David Alan Gilbert NULL
1200266cd583SDr. David Alan Gilbert };
1201266cd583SDr. David Alan Gilbert
1202266cd583SDr. David Alan Gilbert static const struct attribute_group w83627ehf_group = {
1203266cd583SDr. David Alan Gilbert .attrs = w83627ehf_attrs,
1204266cd583SDr. David Alan Gilbert .is_visible = w83627ehf_attrs_visible,
1205266cd583SDr. David Alan Gilbert };
1206266cd583SDr. David Alan Gilbert
1207266cd583SDr. David Alan Gilbert static const struct attribute_group *w83627ehf_groups[] = {
1208266cd583SDr. David Alan Gilbert &w83627ehf_group,
1209266cd583SDr. David Alan Gilbert NULL
1210363a12a4SDmitry Artamonow };
1211363a12a4SDmitry Artamonow
121208e7e278SJean Delvare /*
12131ea6dd38SDavid Hubbard * Driver and device management
121408e7e278SJean Delvare */
121508e7e278SJean Delvare
12161ea6dd38SDavid Hubbard /* Get the monitoring functions started */
w83627ehf_init_device(struct w83627ehf_data * data,enum kinds kind)12176c931ae1SBill Pemberton static inline void w83627ehf_init_device(struct w83627ehf_data *data,
1218bf164c58SJean Delvare enum kinds kind)
121908e7e278SJean Delvare {
122008e7e278SJean Delvare int i;
1221da667365SJean Delvare u8 tmp, diode;
122208e7e278SJean Delvare
122308e7e278SJean Delvare /* Start monitoring is needed */
12241ea6dd38SDavid Hubbard tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
122508e7e278SJean Delvare if (!(tmp & 0x01))
12261ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
122708e7e278SJean Delvare tmp | 0x01);
122808e7e278SJean Delvare
1229d36cf32cSGuenter Roeck /* Enable temperature sensors if needed */
1230d36cf32cSGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) {
1231d36cf32cSGuenter Roeck if (!(data->have_temp & (1 << i)))
1232d36cf32cSGuenter Roeck continue;
1233ec3e5a16SGuenter Roeck if (!data->reg_temp_config[i])
1234d36cf32cSGuenter Roeck continue;
12351ea6dd38SDavid Hubbard tmp = w83627ehf_read_value(data,
1236ec3e5a16SGuenter Roeck data->reg_temp_config[i]);
123708e7e278SJean Delvare if (tmp & 0x01)
12381ea6dd38SDavid Hubbard w83627ehf_write_value(data,
1239ec3e5a16SGuenter Roeck data->reg_temp_config[i],
124008e7e278SJean Delvare tmp & 0xfe);
124108e7e278SJean Delvare }
1242d3130f0eSJean Delvare
1243d3130f0eSJean Delvare /* Enable VBAT monitoring if needed */
1244d3130f0eSJean Delvare tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1245d3130f0eSJean Delvare if (!(tmp & 0x01))
1246d3130f0eSJean Delvare w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
1247da667365SJean Delvare
1248da667365SJean Delvare /* Get thermal sensor types */
1249bf164c58SJean Delvare switch (kind) {
1250bf164c58SJean Delvare case w83627ehf:
1251da667365SJean Delvare diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1252bf164c58SJean Delvare break;
1253eff7687dSJean Delvare case w83627uhg:
1254eff7687dSJean Delvare diode = 0x00;
1255eff7687dSJean Delvare break;
1256bf164c58SJean Delvare default:
1257bf164c58SJean Delvare diode = 0x70;
1258bf164c58SJean Delvare }
1259da667365SJean Delvare for (i = 0; i < 3; i++) {
1260bfa02b0dSGuenter Roeck const char *label = NULL;
1261bfa02b0dSGuenter Roeck
1262bfa02b0dSGuenter Roeck if (data->temp_label)
1263bfa02b0dSGuenter Roeck label = data->temp_label[data->temp_src[i]];
12642265cef2SJean Delvare
12652265cef2SJean Delvare /* Digital source overrides analog type */
1266bfa02b0dSGuenter Roeck if (label && strncmp(label, "PECI", 4) == 0)
12672265cef2SJean Delvare data->temp_type[i] = 6;
1268bfa02b0dSGuenter Roeck else if (label && strncmp(label, "AMD", 3) == 0)
12692265cef2SJean Delvare data->temp_type[i] = 5;
12702265cef2SJean Delvare else if ((tmp & (0x02 << i)))
1271bf164c58SJean Delvare data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
1272da667365SJean Delvare else
1273da667365SJean Delvare data->temp_type[i] = 4; /* thermistor */
1274da667365SJean Delvare }
127508e7e278SJean Delvare }
127608e7e278SJean Delvare
12776c931ae1SBill Pemberton static void
w83627ehf_set_temp_reg_ehf(struct w83627ehf_data * data,int n_temp)12786ba71de5SJean Delvare w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp)
12796ba71de5SJean Delvare {
12806ba71de5SJean Delvare int i;
12816ba71de5SJean Delvare
12826ba71de5SJean Delvare for (i = 0; i < n_temp; i++) {
12836ba71de5SJean Delvare data->reg_temp[i] = W83627EHF_REG_TEMP[i];
12846ba71de5SJean Delvare data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
12856ba71de5SJean Delvare data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
12866ba71de5SJean Delvare data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
12876ba71de5SJean Delvare }
12886ba71de5SJean Delvare }
12896ba71de5SJean Delvare
12906c931ae1SBill Pemberton static void
w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data * sio_data,struct w83627ehf_data * data)129103f5de2bSJean Delvare w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
129203f5de2bSJean Delvare struct w83627ehf_data *data)
129303f5de2bSJean Delvare {
129439292371SYueHaibing int fan3pin, fan4pin, fan5pin, regval;
129503f5de2bSJean Delvare
1296eff7687dSJean Delvare /* The W83627UHG is simple, only two fan inputs, no config */
1297eff7687dSJean Delvare if (sio_data->kind == w83627uhg) {
1298eff7687dSJean Delvare data->has_fan = 0x03; /* fan1 and fan2 */
1299eff7687dSJean Delvare data->has_fan_min = 0x03;
1300eff7687dSJean Delvare return;
1301eff7687dSJean Delvare }
1302eff7687dSJean Delvare
130303f5de2bSJean Delvare /* fan4 and fan5 share some pins with the GPIO and serial flash */
13043207408aSDr. David Alan Gilbert if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
130503f5de2bSJean Delvare fan3pin = 1;
130603f5de2bSJean Delvare fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
130703f5de2bSJean Delvare fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
130803f5de2bSJean Delvare } else {
130903f5de2bSJean Delvare fan3pin = 1;
131003f5de2bSJean Delvare fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
131103f5de2bSJean Delvare fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
131203f5de2bSJean Delvare }
131303f5de2bSJean Delvare
131403f5de2bSJean Delvare data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
131503f5de2bSJean Delvare data->has_fan |= (fan3pin << 2);
131603f5de2bSJean Delvare data->has_fan_min |= (fan3pin << 2);
131703f5de2bSJean Delvare
131803f5de2bSJean Delvare /*
131903f5de2bSJean Delvare * It looks like fan4 and fan5 pins can be alternatively used
132003f5de2bSJean Delvare * as fan on/off switches, but fan5 control is write only :/
132103f5de2bSJean Delvare * We assume that if the serial interface is disabled, designers
132203f5de2bSJean Delvare * connected fan5 as input unless they are emitting log 1, which
132303f5de2bSJean Delvare * is not the default.
132403f5de2bSJean Delvare */
132503f5de2bSJean Delvare regval = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
132603f5de2bSJean Delvare if ((regval & (1 << 2)) && fan4pin) {
132703f5de2bSJean Delvare data->has_fan |= (1 << 3);
132803f5de2bSJean Delvare data->has_fan_min |= (1 << 3);
132903f5de2bSJean Delvare }
133003f5de2bSJean Delvare if (!(regval & (1 << 1)) && fan5pin) {
133103f5de2bSJean Delvare data->has_fan |= (1 << 4);
133203f5de2bSJean Delvare data->has_fan_min |= (1 << 4);
133303f5de2bSJean Delvare }
133403f5de2bSJean Delvare }
133503f5de2bSJean Delvare
1336266cd583SDr. David Alan Gilbert static umode_t
w83627ehf_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)1337266cd583SDr. David Alan Gilbert w83627ehf_is_visible(const void *drvdata, enum hwmon_sensor_types type,
1338266cd583SDr. David Alan Gilbert u32 attr, int channel)
1339266cd583SDr. David Alan Gilbert {
1340266cd583SDr. David Alan Gilbert const struct w83627ehf_data *data = drvdata;
1341266cd583SDr. David Alan Gilbert
1342266cd583SDr. David Alan Gilbert switch (type) {
1343266cd583SDr. David Alan Gilbert case hwmon_temp:
1344266cd583SDr. David Alan Gilbert /* channel 0.., name 1.. */
1345266cd583SDr. David Alan Gilbert if (!(data->have_temp & (1 << channel)))
1346266cd583SDr. David Alan Gilbert return 0;
1347e61d2392SGuenter Roeck if (attr == hwmon_temp_input)
1348266cd583SDr. David Alan Gilbert return 0444;
1349e61d2392SGuenter Roeck if (attr == hwmon_temp_label) {
1350e61d2392SGuenter Roeck if (data->temp_label)
1351e61d2392SGuenter Roeck return 0444;
1352e61d2392SGuenter Roeck return 0;
1353e61d2392SGuenter Roeck }
1354266cd583SDr. David Alan Gilbert if (channel == 2 && data->temp3_val_only)
1355266cd583SDr. David Alan Gilbert return 0;
1356266cd583SDr. David Alan Gilbert if (attr == hwmon_temp_max) {
1357266cd583SDr. David Alan Gilbert if (data->reg_temp_over[channel])
1358266cd583SDr. David Alan Gilbert return 0644;
1359266cd583SDr. David Alan Gilbert else
1360266cd583SDr. David Alan Gilbert return 0;
1361266cd583SDr. David Alan Gilbert }
1362266cd583SDr. David Alan Gilbert if (attr == hwmon_temp_max_hyst) {
1363266cd583SDr. David Alan Gilbert if (data->reg_temp_hyst[channel])
1364266cd583SDr. David Alan Gilbert return 0644;
1365266cd583SDr. David Alan Gilbert else
1366266cd583SDr. David Alan Gilbert return 0;
1367266cd583SDr. David Alan Gilbert }
1368266cd583SDr. David Alan Gilbert if (channel > 2)
1369266cd583SDr. David Alan Gilbert return 0;
1370266cd583SDr. David Alan Gilbert if (attr == hwmon_temp_alarm || attr == hwmon_temp_type)
1371266cd583SDr. David Alan Gilbert return 0444;
1372266cd583SDr. David Alan Gilbert if (attr == hwmon_temp_offset) {
1373266cd583SDr. David Alan Gilbert if (data->have_temp_offset & (1 << channel))
1374266cd583SDr. David Alan Gilbert return 0644;
1375266cd583SDr. David Alan Gilbert else
1376266cd583SDr. David Alan Gilbert return 0;
1377266cd583SDr. David Alan Gilbert }
1378266cd583SDr. David Alan Gilbert break;
1379266cd583SDr. David Alan Gilbert
1380266cd583SDr. David Alan Gilbert case hwmon_fan:
1381266cd583SDr. David Alan Gilbert /* channel 0.., name 1.. */
1382266cd583SDr. David Alan Gilbert if (!(data->has_fan & (1 << channel)))
1383266cd583SDr. David Alan Gilbert return 0;
1384266cd583SDr. David Alan Gilbert if (attr == hwmon_fan_input || attr == hwmon_fan_alarm)
1385266cd583SDr. David Alan Gilbert return 0444;
1386266cd583SDr. David Alan Gilbert if (attr == hwmon_fan_div) {
1387266cd583SDr. David Alan Gilbert return 0444;
1388266cd583SDr. David Alan Gilbert }
1389266cd583SDr. David Alan Gilbert if (attr == hwmon_fan_min) {
1390266cd583SDr. David Alan Gilbert if (data->has_fan_min & (1 << channel))
1391266cd583SDr. David Alan Gilbert return 0644;
1392266cd583SDr. David Alan Gilbert else
1393266cd583SDr. David Alan Gilbert return 0;
1394266cd583SDr. David Alan Gilbert }
1395266cd583SDr. David Alan Gilbert break;
1396266cd583SDr. David Alan Gilbert
1397266cd583SDr. David Alan Gilbert case hwmon_in:
1398266cd583SDr. David Alan Gilbert /* channel 0.., name 0.. */
1399266cd583SDr. David Alan Gilbert if (channel >= data->in_num)
1400266cd583SDr. David Alan Gilbert return 0;
1401266cd583SDr. David Alan Gilbert if (channel == 6 && data->in6_skip)
1402266cd583SDr. David Alan Gilbert return 0;
1403266cd583SDr. David Alan Gilbert if (attr == hwmon_in_alarm || attr == hwmon_in_input)
1404266cd583SDr. David Alan Gilbert return 0444;
1405266cd583SDr. David Alan Gilbert if (attr == hwmon_in_min || attr == hwmon_in_max)
1406266cd583SDr. David Alan Gilbert return 0644;
1407266cd583SDr. David Alan Gilbert break;
1408266cd583SDr. David Alan Gilbert
1409266cd583SDr. David Alan Gilbert case hwmon_pwm:
1410266cd583SDr. David Alan Gilbert /* channel 0.., name 1.. */
1411266cd583SDr. David Alan Gilbert if (!(data->has_fan & (1 << channel)) ||
1412266cd583SDr. David Alan Gilbert channel >= data->pwm_num)
1413266cd583SDr. David Alan Gilbert return 0;
1414266cd583SDr. David Alan Gilbert if (attr == hwmon_pwm_mode || attr == hwmon_pwm_enable ||
1415266cd583SDr. David Alan Gilbert attr == hwmon_pwm_input)
1416266cd583SDr. David Alan Gilbert return 0644;
1417266cd583SDr. David Alan Gilbert break;
1418266cd583SDr. David Alan Gilbert
1419266cd583SDr. David Alan Gilbert case hwmon_intrusion:
1420266cd583SDr. David Alan Gilbert return 0644;
1421266cd583SDr. David Alan Gilbert
1422266cd583SDr. David Alan Gilbert default: /* Shouldn't happen */
1423266cd583SDr. David Alan Gilbert return 0;
1424266cd583SDr. David Alan Gilbert }
1425266cd583SDr. David Alan Gilbert
1426266cd583SDr. David Alan Gilbert return 0; /* Shouldn't happen */
1427266cd583SDr. David Alan Gilbert }
1428266cd583SDr. David Alan Gilbert
1429266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_temp(struct w83627ehf_data * data,u32 attr,int channel,long * val)1430266cd583SDr. David Alan Gilbert w83627ehf_do_read_temp(struct w83627ehf_data *data, u32 attr,
1431266cd583SDr. David Alan Gilbert int channel, long *val)
1432266cd583SDr. David Alan Gilbert {
1433266cd583SDr. David Alan Gilbert switch (attr) {
1434266cd583SDr. David Alan Gilbert case hwmon_temp_input:
1435266cd583SDr. David Alan Gilbert *val = LM75_TEMP_FROM_REG(data->temp[channel]);
1436266cd583SDr. David Alan Gilbert return 0;
1437266cd583SDr. David Alan Gilbert case hwmon_temp_max:
1438266cd583SDr. David Alan Gilbert *val = LM75_TEMP_FROM_REG(data->temp_max[channel]);
1439266cd583SDr. David Alan Gilbert return 0;
1440266cd583SDr. David Alan Gilbert case hwmon_temp_max_hyst:
1441266cd583SDr. David Alan Gilbert *val = LM75_TEMP_FROM_REG(data->temp_max_hyst[channel]);
1442266cd583SDr. David Alan Gilbert return 0;
1443266cd583SDr. David Alan Gilbert case hwmon_temp_offset:
1444266cd583SDr. David Alan Gilbert *val = data->temp_offset[channel] * 1000;
1445266cd583SDr. David Alan Gilbert return 0;
1446266cd583SDr. David Alan Gilbert case hwmon_temp_type:
1447266cd583SDr. David Alan Gilbert *val = (int)data->temp_type[channel];
1448266cd583SDr. David Alan Gilbert return 0;
1449266cd583SDr. David Alan Gilbert case hwmon_temp_alarm:
1450266cd583SDr. David Alan Gilbert if (channel < 3) {
1451266cd583SDr. David Alan Gilbert static const int bit[] = { 4, 5, 13 };
1452266cd583SDr. David Alan Gilbert
1453266cd583SDr. David Alan Gilbert *val = (data->alarms >> bit[channel]) & 1;
1454266cd583SDr. David Alan Gilbert return 0;
1455266cd583SDr. David Alan Gilbert }
1456266cd583SDr. David Alan Gilbert break;
1457266cd583SDr. David Alan Gilbert
1458266cd583SDr. David Alan Gilbert default:
1459266cd583SDr. David Alan Gilbert break;
1460266cd583SDr. David Alan Gilbert }
1461266cd583SDr. David Alan Gilbert
1462266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1463266cd583SDr. David Alan Gilbert }
1464266cd583SDr. David Alan Gilbert
1465266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_in(struct w83627ehf_data * data,u32 attr,int channel,long * val)1466266cd583SDr. David Alan Gilbert w83627ehf_do_read_in(struct w83627ehf_data *data, u32 attr,
1467266cd583SDr. David Alan Gilbert int channel, long *val)
1468266cd583SDr. David Alan Gilbert {
1469266cd583SDr. David Alan Gilbert switch (attr) {
1470266cd583SDr. David Alan Gilbert case hwmon_in_input:
1471266cd583SDr. David Alan Gilbert *val = in_from_reg(data->in[channel], channel, data->scale_in);
1472266cd583SDr. David Alan Gilbert return 0;
1473266cd583SDr. David Alan Gilbert case hwmon_in_min:
1474266cd583SDr. David Alan Gilbert *val = in_from_reg(data->in_min[channel], channel,
1475266cd583SDr. David Alan Gilbert data->scale_in);
1476266cd583SDr. David Alan Gilbert return 0;
1477266cd583SDr. David Alan Gilbert case hwmon_in_max:
1478266cd583SDr. David Alan Gilbert *val = in_from_reg(data->in_max[channel], channel,
1479266cd583SDr. David Alan Gilbert data->scale_in);
1480266cd583SDr. David Alan Gilbert return 0;
1481266cd583SDr. David Alan Gilbert case hwmon_in_alarm:
1482266cd583SDr. David Alan Gilbert if (channel < 10) {
1483266cd583SDr. David Alan Gilbert static const int bit[] = { 0, 1, 2, 3, 8, 21, 20, 16, 17, 19 };
1484266cd583SDr. David Alan Gilbert
1485266cd583SDr. David Alan Gilbert *val = (data->alarms >> bit[channel]) & 1;
1486266cd583SDr. David Alan Gilbert return 0;
1487266cd583SDr. David Alan Gilbert }
1488266cd583SDr. David Alan Gilbert break;
1489266cd583SDr. David Alan Gilbert default:
1490266cd583SDr. David Alan Gilbert break;
1491266cd583SDr. David Alan Gilbert }
1492266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1493266cd583SDr. David Alan Gilbert }
1494266cd583SDr. David Alan Gilbert
1495266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_fan(struct w83627ehf_data * data,u32 attr,int channel,long * val)1496266cd583SDr. David Alan Gilbert w83627ehf_do_read_fan(struct w83627ehf_data *data, u32 attr,
1497266cd583SDr. David Alan Gilbert int channel, long *val)
1498266cd583SDr. David Alan Gilbert {
1499266cd583SDr. David Alan Gilbert switch (attr) {
1500266cd583SDr. David Alan Gilbert case hwmon_fan_input:
1501266cd583SDr. David Alan Gilbert *val = data->rpm[channel];
150269595502SDr. David Alan Gilbert return 0;
1503266cd583SDr. David Alan Gilbert case hwmon_fan_min:
1504266cd583SDr. David Alan Gilbert *val = fan_from_reg8(data->fan_min[channel],
1505266cd583SDr. David Alan Gilbert data->fan_div[channel]);
1506266cd583SDr. David Alan Gilbert return 0;
1507266cd583SDr. David Alan Gilbert case hwmon_fan_div:
1508266cd583SDr. David Alan Gilbert *val = div_from_reg(data->fan_div[channel]);
1509266cd583SDr. David Alan Gilbert return 0;
1510266cd583SDr. David Alan Gilbert case hwmon_fan_alarm:
1511266cd583SDr. David Alan Gilbert if (channel < 5) {
1512266cd583SDr. David Alan Gilbert static const int bit[] = { 6, 7, 11, 10, 23 };
1513266cd583SDr. David Alan Gilbert
1514266cd583SDr. David Alan Gilbert *val = (data->alarms >> bit[channel]) & 1;
1515266cd583SDr. David Alan Gilbert return 0;
1516266cd583SDr. David Alan Gilbert }
1517266cd583SDr. David Alan Gilbert break;
1518266cd583SDr. David Alan Gilbert default:
1519266cd583SDr. David Alan Gilbert break;
1520266cd583SDr. David Alan Gilbert }
1521266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1522266cd583SDr. David Alan Gilbert }
1523266cd583SDr. David Alan Gilbert
1524266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_pwm(struct w83627ehf_data * data,u32 attr,int channel,long * val)1525266cd583SDr. David Alan Gilbert w83627ehf_do_read_pwm(struct w83627ehf_data *data, u32 attr,
1526266cd583SDr. David Alan Gilbert int channel, long *val)
1527266cd583SDr. David Alan Gilbert {
1528266cd583SDr. David Alan Gilbert switch (attr) {
1529266cd583SDr. David Alan Gilbert case hwmon_pwm_input:
1530266cd583SDr. David Alan Gilbert *val = data->pwm[channel];
1531266cd583SDr. David Alan Gilbert return 0;
1532266cd583SDr. David Alan Gilbert case hwmon_pwm_enable:
1533266cd583SDr. David Alan Gilbert *val = data->pwm_enable[channel];
1534266cd583SDr. David Alan Gilbert return 0;
1535266cd583SDr. David Alan Gilbert case hwmon_pwm_mode:
1536266cd583SDr. David Alan Gilbert *val = data->pwm_enable[channel];
1537266cd583SDr. David Alan Gilbert return 0;
1538266cd583SDr. David Alan Gilbert default:
1539266cd583SDr. David Alan Gilbert break;
1540266cd583SDr. David Alan Gilbert }
1541266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1542266cd583SDr. David Alan Gilbert }
1543266cd583SDr. David Alan Gilbert
1544266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_intrusion(struct w83627ehf_data * data,u32 attr,int channel,long * val)1545931f397bSDr. David Alan Gilbert w83627ehf_do_read_intrusion(struct w83627ehf_data *data, u32 attr,
1546266cd583SDr. David Alan Gilbert int channel, long *val)
1547266cd583SDr. David Alan Gilbert {
1548931f397bSDr. David Alan Gilbert if (attr != hwmon_intrusion_alarm || channel != 0)
1549266cd583SDr. David Alan Gilbert return -EOPNOTSUPP; /* shouldn't happen */
1550266cd583SDr. David Alan Gilbert
1551266cd583SDr. David Alan Gilbert *val = !!(data->caseopen & 0x10);
1552266cd583SDr. David Alan Gilbert return 0;
1553266cd583SDr. David Alan Gilbert }
1554266cd583SDr. David Alan Gilbert
1555266cd583SDr. David Alan Gilbert static int
w83627ehf_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)1556266cd583SDr. David Alan Gilbert w83627ehf_read(struct device *dev, enum hwmon_sensor_types type,
1557266cd583SDr. David Alan Gilbert u32 attr, int channel, long *val)
1558266cd583SDr. David Alan Gilbert {
1559266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = w83627ehf_update_device(dev->parent);
1560266cd583SDr. David Alan Gilbert
1561266cd583SDr. David Alan Gilbert switch (type) {
1562266cd583SDr. David Alan Gilbert case hwmon_fan:
1563266cd583SDr. David Alan Gilbert return w83627ehf_do_read_fan(data, attr, channel, val);
1564266cd583SDr. David Alan Gilbert
1565266cd583SDr. David Alan Gilbert case hwmon_in:
1566266cd583SDr. David Alan Gilbert return w83627ehf_do_read_in(data, attr, channel, val);
1567266cd583SDr. David Alan Gilbert
1568266cd583SDr. David Alan Gilbert case hwmon_pwm:
1569266cd583SDr. David Alan Gilbert return w83627ehf_do_read_pwm(data, attr, channel, val);
1570266cd583SDr. David Alan Gilbert
1571266cd583SDr. David Alan Gilbert case hwmon_temp:
1572266cd583SDr. David Alan Gilbert return w83627ehf_do_read_temp(data, attr, channel, val);
1573266cd583SDr. David Alan Gilbert
1574266cd583SDr. David Alan Gilbert case hwmon_intrusion:
1575266cd583SDr. David Alan Gilbert return w83627ehf_do_read_intrusion(data, attr, channel, val);
1576266cd583SDr. David Alan Gilbert
1577266cd583SDr. David Alan Gilbert default:
1578266cd583SDr. David Alan Gilbert break;
1579266cd583SDr. David Alan Gilbert }
1580266cd583SDr. David Alan Gilbert
1581266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1582266cd583SDr. David Alan Gilbert }
1583266cd583SDr. David Alan Gilbert
1584266cd583SDr. David Alan Gilbert static int
w83627ehf_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)1585266cd583SDr. David Alan Gilbert w83627ehf_read_string(struct device *dev, enum hwmon_sensor_types type,
1586266cd583SDr. David Alan Gilbert u32 attr, int channel, const char **str)
1587266cd583SDr. David Alan Gilbert {
1588266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = dev_get_drvdata(dev);
1589266cd583SDr. David Alan Gilbert
1590266cd583SDr. David Alan Gilbert switch (type) {
1591266cd583SDr. David Alan Gilbert case hwmon_temp:
1592266cd583SDr. David Alan Gilbert if (attr == hwmon_temp_label) {
1593266cd583SDr. David Alan Gilbert *str = data->temp_label[data->temp_src[channel]];
1594266cd583SDr. David Alan Gilbert return 0;
1595266cd583SDr. David Alan Gilbert }
1596266cd583SDr. David Alan Gilbert break;
1597266cd583SDr. David Alan Gilbert
1598266cd583SDr. David Alan Gilbert default:
1599266cd583SDr. David Alan Gilbert break;
1600266cd583SDr. David Alan Gilbert }
1601266cd583SDr. David Alan Gilbert /* Nothing else should be read as a string */
1602266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1603266cd583SDr. David Alan Gilbert }
1604266cd583SDr. David Alan Gilbert
1605266cd583SDr. David Alan Gilbert static int
w83627ehf_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)1606266cd583SDr. David Alan Gilbert w83627ehf_write(struct device *dev, enum hwmon_sensor_types type,
1607266cd583SDr. David Alan Gilbert u32 attr, int channel, long val)
1608266cd583SDr. David Alan Gilbert {
1609266cd583SDr. David Alan Gilbert struct w83627ehf_data *data = dev_get_drvdata(dev);
1610266cd583SDr. David Alan Gilbert
1611266cd583SDr. David Alan Gilbert if (type == hwmon_in && attr == hwmon_in_min)
1612266cd583SDr. David Alan Gilbert return store_in_min(dev, data, channel, val);
1613266cd583SDr. David Alan Gilbert if (type == hwmon_in && attr == hwmon_in_max)
1614266cd583SDr. David Alan Gilbert return store_in_max(dev, data, channel, val);
1615266cd583SDr. David Alan Gilbert
1616266cd583SDr. David Alan Gilbert if (type == hwmon_fan && attr == hwmon_fan_min)
1617266cd583SDr. David Alan Gilbert return store_fan_min(dev, data, channel, val);
1618266cd583SDr. David Alan Gilbert
1619266cd583SDr. David Alan Gilbert if (type == hwmon_temp && attr == hwmon_temp_max)
1620266cd583SDr. David Alan Gilbert return store_temp_max(dev, data, channel, val);
1621266cd583SDr. David Alan Gilbert if (type == hwmon_temp && attr == hwmon_temp_max_hyst)
1622266cd583SDr. David Alan Gilbert return store_temp_max_hyst(dev, data, channel, val);
1623266cd583SDr. David Alan Gilbert if (type == hwmon_temp && attr == hwmon_temp_offset)
1624266cd583SDr. David Alan Gilbert return store_temp_offset(dev, data, channel, val);
1625266cd583SDr. David Alan Gilbert
1626266cd583SDr. David Alan Gilbert if (type == hwmon_pwm && attr == hwmon_pwm_mode)
1627266cd583SDr. David Alan Gilbert return store_pwm_mode(dev, data, channel, val);
1628266cd583SDr. David Alan Gilbert if (type == hwmon_pwm && attr == hwmon_pwm_enable)
1629266cd583SDr. David Alan Gilbert return store_pwm_enable(dev, data, channel, val);
1630266cd583SDr. David Alan Gilbert if (type == hwmon_pwm && attr == hwmon_pwm_input)
1631266cd583SDr. David Alan Gilbert return store_pwm(dev, data, channel, val);
1632266cd583SDr. David Alan Gilbert
1633266cd583SDr. David Alan Gilbert if (type == hwmon_intrusion && attr == hwmon_intrusion_alarm)
1634266cd583SDr. David Alan Gilbert return clear_caseopen(dev, data, channel, val);
1635266cd583SDr. David Alan Gilbert
1636266cd583SDr. David Alan Gilbert return -EOPNOTSUPP;
1637266cd583SDr. David Alan Gilbert }
1638266cd583SDr. David Alan Gilbert
1639266cd583SDr. David Alan Gilbert static const struct hwmon_ops w83627ehf_ops = {
1640266cd583SDr. David Alan Gilbert .is_visible = w83627ehf_is_visible,
1641266cd583SDr. David Alan Gilbert .read = w83627ehf_read,
1642266cd583SDr. David Alan Gilbert .read_string = w83627ehf_read_string,
1643*b418bd0aSKrzysztof Kozlowski .write = w83627ehf_write,
1644266cd583SDr. David Alan Gilbert };
1645266cd583SDr. David Alan Gilbert
1646266cd583SDr. David Alan Gilbert static const struct hwmon_channel_info * const w83627ehf_info[] = {
1647266cd583SDr. David Alan Gilbert HWMON_CHANNEL_INFO(fan,
1648266cd583SDr. David Alan Gilbert HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1649266cd583SDr. David Alan Gilbert HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1650266cd583SDr. David Alan Gilbert HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1651266cd583SDr. David Alan Gilbert HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1652266cd583SDr. David Alan Gilbert HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN),
1653266cd583SDr. David Alan Gilbert HWMON_CHANNEL_INFO(in,
1654266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1655266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1656266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1657266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1658266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1659266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1660266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1661266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1662266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1663266cd583SDr. David Alan Gilbert HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN),
1664266cd583SDr. David Alan Gilbert HWMON_CHANNEL_INFO(pwm,
1665266cd583SDr. David Alan Gilbert HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE,
1666266cd583SDr. David Alan Gilbert HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE,
1667266cd583SDr. David Alan Gilbert HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE,
1668266cd583SDr. David Alan Gilbert HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE),
1669266cd583SDr. David Alan Gilbert HWMON_CHANNEL_INFO(temp,
1670266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1671266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1672266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1673266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1674266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1675266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1676266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1677266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1678266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1679266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1680266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1681266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1682266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1683266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1684266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1685266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1686266cd583SDr. David Alan Gilbert HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1687266cd583SDr. David Alan Gilbert HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE),
1688266cd583SDr. David Alan Gilbert HWMON_CHANNEL_INFO(intrusion,
1689266cd583SDr. David Alan Gilbert HWMON_INTRUSION_ALARM),
1690266cd583SDr. David Alan Gilbert NULL
1691266cd583SDr. David Alan Gilbert };
1692266cd583SDr. David Alan Gilbert
1693266cd583SDr. David Alan Gilbert static const struct hwmon_chip_info w83627ehf_chip_info = {
1694266cd583SDr. David Alan Gilbert .ops = &w83627ehf_ops,
1695964c1c91SArmin Wolf .info = w83627ehf_info,
169608e7e278SJean Delvare };
16971ea6dd38SDavid Hubbard
w83627ehf_probe(struct platform_device * pdev)1698a8b3a3a5SJingoo Han static int __init w83627ehf_probe(struct platform_device *pdev)
169908e7e278SJean Delvare {
17001ea6dd38SDavid Hubbard struct device *dev = &pdev->dev;
170103f5de2bSJean Delvare struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
170208e7e278SJean Delvare struct w83627ehf_data *data;
1703266cd583SDr. David Alan Gilbert struct resource *res;
170408e7e278SJean Delvare u8 en_vrm10;
17051ea6dd38SDavid Hubbard int i, err = 0;
1706228f2aedSArmin Wolf struct device *hwmon_dev;
1707228f2aedSArmin Wolf
170808e7e278SJean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1709228f2aedSArmin Wolf if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
1710228f2aedSArmin Wolf return -EBUSY;
1711228f2aedSArmin Wolf
171208e7e278SJean Delvare data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
17131ea6dd38SDavid Hubbard if (!data)
17149a61bf63SIngo Molnar return -ENOMEM;
17159a61bf63SIngo Molnar
17161ea6dd38SDavid Hubbard data->addr = res->start;
17173300fb4fSJean Delvare mutex_init(&data->lock);
17181ea6dd38SDavid Hubbard mutex_init(&data->update_lock);
171908e7e278SJean Delvare data->name = w83627ehf_device_names[sio_data->kind];
1720237c8d2fSGong Jun data->bank = 0xff; /* Force initial bank selection */
1721237c8d2fSGong Jun platform_set_drvdata(pdev, data);
17223207408aSDr. David Alan Gilbert
1723eff7687dSJean Delvare /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1724eff7687dSJean Delvare data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1725eff7687dSJean Delvare /* 667HG has 3 pwms, and 627UHG has only 2 */
1726eff7687dSJean Delvare switch (sio_data->kind) {
1727eff7687dSJean Delvare default:
1728eff7687dSJean Delvare data->pwm_num = 4;
1729eff7687dSJean Delvare break;
1730eff7687dSJean Delvare case w83667hg:
1731eff7687dSJean Delvare case w83667hg_b:
1732eff7687dSJean Delvare data->pwm_num = 3;
1733eff7687dSJean Delvare break;
1734eff7687dSJean Delvare case w83627uhg:
173508e7e278SJean Delvare data->pwm_num = 2;
17366ba71de5SJean Delvare break;
1737d36cf32cSGuenter Roeck }
1738ec3e5a16SGuenter Roeck
1739ec3e5a16SGuenter Roeck /* Default to 3 temperature inputs, code below will adjust as needed */
17403207408aSDr. David Alan Gilbert data->have_temp = 0x07;
1741d36cf32cSGuenter Roeck
1742d36cf32cSGuenter Roeck /* Deal with temperature register setup first. */
17436ba71de5SJean Delvare if (sio_data->kind == w83667hg_b) {
17446ba71de5SJean Delvare u8 reg;
1745ec3e5a16SGuenter Roeck
1746ec3e5a16SGuenter Roeck w83627ehf_set_temp_reg_ehf(data, 4);
1747ec3e5a16SGuenter Roeck
1748ec3e5a16SGuenter Roeck /*
1749d36cf32cSGuenter Roeck * Temperature sources are selected with bank 0, registers 0x49
1750d36cf32cSGuenter Roeck * and 0x4a.
1751d36cf32cSGuenter Roeck */
1752d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, 0x4a);
1753d36cf32cSGuenter Roeck data->temp_src[0] = reg >> 5;
1754d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, 0x49);
1755d36cf32cSGuenter Roeck data->temp_src[1] = reg & 0x07;
1756d36cf32cSGuenter Roeck data->temp_src[2] = (reg >> 4) & 0x07;
1757d36cf32cSGuenter Roeck
1758d36cf32cSGuenter Roeck /*
1759d36cf32cSGuenter Roeck * W83667HG-B has another temperature register at 0x7e.
1760d36cf32cSGuenter Roeck * The temperature source is selected with register 0x7d.
1761d36cf32cSGuenter Roeck * Support it if the source differs from already reported
1762d36cf32cSGuenter Roeck * sources.
1763d36cf32cSGuenter Roeck */
1764d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, 0x7d);
1765d36cf32cSGuenter Roeck reg &= 0x07;
1766d36cf32cSGuenter Roeck if (reg != data->temp_src[0] && reg != data->temp_src[1]
1767d36cf32cSGuenter Roeck && reg != data->temp_src[2]) {
1768d36cf32cSGuenter Roeck data->temp_src[3] = reg;
1769d36cf32cSGuenter Roeck data->have_temp |= 1 << 3;
1770d36cf32cSGuenter Roeck }
1771d36cf32cSGuenter Roeck
1772d36cf32cSGuenter Roeck /*
1773d36cf32cSGuenter Roeck * Chip supports either AUXTIN or VIN3. Try to find out which
1774d36cf32cSGuenter Roeck * one.
1775d36cf32cSGuenter Roeck */
1776d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1777d36cf32cSGuenter Roeck if (data->temp_src[2] == 2 && (reg & 0x01))
1778d36cf32cSGuenter Roeck data->have_temp &= ~(1 << 2);
1779d36cf32cSGuenter Roeck
1780d36cf32cSGuenter Roeck if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
1781d36cf32cSGuenter Roeck || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
1782840e191dSGuenter Roeck data->in6_skip = 1;
1783840e191dSGuenter Roeck
1784840e191dSGuenter Roeck data->temp_label = w83667hg_b_temp_label;
1785840e191dSGuenter Roeck data->have_temp_offset = data->have_temp & 0x07;
1786840e191dSGuenter Roeck for (i = 0; i < 3; i++) {
1787eff7687dSJean Delvare if (data->temp_src[i] > 2)
1788eff7687dSJean Delvare data->have_temp_offset &= ~(1 << i);
1789eff7687dSJean Delvare }
1790eff7687dSJean Delvare } else if (sio_data->kind == w83627uhg) {
1791eff7687dSJean Delvare u8 reg;
1792eff7687dSJean Delvare
1793aacb6b00SJean Delvare w83627ehf_set_temp_reg_ehf(data, 3);
1794eff7687dSJean Delvare
1795eff7687dSJean Delvare /*
1796eff7687dSJean Delvare * Temperature sources for temp2 and temp3 are selected with
1797eff7687dSJean Delvare * bank 0, registers 0x49 and 0x4a.
1798eff7687dSJean Delvare */
1799eff7687dSJean Delvare data->temp_src[0] = 0; /* SYSTIN */
1800aacb6b00SJean Delvare reg = w83627ehf_read_value(data, 0x49) & 0x07;
1801eff7687dSJean Delvare /* Adjust to have the same mapping as other source registers */
1802aacb6b00SJean Delvare if (reg == 0)
1803eff7687dSJean Delvare data->temp_src[1] = 1;
1804eff7687dSJean Delvare else if (reg >= 2 && reg <= 5)
1805eff7687dSJean Delvare data->temp_src[1] = reg + 2;
1806eff7687dSJean Delvare else /* should never happen */
1807eff7687dSJean Delvare data->have_temp &= ~(1 << 1);
1808eff7687dSJean Delvare reg = w83627ehf_read_value(data, 0x4a);
1809eff7687dSJean Delvare data->temp_src[2] = reg >> 5;
1810eff7687dSJean Delvare
1811eff7687dSJean Delvare /*
1812eff7687dSJean Delvare * Skip temp3 if source is invalid or the same as temp1
1813eff7687dSJean Delvare * or temp2.
1814eff7687dSJean Delvare */
1815eff7687dSJean Delvare if (data->temp_src[2] == 2 || data->temp_src[2] == 3 ||
1816eff7687dSJean Delvare data->temp_src[2] == data->temp_src[0] ||
1817eff7687dSJean Delvare ((data->have_temp & (1 << 1)) &&
1818eff7687dSJean Delvare data->temp_src[2] == data->temp_src[1]))
1819eff7687dSJean Delvare data->have_temp &= ~(1 << 2);
1820eff7687dSJean Delvare else
1821eff7687dSJean Delvare data->temp3_val_only = 1; /* No limit regs */
1822eff7687dSJean Delvare
1823840e191dSGuenter Roeck data->in6_skip = 1; /* No VIN3 */
1824840e191dSGuenter Roeck
1825840e191dSGuenter Roeck data->temp_label = w83667hg_b_temp_label;
1826840e191dSGuenter Roeck data->have_temp_offset = data->have_temp & 0x03;
1827840e191dSGuenter Roeck for (i = 0; i < 3; i++) {
1828ec3e5a16SGuenter Roeck if (data->temp_src[i] > 1)
18296ba71de5SJean Delvare data->have_temp_offset &= ~(1 << i);
18306ba71de5SJean Delvare }
1831ec3e5a16SGuenter Roeck } else {
18326ba71de5SJean Delvare w83627ehf_set_temp_reg_ehf(data, 3);
18336ba71de5SJean Delvare
18346ba71de5SJean Delvare /* Temperature sources are fixed */
18356ba71de5SJean Delvare
18366ba71de5SJean Delvare if (sio_data->kind == w83667hg) {
18376ba71de5SJean Delvare u8 reg;
18386ba71de5SJean Delvare
18396ba71de5SJean Delvare /*
18406ba71de5SJean Delvare * Chip supports either AUXTIN or VIN3. Try to find
18416ba71de5SJean Delvare * out which one.
18426ba71de5SJean Delvare */
18436ba71de5SJean Delvare reg = w83627ehf_read_value(data,
18446ba71de5SJean Delvare W83627EHF_REG_TEMP_CONFIG[2]);
18456ba71de5SJean Delvare if (reg & 0x01)
1846ec3e5a16SGuenter Roeck data->have_temp &= ~(1 << 2);
1847840e191dSGuenter Roeck else
1848a157d06dSGong Jun data->in6_skip = 1;
1849a157d06dSGong Jun }
18503207408aSDr. David Alan Gilbert data->have_temp_offset = data->have_temp & 0x07;
1851c39aedafSGuenter Roeck }
1852c39aedafSGuenter Roeck
1853c39aedafSGuenter Roeck if (sio_data->kind == w83667hg_b) {
1854c39aedafSGuenter Roeck data->REG_FAN_MAX_OUTPUT =
1855c39aedafSGuenter Roeck W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1856c39aedafSGuenter Roeck data->REG_FAN_STEP_OUTPUT =
1857c39aedafSGuenter Roeck W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1858c39aedafSGuenter Roeck } else {
1859c39aedafSGuenter Roeck data->REG_FAN_MAX_OUTPUT =
1860c39aedafSGuenter Roeck W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1861da2e0255SGuenter Roeck data->REG_FAN_STEP_OUTPUT =
1862eff7687dSJean Delvare W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1863eff7687dSJean Delvare }
1864eff7687dSJean Delvare
1865eff7687dSJean Delvare /* Setup input voltage scaling factors */
1866eff7687dSJean Delvare if (sio_data->kind == w83627uhg)
1867eff7687dSJean Delvare data->scale_in = scale_in_w83627uhg;
186808e7e278SJean Delvare else
1869bf164c58SJean Delvare data->scale_in = scale_in_common;
187008e7e278SJean Delvare
1871fc18d6c0SJean Delvare /* Initialize the chip */
18720d023530SKatsumi Sato w83627ehf_init_device(data, sio_data->kind);
18730d023530SKatsumi Sato
18740d023530SKatsumi Sato data->vrm = vid_which_vrm();
1875228f2aedSArmin Wolf
18760d023530SKatsumi Sato err = superio_enter(sio_data->sioreg);
187758e6e781SJean Delvare if (err)
18783207408aSDr. David Alan Gilbert return err;
18798969e84dSGuenter Roeck
18808969e84dSGuenter Roeck /* Read VID value */
18818969e84dSGuenter Roeck if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
18828969e84dSGuenter Roeck /*
18838969e84dSGuenter Roeck * W83667HG has different pins for VID input and output, so
1884237c8d2fSGong Jun * we can get the VID input values directly at logical device D
1885237c8d2fSGong Jun * 0xe3.
1886266cd583SDr. David Alan Gilbert */
1887eff7687dSJean Delvare superio_select(sio_data->sioreg, W83667HG_LD_VID);
188858e6e781SJean Delvare data->vid = superio_inb(sio_data->sioreg, 0xe3);
188958e6e781SJean Delvare data->have_vid = true;
18908969e84dSGuenter Roeck } else if (sio_data->kind != w83627uhg) {
18918969e84dSGuenter Roeck superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
18928969e84dSGuenter Roeck if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
18938969e84dSGuenter Roeck /*
18948969e84dSGuenter Roeck * Set VID input sensibility if needed. In theory the
18958969e84dSGuenter Roeck * BIOS should have set it, but in practice it's not
18968969e84dSGuenter Roeck * always the case. We only do it for the W83627EHF/EHG
189758e6e781SJean Delvare * because the W83627DHG is more complex in this
189858e6e781SJean Delvare * respect.
189958e6e781SJean Delvare */
190058e6e781SJean Delvare if (sio_data->kind == w83627ehf) {
1901b55f3757SGuenter Roeck en_vrm10 = superio_inb(sio_data->sioreg,
1902b55f3757SGuenter Roeck SIO_REG_EN_VRM10);
1903237c8d2fSGong Jun if ((en_vrm10 & 0x08) && data->vrm == 90) {
1904237c8d2fSGong Jun dev_warn(dev,
1905fc18d6c0SJean Delvare "Setting VID input voltage to TTL\n");
1906237c8d2fSGong Jun superio_outb(sio_data->sioreg,
1907237c8d2fSGong Jun SIO_REG_EN_VRM10,
1908b55f3757SGuenter Roeck en_vrm10 & ~0x08);
1909b55f3757SGuenter Roeck } else if (!(en_vrm10 & 0x08)
1910237c8d2fSGong Jun && data->vrm == 100) {
1911237c8d2fSGong Jun dev_warn(dev,
1912fc18d6c0SJean Delvare "Setting VID input voltage to VRM10\n");
1913fc18d6c0SJean Delvare superio_outb(sio_data->sioreg,
191458e6e781SJean Delvare SIO_REG_EN_VRM10,
191558e6e781SJean Delvare en_vrm10 | 0x08);
1916237c8d2fSGong Jun }
1917237c8d2fSGong Jun }
1918cbe311f2SJean Delvare
1919cbe311f2SJean Delvare data->vid = superio_inb(sio_data->sioreg,
1920266cd583SDr. David Alan Gilbert SIO_REG_VID_DATA);
192158e6e781SJean Delvare if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1922b55f3757SGuenter Roeck data->vid &= 0x3f;
1923b55f3757SGuenter Roeck data->have_vid = true;
1924fc18d6c0SJean Delvare } else {
1925237c8d2fSGong Jun dev_info(dev,
1926fc18d6c0SJean Delvare "VID pins in output mode, CPU VID not available\n");
192703f5de2bSJean Delvare }
192808e7e278SJean Delvare }
19290d023530SKatsumi Sato
19300d023530SKatsumi Sato w83627ehf_check_fan_inputs(sio_data, data);
1931ea7be66cSMark M. Hoffman
193269595502SDr. David Alan Gilbert superio_exit(sio_data->sioreg);
1933ec3e5a16SGuenter Roeck
1934ec3e5a16SGuenter Roeck /* Read fan clock dividers immediately */
193569595502SDr. David Alan Gilbert w83627ehf_update_fan_div(data);
1936ec3e5a16SGuenter Roeck
1937ec3e5a16SGuenter Roeck /* Read pwm data to save original values */
1938ea7be66cSMark M. Hoffman w83627ehf_update_pwm(data);
1939266cd583SDr. David Alan Gilbert for (i = 0; i < data->pwm_num; i++)
1940266cd583SDr. David Alan Gilbert data->pwm_enable_orig[i] = data->pwm_enable[i];
1941266cd583SDr. David Alan Gilbert
1942266cd583SDr. David Alan Gilbert hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
1943266cd583SDr. David Alan Gilbert data->name,
1944228f2aedSArmin Wolf data,
194508e7e278SJean Delvare &w83627ehf_chip_info,
194608e7e278SJean Delvare w83627ehf_groups);
1947655231d4SJonathan Cameron return PTR_ERR_OR_ZERO(hwmon_dev);
19487e630bb5SJean Delvare }
19497e630bb5SJean Delvare
w83627ehf_suspend(struct device * dev)19507e630bb5SJean Delvare static int w83627ehf_suspend(struct device *dev)
19517e630bb5SJean Delvare {
19527e630bb5SJean Delvare struct w83627ehf_data *data = w83627ehf_update_device(dev);
19537e630bb5SJean Delvare
19547e630bb5SJean Delvare mutex_lock(&data->update_lock);
19557e630bb5SJean Delvare data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
19567e630bb5SJean Delvare mutex_unlock(&data->update_lock);
19577e630bb5SJean Delvare
1958655231d4SJonathan Cameron return 0;
19597e630bb5SJean Delvare }
19607e630bb5SJean Delvare
w83627ehf_resume(struct device * dev)19617e630bb5SJean Delvare static int w83627ehf_resume(struct device *dev)
19627e630bb5SJean Delvare {
19637e630bb5SJean Delvare struct w83627ehf_data *data = dev_get_drvdata(dev);
19647e630bb5SJean Delvare int i;
19657e630bb5SJean Delvare
19667e630bb5SJean Delvare mutex_lock(&data->update_lock);
19677e630bb5SJean Delvare data->bank = 0xff; /* Force initial bank selection */
19687e630bb5SJean Delvare
19697e630bb5SJean Delvare /* Restore limits */
19707e630bb5SJean Delvare for (i = 0; i < data->in_num; i++) {
19717e630bb5SJean Delvare if ((i == 6) && data->in6_skip)
19727e630bb5SJean Delvare continue;
19737e630bb5SJean Delvare
19747e630bb5SJean Delvare w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i),
19757e630bb5SJean Delvare data->in_min[i]);
19767e630bb5SJean Delvare w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i),
19777e630bb5SJean Delvare data->in_max[i]);
19787e630bb5SJean Delvare }
19797e630bb5SJean Delvare
19807e630bb5SJean Delvare for (i = 0; i < 5; i++) {
198169595502SDr. David Alan Gilbert if (!(data->has_fan_min & (1 << i)))
19827e630bb5SJean Delvare continue;
19837e630bb5SJean Delvare
19847e630bb5SJean Delvare w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[i],
19857e630bb5SJean Delvare data->fan_min[i]);
19867e630bb5SJean Delvare }
19877e630bb5SJean Delvare
19887e630bb5SJean Delvare for (i = 0; i < NUM_REG_TEMP; i++) {
19897e630bb5SJean Delvare if (!(data->have_temp & (1 << i)))
19907e630bb5SJean Delvare continue;
19917e630bb5SJean Delvare
19927e630bb5SJean Delvare if (data->reg_temp_over[i])
19937e630bb5SJean Delvare w83627ehf_write_temp(data, data->reg_temp_over[i],
19947e630bb5SJean Delvare data->temp_max[i]);
199545633fb3SJean Delvare if (data->reg_temp_hyst[i])
199645633fb3SJean Delvare w83627ehf_write_temp(data, data->reg_temp_hyst[i],
19977e630bb5SJean Delvare data->temp_max_hyst[i]);
19987e630bb5SJean Delvare if (i > 2)
19997e630bb5SJean Delvare continue;
20007e630bb5SJean Delvare if (data->have_temp_offset & (1 << i))
20017e630bb5SJean Delvare w83627ehf_write_value(data,
20027e630bb5SJean Delvare W83627EHF_REG_TEMP_OFFSET[i],
20037e630bb5SJean Delvare data->temp_offset[i]);
20047e630bb5SJean Delvare }
20057e630bb5SJean Delvare
20067e630bb5SJean Delvare /* Restore other settings */
2007952a11caSPaul Fertser w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat);
20087e630bb5SJean Delvare
20097e630bb5SJean Delvare /* Force re-reading all values */
20107e630bb5SJean Delvare data->valid = false;
20117e630bb5SJean Delvare mutex_unlock(&data->update_lock);
20127e630bb5SJean Delvare
2013655231d4SJonathan Cameron return 0;
20147e630bb5SJean Delvare }
20151ea6dd38SDavid Hubbard
2016cdaf7934SLaurent Riffard static DEFINE_SIMPLE_DEV_PM_OPS(w83627ehf_dev_pm_ops, w83627ehf_suspend, w83627ehf_resume);
20171ea6dd38SDavid Hubbard
2018655231d4SJonathan Cameron static struct platform_driver w83627ehf_driver = {
2019cdaf7934SLaurent Riffard .driver = {
202008e7e278SJean Delvare .name = DRVNAME,
202108e7e278SJean Delvare .pm = pm_sleep_ptr(&w83627ehf_dev_pm_ops),
20221ea6dd38SDavid Hubbard },
20231ea6dd38SDavid Hubbard };
20241ea6dd38SDavid Hubbard
202508e7e278SJean Delvare /* w83627ehf_find() looks for a '627 in the Super-I/O config space */
w83627ehf_find(int sioaddr,unsigned short * addr,struct w83627ehf_sio_data * sio_data)20266f7805a8SUwe Kleine-König static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
20276f7805a8SUwe Kleine-König struct w83627ehf_sio_data *sio_data)
20286f7805a8SUwe Kleine-König {
20296f7805a8SUwe Kleine-König static const char sio_name_W83627EHF[] __initconst = "W83627EHF";
20306f7805a8SUwe Kleine-König static const char sio_name_W83627EHG[] __initconst = "W83627EHG";
20316f7805a8SUwe Kleine-König static const char sio_name_W83627DHG[] __initconst = "W83627DHG";
20326f7805a8SUwe Kleine-König static const char sio_name_W83627DHG_P[] __initconst = "W83627DHG-P";
20331ea6dd38SDavid Hubbard static const char sio_name_W83627UHG[] __initconst = "W83627UHG";
203408e7e278SJean Delvare static const char sio_name_W83667HG[] __initconst = "W83667HG";
20351ea6dd38SDavid Hubbard static const char sio_name_W83667HG_B[] __initconst = "W83667HG-B";
20360d023530SKatsumi Sato
203708e7e278SJean Delvare u16 val;
20380d023530SKatsumi Sato const char *sio_name;
20390d023530SKatsumi Sato int err;
20400d023530SKatsumi Sato
204108e7e278SJean Delvare err = superio_enter(sioaddr);
204267b671bcSJean Delvare if (err)
204367b671bcSJean Delvare return err;
204467b671bcSJean Delvare
20451ea6dd38SDavid Hubbard if (force_id)
20461ea6dd38SDavid Hubbard val = force_id;
2047657c93b1SDavid Hubbard else
2048657c93b1SDavid Hubbard val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
20491ea6dd38SDavid Hubbard | superio_inb(sioaddr, SIO_REG_DEVID + 1);
20501ea6dd38SDavid Hubbard switch (val & SIO_ID_MASK) {
20511ea6dd38SDavid Hubbard case SIO_W83627EHF_ID:
2052657c93b1SDavid Hubbard sio_data->kind = w83627ehf;
20531ea6dd38SDavid Hubbard sio_name = sio_name_W83627EHF;
20541ea6dd38SDavid Hubbard break;
20551ea6dd38SDavid Hubbard case SIO_W83627EHG_ID:
20561ea6dd38SDavid Hubbard sio_data->kind = w83627ehf;
20571ea6dd38SDavid Hubbard sio_name = sio_name_W83627EHG;
20581ea6dd38SDavid Hubbard break;
2059657c93b1SDavid Hubbard case SIO_W83627DHG_ID:
2060c1e48dceSJean Delvare sio_data->kind = w83627dhg;
2061c1e48dceSJean Delvare sio_name = sio_name_W83627DHG;
2062c1e48dceSJean Delvare break;
2063c1e48dceSJean Delvare case SIO_W83627DHG_P_ID:
2064eff7687dSJean Delvare sio_data->kind = w83627dhg_p;
2065eff7687dSJean Delvare sio_name = sio_name_W83627DHG_P;
2066eff7687dSJean Delvare break;
2067eff7687dSJean Delvare case SIO_W83627UHG_ID:
2068237c8d2fSGong Jun sio_data->kind = w83627uhg;
2069237c8d2fSGong Jun sio_name = sio_name_W83627UHG;
2070237c8d2fSGong Jun break;
2071237c8d2fSGong Jun case SIO_W83667HG_ID:
2072c39aedafSGuenter Roeck sio_data->kind = w83667hg;
2073c39aedafSGuenter Roeck sio_name = sio_name_W83667HG;
2074c39aedafSGuenter Roeck break;
2075c39aedafSGuenter Roeck case SIO_W83667HG_B_ID:
2076657c93b1SDavid Hubbard sio_data->kind = w83667hg_b;
20779f66036bSJean Delvare sio_name = sio_name_W83667HG_B;
2078abdc6fd1SJoe Perches break;
20791ea6dd38SDavid Hubbard default:
208008e7e278SJean Delvare if (val != 0xffff)
208108e7e278SJean Delvare pr_debug("unsupported chip ID: 0x%04x\n", val);
208208e7e278SJean Delvare superio_exit(sioaddr);
20831ea6dd38SDavid Hubbard return -ENODEV;
20841ea6dd38SDavid Hubbard }
20851ea6dd38SDavid Hubbard
20861ea6dd38SDavid Hubbard /* We have a known chip, find the HWM I/O address */
20871a641fceSJean Delvare superio_select(sioaddr, W83627EHF_LD_HWM);
20882d8672c5SJean Delvare val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
2089abdc6fd1SJoe Perches | superio_inb(sioaddr, SIO_REG_ADDR + 1);
20901ea6dd38SDavid Hubbard *addr = val & IOREGION_ALIGNMENT;
209108e7e278SJean Delvare if (*addr == 0) {
209208e7e278SJean Delvare pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
209308e7e278SJean Delvare superio_exit(sioaddr);
209408e7e278SJean Delvare return -ENODEV;
20951ea6dd38SDavid Hubbard }
2096475ef855SDavid Hubbard
2097b55f3757SGuenter Roeck /* Activate logical device if needed */
20981ea6dd38SDavid Hubbard val = superio_inb(sioaddr, SIO_REG_ENABLE);
2099475ef855SDavid Hubbard if (!(val & 0x01)) {
210008e7e278SJean Delvare pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
21011ea6dd38SDavid Hubbard superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
2102abdc6fd1SJoe Perches }
21031ea6dd38SDavid Hubbard
21041ea6dd38SDavid Hubbard superio_exit(sioaddr);
210508e7e278SJean Delvare pr_info("Found %s chip at %#x\n", sio_name, *addr);
210608e7e278SJean Delvare sio_data->sioreg = sioaddr;
210708e7e278SJean Delvare
21088969e84dSGuenter Roeck return 0;
21098969e84dSGuenter Roeck }
21101ea6dd38SDavid Hubbard
2111964c1c91SArmin Wolf /*
21128969e84dSGuenter Roeck * when Super-I/O functions move to a separate file, the Super-I/O
21131ea6dd38SDavid Hubbard * bus will manage the lifetime of the device and this module will only keep
21141ea6dd38SDavid Hubbard * track of the w83627ehf driver.
211508e7e278SJean Delvare */
211608e7e278SJean Delvare static struct platform_device *pdev;
21171ea6dd38SDavid Hubbard
sensors_w83627ehf_init(void)21181ea6dd38SDavid Hubbard static int __init sensors_w83627ehf_init(void)
2119964c1c91SArmin Wolf {
2120964c1c91SArmin Wolf int err;
2121964c1c91SArmin Wolf unsigned short address;
2122964c1c91SArmin Wolf struct resource res = {
21231ea6dd38SDavid Hubbard .name = DRVNAME,
21241ea6dd38SDavid Hubbard .flags = IORESOURCE_IO,
21258969e84dSGuenter Roeck };
21268969e84dSGuenter Roeck struct w83627ehf_sio_data sio_data;
21271ea6dd38SDavid Hubbard
21281ea6dd38SDavid Hubbard /*
21291ea6dd38SDavid Hubbard * initialize sio_data->kind and sio_data->sioreg.
21308969e84dSGuenter Roeck *
21318969e84dSGuenter Roeck * when Super-I/O functions move to a separate file, the Super-I/O
21321ea6dd38SDavid Hubbard * driver will probe 0x2e and 0x4e and auto-detect the presence of a
21331ea6dd38SDavid Hubbard * w83627ehf hardware monitor, and call probe()
213408e7e278SJean Delvare */
213508e7e278SJean Delvare if (w83627ehf_find(0x2e, &address, &sio_data) &&
21361ea6dd38SDavid Hubbard w83627ehf_find(0x4e, &address, &sio_data))
21371ea6dd38SDavid Hubbard return -ENODEV;
2138b9acb64aSJean Delvare
2139b9acb64aSJean Delvare res.start = address + IOREGION_OFFSET;
2140b9acb64aSJean Delvare res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
21411ea6dd38SDavid Hubbard
2142964c1c91SArmin Wolf err = acpi_check_resource_conflict(&res);
2143964c1c91SArmin Wolf if (err)
2144964c1c91SArmin Wolf return err;
2145964c1c91SArmin Wolf
2146964c1c91SArmin Wolf pdev = platform_create_bundle(&w83627ehf_driver, w83627ehf_probe, &res, 1, &sio_data,
214708e7e278SJean Delvare sizeof(struct w83627ehf_sio_data));
214808e7e278SJean Delvare
214908e7e278SJean Delvare return PTR_ERR_OR_ZERO(pdev);
215008e7e278SJean Delvare }
21511ea6dd38SDavid Hubbard
sensors_w83627ehf_exit(void)21521ea6dd38SDavid Hubbard static void __exit sensors_w83627ehf_exit(void)
215308e7e278SJean Delvare {
215408e7e278SJean Delvare platform_device_unregister(pdev);
21557c81c60fSJean Delvare platform_driver_unregister(&w83627ehf_driver);
215608e7e278SJean Delvare }
215708e7e278SJean Delvare
215808e7e278SJean Delvare MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
215908e7e278SJean Delvare MODULE_DESCRIPTION("W83627EHF driver");
216008e7e278SJean Delvare MODULE_LICENSE("GPL");
2161
2162 module_init(sensors_w83627ehf_init);
2163 module_exit(sensors_w83627ehf_exit);
2164