108e7e278SJean Delvare /* 208e7e278SJean Delvare w83627ehf - Driver for the hardware monitoring functionality of 308e7e278SJean Delvare the Winbond W83627EHF Super-I/O chip 408e7e278SJean Delvare Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> 53379ceeeSJean Delvare Copyright (C) 2006 Yuan Mu (Winbond), 67188cc66SJean Delvare Rudolf Marek <r.marek@assembler.cz> 7c18beb5bSDavid Hubbard David Hubbard <david.c.hubbard@gmail.com> 841e9a062SDaniel J Blueman Daniel J Blueman <daniel.blueman@gmail.com> 9ec3e5a16SGuenter Roeck Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00) 1008e7e278SJean Delvare 1108e7e278SJean Delvare Shamelessly ripped from the w83627hf driver 1208e7e278SJean Delvare Copyright (C) 2003 Mark Studebaker 1308e7e278SJean Delvare 1408e7e278SJean Delvare Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help 1508e7e278SJean Delvare in testing and debugging this driver. 1608e7e278SJean Delvare 178dd2d2caSJean Delvare This driver also supports the W83627EHG, which is the lead-free 188dd2d2caSJean Delvare version of the W83627EHF. 198dd2d2caSJean Delvare 2008e7e278SJean Delvare This program is free software; you can redistribute it and/or modify 2108e7e278SJean Delvare it under the terms of the GNU General Public License as published by 2208e7e278SJean Delvare the Free Software Foundation; either version 2 of the License, or 2308e7e278SJean Delvare (at your option) any later version. 2408e7e278SJean Delvare 2508e7e278SJean Delvare This program is distributed in the hope that it will be useful, 2608e7e278SJean Delvare but WITHOUT ANY WARRANTY; without even the implied warranty of 2708e7e278SJean Delvare MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2808e7e278SJean Delvare GNU General Public License for more details. 2908e7e278SJean Delvare 3008e7e278SJean Delvare You should have received a copy of the GNU General Public License 3108e7e278SJean Delvare along with this program; if not, write to the Free Software 3208e7e278SJean Delvare Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 3308e7e278SJean Delvare 3408e7e278SJean Delvare 3508e7e278SJean Delvare Supports the following chips: 3608e7e278SJean Delvare 37657c93b1SDavid Hubbard Chip #vin #fan #pwm #temp chip IDs man ID 38657c93b1SDavid Hubbard w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 39657c93b1SDavid Hubbard 0x8860 0xa1 40657c93b1SDavid Hubbard w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 41c1e48dceSJean Delvare w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 42237c8d2fSGong Jun w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 43d36cf32cSGuenter Roeck w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 44ec3e5a16SGuenter Roeck nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3 45ec3e5a16SGuenter Roeck nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3 4608e7e278SJean Delvare */ 4708e7e278SJean Delvare 48abdc6fd1SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 49abdc6fd1SJoe Perches 5008e7e278SJean Delvare #include <linux/module.h> 5108e7e278SJean Delvare #include <linux/init.h> 5208e7e278SJean Delvare #include <linux/slab.h> 531ea6dd38SDavid Hubbard #include <linux/jiffies.h> 541ea6dd38SDavid Hubbard #include <linux/platform_device.h> 55943b0830SMark M. Hoffman #include <linux/hwmon.h> 56412fec82SYuan Mu #include <linux/hwmon-sysfs.h> 57fc18d6c0SJean Delvare #include <linux/hwmon-vid.h> 58943b0830SMark M. Hoffman #include <linux/err.h> 599a61bf63SIngo Molnar #include <linux/mutex.h> 60b9acb64aSJean Delvare #include <linux/acpi.h> 616055fae8SH Hartley Sweeten #include <linux/io.h> 6208e7e278SJean Delvare #include "lm75.h" 6308e7e278SJean Delvare 64ec3e5a16SGuenter Roeck enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775, 65ec3e5a16SGuenter Roeck nct6776 }; 661ea6dd38SDavid Hubbard 671ea6dd38SDavid Hubbard /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ 68e7e1ca6eSGuenter Roeck static const char * const w83627ehf_device_names[] = { 691ea6dd38SDavid Hubbard "w83627ehf", 701ea6dd38SDavid Hubbard "w83627dhg", 71c1e48dceSJean Delvare "w83627dhg", 72237c8d2fSGong Jun "w83667hg", 73c39aedafSGuenter Roeck "w83667hg", 74ec3e5a16SGuenter Roeck "nct6775", 75ec3e5a16SGuenter Roeck "nct6776", 761ea6dd38SDavid Hubbard }; 771ea6dd38SDavid Hubbard 7867b671bcSJean Delvare static unsigned short force_id; 7967b671bcSJean Delvare module_param(force_id, ushort, 0); 8067b671bcSJean Delvare MODULE_PARM_DESC(force_id, "Override the detected device ID"); 8167b671bcSJean Delvare 82d42e869aSIan Dobson static unsigned short fan_debounce; 83d42e869aSIan Dobson module_param(fan_debounce, ushort, 0); 84d42e869aSIan Dobson MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); 85d42e869aSIan Dobson 861ea6dd38SDavid Hubbard #define DRVNAME "w83627ehf" 8708e7e278SJean Delvare 8808e7e278SJean Delvare /* 8908e7e278SJean Delvare * Super-I/O constants and functions 9008e7e278SJean Delvare */ 9108e7e278SJean Delvare 9208e7e278SJean Delvare #define W83627EHF_LD_HWM 0x0b 93237c8d2fSGong Jun #define W83667HG_LD_VID 0x0d 9408e7e278SJean Delvare 9508e7e278SJean Delvare #define SIO_REG_LDSEL 0x07 /* Logical device select */ 9608e7e278SJean Delvare #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ 97fc18d6c0SJean Delvare #define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */ 9808e7e278SJean Delvare #define SIO_REG_ENABLE 0x30 /* Logical device enable */ 9908e7e278SJean Delvare #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ 100fc18d6c0SJean Delvare #define SIO_REG_VID_CTRL 0xF0 /* VID control */ 101fc18d6c0SJean Delvare #define SIO_REG_VID_DATA 0xF1 /* VID data */ 10208e7e278SJean Delvare 103657c93b1SDavid Hubbard #define SIO_W83627EHF_ID 0x8850 104657c93b1SDavid Hubbard #define SIO_W83627EHG_ID 0x8860 105657c93b1SDavid Hubbard #define SIO_W83627DHG_ID 0xa020 106c1e48dceSJean Delvare #define SIO_W83627DHG_P_ID 0xb070 107237c8d2fSGong Jun #define SIO_W83667HG_ID 0xa510 108c39aedafSGuenter Roeck #define SIO_W83667HG_B_ID 0xb350 109ec3e5a16SGuenter Roeck #define SIO_NCT6775_ID 0xb470 110ec3e5a16SGuenter Roeck #define SIO_NCT6776_ID 0xc330 111657c93b1SDavid Hubbard #define SIO_ID_MASK 0xFFF0 11208e7e278SJean Delvare 11308e7e278SJean Delvare static inline void 1141ea6dd38SDavid Hubbard superio_outb(int ioreg, int reg, int val) 11508e7e278SJean Delvare { 1161ea6dd38SDavid Hubbard outb(reg, ioreg); 1171ea6dd38SDavid Hubbard outb(val, ioreg + 1); 11808e7e278SJean Delvare } 11908e7e278SJean Delvare 12008e7e278SJean Delvare static inline int 1211ea6dd38SDavid Hubbard superio_inb(int ioreg, int reg) 12208e7e278SJean Delvare { 1231ea6dd38SDavid Hubbard outb(reg, ioreg); 1241ea6dd38SDavid Hubbard return inb(ioreg + 1); 12508e7e278SJean Delvare } 12608e7e278SJean Delvare 12708e7e278SJean Delvare static inline void 1281ea6dd38SDavid Hubbard superio_select(int ioreg, int ld) 12908e7e278SJean Delvare { 1301ea6dd38SDavid Hubbard outb(SIO_REG_LDSEL, ioreg); 1311ea6dd38SDavid Hubbard outb(ld, ioreg + 1); 13208e7e278SJean Delvare } 13308e7e278SJean Delvare 13408e7e278SJean Delvare static inline void 1351ea6dd38SDavid Hubbard superio_enter(int ioreg) 13608e7e278SJean Delvare { 1371ea6dd38SDavid Hubbard outb(0x87, ioreg); 1381ea6dd38SDavid Hubbard outb(0x87, ioreg); 13908e7e278SJean Delvare } 14008e7e278SJean Delvare 14108e7e278SJean Delvare static inline void 1421ea6dd38SDavid Hubbard superio_exit(int ioreg) 14308e7e278SJean Delvare { 144022b75a3SJonas Jonsson outb(0xaa, ioreg); 1451ea6dd38SDavid Hubbard outb(0x02, ioreg); 1461ea6dd38SDavid Hubbard outb(0x02, ioreg + 1); 14708e7e278SJean Delvare } 14808e7e278SJean Delvare 14908e7e278SJean Delvare /* 15008e7e278SJean Delvare * ISA constants 15108e7e278SJean Delvare */ 15208e7e278SJean Delvare 153e7e1ca6eSGuenter Roeck #define IOREGION_ALIGNMENT (~7) 1541a641fceSJean Delvare #define IOREGION_OFFSET 5 1551a641fceSJean Delvare #define IOREGION_LENGTH 2 1561ea6dd38SDavid Hubbard #define ADDR_REG_OFFSET 0 1571ea6dd38SDavid Hubbard #define DATA_REG_OFFSET 1 15808e7e278SJean Delvare 15908e7e278SJean Delvare #define W83627EHF_REG_BANK 0x4E 16008e7e278SJean Delvare #define W83627EHF_REG_CONFIG 0x40 161657c93b1SDavid Hubbard 162657c93b1SDavid Hubbard /* Not currently used: 163657c93b1SDavid Hubbard * REG_MAN_ID has the value 0x5ca3 for all supported chips. 164657c93b1SDavid Hubbard * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model. 165657c93b1SDavid Hubbard * REG_MAN_ID is at port 0x4f 166657c93b1SDavid Hubbard * REG_CHIP_ID is at port 0x58 */ 16708e7e278SJean Delvare 16808e7e278SJean Delvare static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; 16908e7e278SJean Delvare static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; 17008e7e278SJean Delvare 171cf0676feSRudolf Marek /* The W83627EHF registers for nr=7,8,9 are in bank 5 */ 172cf0676feSRudolf Marek #define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ 173cf0676feSRudolf Marek (0x554 + (((nr) - 7) * 2))) 174cf0676feSRudolf Marek #define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ 175cf0676feSRudolf Marek (0x555 + (((nr) - 7) * 2))) 176cf0676feSRudolf Marek #define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ 177cf0676feSRudolf Marek (0x550 + (nr) - 7)) 178cf0676feSRudolf Marek 179d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e }; 180d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 }; 181d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 }; 182d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 }; 18308e7e278SJean Delvare 18408e7e278SJean Delvare /* Fan clock dividers are spread over the following five registers */ 18508e7e278SJean Delvare #define W83627EHF_REG_FANDIV1 0x47 18608e7e278SJean Delvare #define W83627EHF_REG_FANDIV2 0x4B 18708e7e278SJean Delvare #define W83627EHF_REG_VBAT 0x5D 18808e7e278SJean Delvare #define W83627EHF_REG_DIODE 0x59 18908e7e278SJean Delvare #define W83627EHF_REG_SMI_OVT 0x4C 19008e7e278SJean Delvare 191ec3e5a16SGuenter Roeck /* NCT6775F has its own fan divider registers */ 192ec3e5a16SGuenter Roeck #define NCT6775_REG_FANDIV1 0x506 193ec3e5a16SGuenter Roeck #define NCT6775_REG_FANDIV2 0x507 194d42e869aSIan Dobson #define NCT6775_REG_FAN_DEBOUNCE 0xf0 195ec3e5a16SGuenter Roeck 196a4589dbbSJean Delvare #define W83627EHF_REG_ALARM1 0x459 197a4589dbbSJean Delvare #define W83627EHF_REG_ALARM2 0x45A 198a4589dbbSJean Delvare #define W83627EHF_REG_ALARM3 0x45B 199a4589dbbSJean Delvare 20008c79950SRudolf Marek /* SmartFan registers */ 20141e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPUP_TIME 0x0f 20241e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e 20341e9a062SDaniel J Blueman 20408c79950SRudolf Marek /* DC or PWM output fan configuration */ 20508c79950SRudolf Marek static const u8 W83627EHF_REG_PWM_ENABLE[] = { 20608c79950SRudolf Marek 0x04, /* SYS FAN0 output mode and PWM mode */ 20708c79950SRudolf Marek 0x04, /* CPU FAN0 output mode and PWM mode */ 20808c79950SRudolf Marek 0x12, /* AUX FAN mode */ 20941e9a062SDaniel J Blueman 0x62, /* CPU FAN1 mode */ 21008c79950SRudolf Marek }; 21108c79950SRudolf Marek 21208c79950SRudolf Marek static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 }; 21308c79950SRudolf Marek static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 }; 21408c79950SRudolf Marek 21508c79950SRudolf Marek /* FAN Duty Cycle, be used to control */ 216279af1a9SGuenter Roeck static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 }; 217279af1a9SGuenter Roeck static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 }; 21808c79950SRudolf Marek static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 }; 21908c79950SRudolf Marek 22008c79950SRudolf Marek /* Advanced Fan control, some values are common for all fans */ 221279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 }; 222279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 }; 223279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 }; 224c39aedafSGuenter Roeck 225279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[] 226c39aedafSGuenter Roeck = { 0xff, 0x67, 0xff, 0x69 }; 227279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[] 228c39aedafSGuenter Roeck = { 0xff, 0x68, 0xff, 0x6a }; 229c39aedafSGuenter Roeck 230279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b }; 231279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] 232279af1a9SGuenter Roeck = { 0x68, 0x6a, 0x6c }; 23308c79950SRudolf Marek 234ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 }; 235ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 }; 236ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 }; 237ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 }; 238ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 }; 239ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 }; 240ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a }; 241ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b }; 24226bc440eSGuenter Roeck static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; 243ec3e5a16SGuenter Roeck static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642}; 244ec3e5a16SGuenter Roeck 245ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP[] 246ec3e5a16SGuenter Roeck = { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d }; 247ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_CONFIG[] 248ec3e5a16SGuenter Roeck = { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A }; 249ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_HYST[] 250ec3e5a16SGuenter Roeck = { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D }; 251ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_OVER[] 252ec3e5a16SGuenter Roeck = { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C }; 253ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_SOURCE[] 254ec3e5a16SGuenter Roeck = { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 }; 255ec3e5a16SGuenter Roeck 256d36cf32cSGuenter Roeck static const char *const w83667hg_b_temp_label[] = { 257d36cf32cSGuenter Roeck "SYSTIN", 258d36cf32cSGuenter Roeck "CPUTIN", 259d36cf32cSGuenter Roeck "AUXTIN", 260d36cf32cSGuenter Roeck "AMDTSI", 261d36cf32cSGuenter Roeck "PECI Agent 1", 262d36cf32cSGuenter Roeck "PECI Agent 2", 263d36cf32cSGuenter Roeck "PECI Agent 3", 264d36cf32cSGuenter Roeck "PECI Agent 4" 265d36cf32cSGuenter Roeck }; 266d36cf32cSGuenter Roeck 267ec3e5a16SGuenter Roeck static const char *const nct6775_temp_label[] = { 268ec3e5a16SGuenter Roeck "", 269ec3e5a16SGuenter Roeck "SYSTIN", 270ec3e5a16SGuenter Roeck "CPUTIN", 271ec3e5a16SGuenter Roeck "AUXTIN", 272ec3e5a16SGuenter Roeck "AMD SB-TSI", 273ec3e5a16SGuenter Roeck "PECI Agent 0", 274ec3e5a16SGuenter Roeck "PECI Agent 1", 275ec3e5a16SGuenter Roeck "PECI Agent 2", 276ec3e5a16SGuenter Roeck "PECI Agent 3", 277ec3e5a16SGuenter Roeck "PECI Agent 4", 278ec3e5a16SGuenter Roeck "PECI Agent 5", 279ec3e5a16SGuenter Roeck "PECI Agent 6", 280ec3e5a16SGuenter Roeck "PECI Agent 7", 281ec3e5a16SGuenter Roeck "PCH_CHIP_CPU_MAX_TEMP", 282ec3e5a16SGuenter Roeck "PCH_CHIP_TEMP", 283ec3e5a16SGuenter Roeck "PCH_CPU_TEMP", 284ec3e5a16SGuenter Roeck "PCH_MCH_TEMP", 285ec3e5a16SGuenter Roeck "PCH_DIM0_TEMP", 286ec3e5a16SGuenter Roeck "PCH_DIM1_TEMP", 287ec3e5a16SGuenter Roeck "PCH_DIM2_TEMP", 288ec3e5a16SGuenter Roeck "PCH_DIM3_TEMP" 289ec3e5a16SGuenter Roeck }; 290ec3e5a16SGuenter Roeck 291ec3e5a16SGuenter Roeck static const char *const nct6776_temp_label[] = { 292ec3e5a16SGuenter Roeck "", 293ec3e5a16SGuenter Roeck "SYSTIN", 294ec3e5a16SGuenter Roeck "CPUTIN", 295ec3e5a16SGuenter Roeck "AUXTIN", 296ec3e5a16SGuenter Roeck "SMBUSMASTER 0", 297ec3e5a16SGuenter Roeck "SMBUSMASTER 1", 298ec3e5a16SGuenter Roeck "SMBUSMASTER 2", 299ec3e5a16SGuenter Roeck "SMBUSMASTER 3", 300ec3e5a16SGuenter Roeck "SMBUSMASTER 4", 301ec3e5a16SGuenter Roeck "SMBUSMASTER 5", 302ec3e5a16SGuenter Roeck "SMBUSMASTER 6", 303ec3e5a16SGuenter Roeck "SMBUSMASTER 7", 304ec3e5a16SGuenter Roeck "PECI Agent 0", 305ec3e5a16SGuenter Roeck "PECI Agent 1", 306ec3e5a16SGuenter Roeck "PCH_CHIP_CPU_MAX_TEMP", 307ec3e5a16SGuenter Roeck "PCH_CHIP_TEMP", 308ec3e5a16SGuenter Roeck "PCH_CPU_TEMP", 309ec3e5a16SGuenter Roeck "PCH_MCH_TEMP", 310ec3e5a16SGuenter Roeck "PCH_DIM0_TEMP", 311ec3e5a16SGuenter Roeck "PCH_DIM1_TEMP", 312ec3e5a16SGuenter Roeck "PCH_DIM2_TEMP", 313ec3e5a16SGuenter Roeck "PCH_DIM3_TEMP", 314ec3e5a16SGuenter Roeck "BYTE_TEMP" 315ec3e5a16SGuenter Roeck }; 316ec3e5a16SGuenter Roeck 317ec3e5a16SGuenter Roeck #define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP) 318d36cf32cSGuenter Roeck 319bce26c58SGuenter Roeck static inline int is_word_sized(u16 reg) 320bce26c58SGuenter Roeck { 321ec3e5a16SGuenter Roeck return ((((reg & 0xff00) == 0x100 322bce26c58SGuenter Roeck || (reg & 0xff00) == 0x200) 323bce26c58SGuenter Roeck && ((reg & 0x00ff) == 0x50 324bce26c58SGuenter Roeck || (reg & 0x00ff) == 0x53 325ec3e5a16SGuenter Roeck || (reg & 0x00ff) == 0x55)) 326ec3e5a16SGuenter Roeck || (reg & 0xfff0) == 0x630 327ec3e5a16SGuenter Roeck || reg == 0x640 || reg == 0x642 328ec3e5a16SGuenter Roeck || ((reg & 0xfff0) == 0x650 329ec3e5a16SGuenter Roeck && (reg & 0x000f) >= 0x06) 330ec3e5a16SGuenter Roeck || reg == 0x73 || reg == 0x75 || reg == 0x77 331ec3e5a16SGuenter Roeck ); 332bce26c58SGuenter Roeck } 333bce26c58SGuenter Roeck 33408e7e278SJean Delvare /* 33508e7e278SJean Delvare * Conversions 33608e7e278SJean Delvare */ 33708e7e278SJean Delvare 33808c79950SRudolf Marek /* 1 is PWM mode, output in ms */ 33908c79950SRudolf Marek static inline unsigned int step_time_from_reg(u8 reg, u8 mode) 34008c79950SRudolf Marek { 34108c79950SRudolf Marek return mode ? 100 * reg : 400 * reg; 34208c79950SRudolf Marek } 34308c79950SRudolf Marek 34408c79950SRudolf Marek static inline u8 step_time_to_reg(unsigned int msec, u8 mode) 34508c79950SRudolf Marek { 34608c79950SRudolf Marek return SENSORS_LIMIT((mode ? (msec + 50) / 100 : 34708c79950SRudolf Marek (msec + 200) / 400), 1, 255); 34808c79950SRudolf Marek } 34908c79950SRudolf Marek 35026bc440eSGuenter Roeck static unsigned int fan_from_reg8(u16 reg, unsigned int divreg) 35108e7e278SJean Delvare { 35226bc440eSGuenter Roeck if (reg == 0 || reg == 255) 35308e7e278SJean Delvare return 0; 35426bc440eSGuenter Roeck return 1350000U / (reg << divreg); 355ec3e5a16SGuenter Roeck } 35626bc440eSGuenter Roeck 35726bc440eSGuenter Roeck static unsigned int fan_from_reg13(u16 reg, unsigned int divreg) 35826bc440eSGuenter Roeck { 35926bc440eSGuenter Roeck if ((reg & 0xff1f) == 0xff1f) 36026bc440eSGuenter Roeck return 0; 36126bc440eSGuenter Roeck 36226bc440eSGuenter Roeck reg = (reg & 0x1f) | ((reg & 0xff00) >> 3); 36326bc440eSGuenter Roeck 36426bc440eSGuenter Roeck if (reg == 0) 36526bc440eSGuenter Roeck return 0; 36626bc440eSGuenter Roeck 36726bc440eSGuenter Roeck return 1350000U / reg; 36826bc440eSGuenter Roeck } 36926bc440eSGuenter Roeck 37026bc440eSGuenter Roeck static unsigned int fan_from_reg16(u16 reg, unsigned int divreg) 37126bc440eSGuenter Roeck { 37226bc440eSGuenter Roeck if (reg == 0 || reg == 0xffff) 37326bc440eSGuenter Roeck return 0; 37426bc440eSGuenter Roeck 37526bc440eSGuenter Roeck /* 37626bc440eSGuenter Roeck * Even though the registers are 16 bit wide, the fan divisor 37726bc440eSGuenter Roeck * still applies. 37826bc440eSGuenter Roeck */ 37926bc440eSGuenter Roeck return 1350000U / (reg << divreg); 38008e7e278SJean Delvare } 38108e7e278SJean Delvare 38208e7e278SJean Delvare static inline unsigned int 38308e7e278SJean Delvare div_from_reg(u8 reg) 38408e7e278SJean Delvare { 38508e7e278SJean Delvare return 1 << reg; 38608e7e278SJean Delvare } 38708e7e278SJean Delvare 38808e7e278SJean Delvare static inline int 389bce26c58SGuenter Roeck temp_from_reg(u16 reg, s16 regval) 39008e7e278SJean Delvare { 391bce26c58SGuenter Roeck if (is_word_sized(reg)) 392bce26c58SGuenter Roeck return LM75_TEMP_FROM_REG(regval); 393bce26c58SGuenter Roeck return regval * 1000; 39408e7e278SJean Delvare } 39508e7e278SJean Delvare 396ec3e5a16SGuenter Roeck static inline u16 397bce26c58SGuenter Roeck temp_to_reg(u16 reg, long temp) 39808e7e278SJean Delvare { 399bce26c58SGuenter Roeck if (is_word_sized(reg)) 400bce26c58SGuenter Roeck return LM75_TEMP_TO_REG(temp); 401bce26c58SGuenter Roeck return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000); 40208e7e278SJean Delvare } 40308e7e278SJean Delvare 404cf0676feSRudolf Marek /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ 405cf0676feSRudolf Marek 406cf0676feSRudolf Marek static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; 407cf0676feSRudolf Marek 408cf0676feSRudolf Marek static inline long in_from_reg(u8 reg, u8 nr) 409cf0676feSRudolf Marek { 410cf0676feSRudolf Marek return reg * scale_in[nr]; 411cf0676feSRudolf Marek } 412cf0676feSRudolf Marek 413cf0676feSRudolf Marek static inline u8 in_to_reg(u32 val, u8 nr) 414cf0676feSRudolf Marek { 415e7e1ca6eSGuenter Roeck return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 416e7e1ca6eSGuenter Roeck 255); 417cf0676feSRudolf Marek } 418cf0676feSRudolf Marek 41908e7e278SJean Delvare /* 42008e7e278SJean Delvare * Data structures and manipulation thereof 42108e7e278SJean Delvare */ 42208e7e278SJean Delvare 42308e7e278SJean Delvare struct w83627ehf_data { 4241ea6dd38SDavid Hubbard int addr; /* IO base of hw monitor block */ 4251ea6dd38SDavid Hubbard const char *name; 4261ea6dd38SDavid Hubbard 4271beeffe4STony Jones struct device *hwmon_dev; 4289a61bf63SIngo Molnar struct mutex lock; 42908e7e278SJean Delvare 430ec3e5a16SGuenter Roeck u16 reg_temp[NUM_REG_TEMP]; 431ec3e5a16SGuenter Roeck u16 reg_temp_over[NUM_REG_TEMP]; 432ec3e5a16SGuenter Roeck u16 reg_temp_hyst[NUM_REG_TEMP]; 433ec3e5a16SGuenter Roeck u16 reg_temp_config[NUM_REG_TEMP]; 434d36cf32cSGuenter Roeck u8 temp_src[NUM_REG_TEMP]; 435d36cf32cSGuenter Roeck const char * const *temp_label; 436d36cf32cSGuenter Roeck 437279af1a9SGuenter Roeck const u16 *REG_PWM; 438279af1a9SGuenter Roeck const u16 *REG_TARGET; 439279af1a9SGuenter Roeck const u16 *REG_FAN; 440279af1a9SGuenter Roeck const u16 *REG_FAN_MIN; 441279af1a9SGuenter Roeck const u16 *REG_FAN_START_OUTPUT; 442279af1a9SGuenter Roeck const u16 *REG_FAN_STOP_OUTPUT; 443279af1a9SGuenter Roeck const u16 *REG_FAN_STOP_TIME; 444279af1a9SGuenter Roeck const u16 *REG_FAN_MAX_OUTPUT; 445279af1a9SGuenter Roeck const u16 *REG_FAN_STEP_OUTPUT; 446da2e0255SGuenter Roeck 44726bc440eSGuenter Roeck unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg); 44826bc440eSGuenter Roeck unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg); 44926bc440eSGuenter Roeck 4509a61bf63SIngo Molnar struct mutex update_lock; 45108e7e278SJean Delvare char valid; /* !=0 if following fields are valid */ 45208e7e278SJean Delvare unsigned long last_updated; /* In jiffies */ 45308e7e278SJean Delvare 45408e7e278SJean Delvare /* Register values */ 45583cc8985SGuenter Roeck u8 bank; /* current register bank */ 4561ea6dd38SDavid Hubbard u8 in_num; /* number of in inputs we have */ 457cf0676feSRudolf Marek u8 in[10]; /* Register value */ 458cf0676feSRudolf Marek u8 in_max[10]; /* Register value */ 459cf0676feSRudolf Marek u8 in_min[10]; /* Register value */ 4603382a918SGuenter Roeck unsigned int rpm[5]; 461ec3e5a16SGuenter Roeck u16 fan_min[5]; 46208e7e278SJean Delvare u8 fan_div[5]; 46308e7e278SJean Delvare u8 has_fan; /* some fan inputs can be disabled */ 464ec3e5a16SGuenter Roeck u8 has_fan_min; /* some fans don't have min register */ 46526bc440eSGuenter Roeck bool has_fan_div; 466da667365SJean Delvare u8 temp_type[3]; 467ec3e5a16SGuenter Roeck s16 temp[9]; 468ec3e5a16SGuenter Roeck s16 temp_max[9]; 469ec3e5a16SGuenter Roeck s16 temp_max_hyst[9]; 470a4589dbbSJean Delvare u32 alarms; 47108c79950SRudolf Marek 47208c79950SRudolf Marek u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ 47308c79950SRudolf Marek u8 pwm_enable[4]; /* 1->manual 47441e9a062SDaniel J Blueman 2->thermal cruise mode (also called SmartFan I) 47541e9a062SDaniel J Blueman 3->fan speed cruise mode 476e7e1ca6eSGuenter Roeck 4->variable thermal cruise (also called 477b84bb518SGuenter Roeck SmartFan III) 478b84bb518SGuenter Roeck 5->enhanced variable thermal cruise (also called 479b84bb518SGuenter Roeck SmartFan IV) */ 480b84bb518SGuenter Roeck u8 pwm_enable_orig[4]; /* original value of pwm_enable */ 481237c8d2fSGong Jun u8 pwm_num; /* number of pwm */ 48208c79950SRudolf Marek u8 pwm[4]; 48308c79950SRudolf Marek u8 target_temp[4]; 48408c79950SRudolf Marek u8 tolerance[4]; 48508c79950SRudolf Marek 48641e9a062SDaniel J Blueman u8 fan_start_output[4]; /* minimum fan speed when spinning up */ 48741e9a062SDaniel J Blueman u8 fan_stop_output[4]; /* minimum fan speed when spinning down */ 48841e9a062SDaniel J Blueman u8 fan_stop_time[4]; /* time at minimum before disabling fan */ 48941e9a062SDaniel J Blueman u8 fan_max_output[4]; /* maximum fan speed */ 49041e9a062SDaniel J Blueman u8 fan_step_output[4]; /* rate of change output value */ 491fc18d6c0SJean Delvare 492fc18d6c0SJean Delvare u8 vid; 493fc18d6c0SJean Delvare u8 vrm; 494a157d06dSGong Jun 495ec3e5a16SGuenter Roeck u16 have_temp; 496a157d06dSGong Jun u8 in6_skip; 49708e7e278SJean Delvare }; 49808e7e278SJean Delvare 4991ea6dd38SDavid Hubbard struct w83627ehf_sio_data { 5001ea6dd38SDavid Hubbard int sioreg; 5011ea6dd38SDavid Hubbard enum kinds kind; 5021ea6dd38SDavid Hubbard }; 5031ea6dd38SDavid Hubbard 50483cc8985SGuenter Roeck /* 50583cc8985SGuenter Roeck * On older chips, only registers 0x50-0x5f are banked. 50683cc8985SGuenter Roeck * On more recent chips, all registers are banked. 50783cc8985SGuenter Roeck * Assume that is the case and set the bank number for each access. 50883cc8985SGuenter Roeck * Cache the bank number so it only needs to be set if it changes. 50983cc8985SGuenter Roeck */ 5101ea6dd38SDavid Hubbard static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg) 51108e7e278SJean Delvare { 51283cc8985SGuenter Roeck u8 bank = reg >> 8; 51383cc8985SGuenter Roeck if (data->bank != bank) { 5141ea6dd38SDavid Hubbard outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET); 51583cc8985SGuenter Roeck outb_p(bank, data->addr + DATA_REG_OFFSET); 51683cc8985SGuenter Roeck data->bank = bank; 51708e7e278SJean Delvare } 51808e7e278SJean Delvare } 51908e7e278SJean Delvare 5201ea6dd38SDavid Hubbard static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg) 52108e7e278SJean Delvare { 52208e7e278SJean Delvare int res, word_sized = is_word_sized(reg); 52308e7e278SJean Delvare 5249a61bf63SIngo Molnar mutex_lock(&data->lock); 52508e7e278SJean Delvare 5261ea6dd38SDavid Hubbard w83627ehf_set_bank(data, reg); 5271ea6dd38SDavid Hubbard outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); 5281ea6dd38SDavid Hubbard res = inb_p(data->addr + DATA_REG_OFFSET); 52908e7e278SJean Delvare if (word_sized) { 53008e7e278SJean Delvare outb_p((reg & 0xff) + 1, 5311ea6dd38SDavid Hubbard data->addr + ADDR_REG_OFFSET); 5321ea6dd38SDavid Hubbard res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET); 53308e7e278SJean Delvare } 53408e7e278SJean Delvare 5359a61bf63SIngo Molnar mutex_unlock(&data->lock); 53608e7e278SJean Delvare return res; 53708e7e278SJean Delvare } 53808e7e278SJean Delvare 539e7e1ca6eSGuenter Roeck static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, 540e7e1ca6eSGuenter Roeck u16 value) 54108e7e278SJean Delvare { 54208e7e278SJean Delvare int word_sized = is_word_sized(reg); 54308e7e278SJean Delvare 5449a61bf63SIngo Molnar mutex_lock(&data->lock); 54508e7e278SJean Delvare 5461ea6dd38SDavid Hubbard w83627ehf_set_bank(data, reg); 5471ea6dd38SDavid Hubbard outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); 54808e7e278SJean Delvare if (word_sized) { 5491ea6dd38SDavid Hubbard outb_p(value >> 8, data->addr + DATA_REG_OFFSET); 55008e7e278SJean Delvare outb_p((reg & 0xff) + 1, 5511ea6dd38SDavid Hubbard data->addr + ADDR_REG_OFFSET); 55208e7e278SJean Delvare } 5531ea6dd38SDavid Hubbard outb_p(value & 0xff, data->addr + DATA_REG_OFFSET); 55408e7e278SJean Delvare 5559a61bf63SIngo Molnar mutex_unlock(&data->lock); 55608e7e278SJean Delvare return 0; 55708e7e278SJean Delvare } 55808e7e278SJean Delvare 55908e7e278SJean Delvare /* This function assumes that the caller holds data->update_lock */ 560ec3e5a16SGuenter Roeck static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr) 561ec3e5a16SGuenter Roeck { 562ec3e5a16SGuenter Roeck u8 reg; 563ec3e5a16SGuenter Roeck 564ec3e5a16SGuenter Roeck switch (nr) { 565ec3e5a16SGuenter Roeck case 0: 566ec3e5a16SGuenter Roeck reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70) 567ec3e5a16SGuenter Roeck | (data->fan_div[0] & 0x7); 568ec3e5a16SGuenter Roeck w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg); 569ec3e5a16SGuenter Roeck break; 570ec3e5a16SGuenter Roeck case 1: 571ec3e5a16SGuenter Roeck reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7) 572ec3e5a16SGuenter Roeck | ((data->fan_div[1] << 4) & 0x70); 573ec3e5a16SGuenter Roeck w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg); 574ec3e5a16SGuenter Roeck case 2: 575ec3e5a16SGuenter Roeck reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70) 576ec3e5a16SGuenter Roeck | (data->fan_div[2] & 0x7); 577ec3e5a16SGuenter Roeck w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg); 578ec3e5a16SGuenter Roeck break; 579ec3e5a16SGuenter Roeck case 3: 580ec3e5a16SGuenter Roeck reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7) 581ec3e5a16SGuenter Roeck | ((data->fan_div[3] << 4) & 0x70); 582ec3e5a16SGuenter Roeck w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg); 583ec3e5a16SGuenter Roeck break; 584ec3e5a16SGuenter Roeck } 585ec3e5a16SGuenter Roeck } 586ec3e5a16SGuenter Roeck 587ec3e5a16SGuenter Roeck /* This function assumes that the caller holds data->update_lock */ 5881ea6dd38SDavid Hubbard static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr) 58908e7e278SJean Delvare { 59008e7e278SJean Delvare u8 reg; 59108e7e278SJean Delvare 59208e7e278SJean Delvare switch (nr) { 59308e7e278SJean Delvare case 0: 5941ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf) 59508e7e278SJean Delvare | ((data->fan_div[0] & 0x03) << 4); 59614992c7eSRudolf Marek /* fan5 input control bit is write only, compute the value */ 59714992c7eSRudolf Marek reg |= (data->has_fan & (1 << 4)) ? 1 : 0; 5981ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg); 5991ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf) 60008e7e278SJean Delvare | ((data->fan_div[0] & 0x04) << 3); 6011ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg); 60208e7e278SJean Delvare break; 60308e7e278SJean Delvare case 1: 6041ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f) 60508e7e278SJean Delvare | ((data->fan_div[1] & 0x03) << 6); 60614992c7eSRudolf Marek /* fan5 input control bit is write only, compute the value */ 60714992c7eSRudolf Marek reg |= (data->has_fan & (1 << 4)) ? 1 : 0; 6081ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg); 6091ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf) 61008e7e278SJean Delvare | ((data->fan_div[1] & 0x04) << 4); 6111ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg); 61208e7e278SJean Delvare break; 61308e7e278SJean Delvare case 2: 6141ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f) 61508e7e278SJean Delvare | ((data->fan_div[2] & 0x03) << 6); 6161ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg); 6171ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f) 61808e7e278SJean Delvare | ((data->fan_div[2] & 0x04) << 5); 6191ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg); 62008e7e278SJean Delvare break; 62108e7e278SJean Delvare case 3: 6221ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc) 62308e7e278SJean Delvare | (data->fan_div[3] & 0x03); 6241ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg); 6251ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f) 62608e7e278SJean Delvare | ((data->fan_div[3] & 0x04) << 5); 6271ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg); 62808e7e278SJean Delvare break; 62908e7e278SJean Delvare case 4: 6301ea6dd38SDavid Hubbard reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73) 63133725ad3SJean Delvare | ((data->fan_div[4] & 0x03) << 2) 63208e7e278SJean Delvare | ((data->fan_div[4] & 0x04) << 5); 6331ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg); 63408e7e278SJean Delvare break; 63508e7e278SJean Delvare } 63608e7e278SJean Delvare } 63708e7e278SJean Delvare 638ec3e5a16SGuenter Roeck static void w83627ehf_write_fan_div_common(struct device *dev, 639ec3e5a16SGuenter Roeck struct w83627ehf_data *data, int nr) 640ec3e5a16SGuenter Roeck { 641ec3e5a16SGuenter Roeck struct w83627ehf_sio_data *sio_data = dev->platform_data; 642ec3e5a16SGuenter Roeck 643ec3e5a16SGuenter Roeck if (sio_data->kind == nct6776) 644ec3e5a16SGuenter Roeck ; /* no dividers, do nothing */ 645ec3e5a16SGuenter Roeck else if (sio_data->kind == nct6775) 646ec3e5a16SGuenter Roeck nct6775_write_fan_div(data, nr); 647ec3e5a16SGuenter Roeck else 648ec3e5a16SGuenter Roeck w83627ehf_write_fan_div(data, nr); 649ec3e5a16SGuenter Roeck } 650ec3e5a16SGuenter Roeck 651ec3e5a16SGuenter Roeck static void nct6775_update_fan_div(struct w83627ehf_data *data) 652ec3e5a16SGuenter Roeck { 653ec3e5a16SGuenter Roeck u8 i; 654ec3e5a16SGuenter Roeck 655ec3e5a16SGuenter Roeck i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1); 656ec3e5a16SGuenter Roeck data->fan_div[0] = i & 0x7; 657ec3e5a16SGuenter Roeck data->fan_div[1] = (i & 0x70) >> 4; 658ec3e5a16SGuenter Roeck i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2); 659ec3e5a16SGuenter Roeck data->fan_div[2] = i & 0x7; 660ec3e5a16SGuenter Roeck if (data->has_fan & (1<<3)) 661ec3e5a16SGuenter Roeck data->fan_div[3] = (i & 0x70) >> 4; 662ec3e5a16SGuenter Roeck } 663ec3e5a16SGuenter Roeck 664ea7be66cSMark M. Hoffman static void w83627ehf_update_fan_div(struct w83627ehf_data *data) 66508e7e278SJean Delvare { 66608e7e278SJean Delvare int i; 66708e7e278SJean Delvare 6681ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); 66908e7e278SJean Delvare data->fan_div[0] = (i >> 4) & 0x03; 67008e7e278SJean Delvare data->fan_div[1] = (i >> 6) & 0x03; 6711ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2); 67208e7e278SJean Delvare data->fan_div[2] = (i >> 6) & 0x03; 6731ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_VBAT); 67408e7e278SJean Delvare data->fan_div[0] |= (i >> 3) & 0x04; 67508e7e278SJean Delvare data->fan_div[1] |= (i >> 4) & 0x04; 67608e7e278SJean Delvare data->fan_div[2] |= (i >> 5) & 0x04; 67708e7e278SJean Delvare if (data->has_fan & ((1 << 3) | (1 << 4))) { 6781ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_DIODE); 67908e7e278SJean Delvare data->fan_div[3] = i & 0x03; 68008e7e278SJean Delvare data->fan_div[4] = ((i >> 2) & 0x03) 68108e7e278SJean Delvare | ((i >> 5) & 0x04); 68208e7e278SJean Delvare } 68308e7e278SJean Delvare if (data->has_fan & (1 << 3)) { 6841ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT); 68508e7e278SJean Delvare data->fan_div[3] |= (i >> 5) & 0x04; 68608e7e278SJean Delvare } 687ea7be66cSMark M. Hoffman } 688ea7be66cSMark M. Hoffman 689ec3e5a16SGuenter Roeck static void w83627ehf_update_fan_div_common(struct device *dev, 690ec3e5a16SGuenter Roeck struct w83627ehf_data *data) 691ec3e5a16SGuenter Roeck { 692ec3e5a16SGuenter Roeck struct w83627ehf_sio_data *sio_data = dev->platform_data; 693ec3e5a16SGuenter Roeck 694ec3e5a16SGuenter Roeck if (sio_data->kind == nct6776) 695ec3e5a16SGuenter Roeck ; /* no dividers, do nothing */ 696ec3e5a16SGuenter Roeck else if (sio_data->kind == nct6775) 697ec3e5a16SGuenter Roeck nct6775_update_fan_div(data); 698ec3e5a16SGuenter Roeck else 699ec3e5a16SGuenter Roeck w83627ehf_update_fan_div(data); 700ec3e5a16SGuenter Roeck } 701ec3e5a16SGuenter Roeck 702ec3e5a16SGuenter Roeck static void nct6775_update_pwm(struct w83627ehf_data *data) 703ec3e5a16SGuenter Roeck { 704ec3e5a16SGuenter Roeck int i; 705ec3e5a16SGuenter Roeck int pwmcfg, fanmodecfg; 706ec3e5a16SGuenter Roeck 707ec3e5a16SGuenter Roeck for (i = 0; i < data->pwm_num; i++) { 708ec3e5a16SGuenter Roeck pwmcfg = w83627ehf_read_value(data, 709ec3e5a16SGuenter Roeck W83627EHF_REG_PWM_ENABLE[i]); 710ec3e5a16SGuenter Roeck fanmodecfg = w83627ehf_read_value(data, 711ec3e5a16SGuenter Roeck NCT6775_REG_FAN_MODE[i]); 712ec3e5a16SGuenter Roeck data->pwm_mode[i] = 713ec3e5a16SGuenter Roeck ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1; 714ec3e5a16SGuenter Roeck data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1; 715ec3e5a16SGuenter Roeck data->tolerance[i] = fanmodecfg & 0x0f; 716ec3e5a16SGuenter Roeck data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]); 717ec3e5a16SGuenter Roeck } 718ec3e5a16SGuenter Roeck } 719ec3e5a16SGuenter Roeck 720ec3e5a16SGuenter Roeck static void w83627ehf_update_pwm(struct w83627ehf_data *data) 721ec3e5a16SGuenter Roeck { 722ec3e5a16SGuenter Roeck int i; 723ec3e5a16SGuenter Roeck int pwmcfg = 0, tolerance = 0; /* shut up the compiler */ 724ec3e5a16SGuenter Roeck 725ec3e5a16SGuenter Roeck for (i = 0; i < data->pwm_num; i++) { 726ec3e5a16SGuenter Roeck if (!(data->has_fan & (1 << i))) 727ec3e5a16SGuenter Roeck continue; 728ec3e5a16SGuenter Roeck 729ec3e5a16SGuenter Roeck /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */ 730ec3e5a16SGuenter Roeck if (i != 1) { 731ec3e5a16SGuenter Roeck pwmcfg = w83627ehf_read_value(data, 732ec3e5a16SGuenter Roeck W83627EHF_REG_PWM_ENABLE[i]); 733ec3e5a16SGuenter Roeck tolerance = w83627ehf_read_value(data, 734ec3e5a16SGuenter Roeck W83627EHF_REG_TOLERANCE[i]); 735ec3e5a16SGuenter Roeck } 736ec3e5a16SGuenter Roeck data->pwm_mode[i] = 737ec3e5a16SGuenter Roeck ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1; 738ec3e5a16SGuenter Roeck data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) 739ec3e5a16SGuenter Roeck & 3) + 1; 740ec3e5a16SGuenter Roeck data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]); 741ec3e5a16SGuenter Roeck 742ec3e5a16SGuenter Roeck data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f; 743ec3e5a16SGuenter Roeck } 744ec3e5a16SGuenter Roeck } 745ec3e5a16SGuenter Roeck 746ec3e5a16SGuenter Roeck static void w83627ehf_update_pwm_common(struct device *dev, 747ec3e5a16SGuenter Roeck struct w83627ehf_data *data) 748ec3e5a16SGuenter Roeck { 749ec3e5a16SGuenter Roeck struct w83627ehf_sio_data *sio_data = dev->platform_data; 750ec3e5a16SGuenter Roeck 751ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775 || sio_data->kind == nct6776) 752ec3e5a16SGuenter Roeck nct6775_update_pwm(data); 753ec3e5a16SGuenter Roeck else 754ec3e5a16SGuenter Roeck w83627ehf_update_pwm(data); 755ec3e5a16SGuenter Roeck } 756ec3e5a16SGuenter Roeck 757ea7be66cSMark M. Hoffman static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) 758ea7be66cSMark M. Hoffman { 759ea7be66cSMark M. Hoffman struct w83627ehf_data *data = dev_get_drvdata(dev); 760ec3e5a16SGuenter Roeck struct w83627ehf_sio_data *sio_data = dev->platform_data; 761ec3e5a16SGuenter Roeck 762ea7be66cSMark M. Hoffman int i; 763ea7be66cSMark M. Hoffman 764ea7be66cSMark M. Hoffman mutex_lock(&data->update_lock); 765ea7be66cSMark M. Hoffman 766ea7be66cSMark M. Hoffman if (time_after(jiffies, data->last_updated + HZ + HZ/2) 767ea7be66cSMark M. Hoffman || !data->valid) { 768ea7be66cSMark M. Hoffman /* Fan clock dividers */ 769ec3e5a16SGuenter Roeck w83627ehf_update_fan_div_common(dev, data); 77008e7e278SJean Delvare 771cf0676feSRudolf Marek /* Measured voltages and limits */ 7721ea6dd38SDavid Hubbard for (i = 0; i < data->in_num; i++) { 7731ea6dd38SDavid Hubbard data->in[i] = w83627ehf_read_value(data, 774cf0676feSRudolf Marek W83627EHF_REG_IN(i)); 7751ea6dd38SDavid Hubbard data->in_min[i] = w83627ehf_read_value(data, 776cf0676feSRudolf Marek W83627EHF_REG_IN_MIN(i)); 7771ea6dd38SDavid Hubbard data->in_max[i] = w83627ehf_read_value(data, 778cf0676feSRudolf Marek W83627EHF_REG_IN_MAX(i)); 779cf0676feSRudolf Marek } 780cf0676feSRudolf Marek 78108e7e278SJean Delvare /* Measured fan speeds and limits */ 78208e7e278SJean Delvare for (i = 0; i < 5; i++) { 7833382a918SGuenter Roeck u16 reg; 7843382a918SGuenter Roeck 78508e7e278SJean Delvare if (!(data->has_fan & (1 << i))) 78608e7e278SJean Delvare continue; 78708e7e278SJean Delvare 7883382a918SGuenter Roeck reg = w83627ehf_read_value(data, data->REG_FAN[i]); 7893382a918SGuenter Roeck data->rpm[i] = data->fan_from_reg(reg, 7903382a918SGuenter Roeck data->fan_div[i]); 791ec3e5a16SGuenter Roeck 792ec3e5a16SGuenter Roeck if (data->has_fan_min & (1 << i)) 7931ea6dd38SDavid Hubbard data->fan_min[i] = w83627ehf_read_value(data, 794279af1a9SGuenter Roeck data->REG_FAN_MIN[i]); 79508e7e278SJean Delvare 79608e7e278SJean Delvare /* If we failed to measure the fan speed and clock 79708e7e278SJean Delvare divider can be increased, let's try that for next 79808e7e278SJean Delvare time */ 79926bc440eSGuenter Roeck if (data->has_fan_div 8003382a918SGuenter Roeck && (reg >= 0xff || (sio_data->kind == nct6775 8013382a918SGuenter Roeck && reg == 0x00)) 80208e7e278SJean Delvare && data->fan_div[i] < 0x07) { 8031ea6dd38SDavid Hubbard dev_dbg(dev, "Increasing fan%d " 80408e7e278SJean Delvare "clock divider from %u to %u\n", 80533725ad3SJean Delvare i + 1, div_from_reg(data->fan_div[i]), 80608e7e278SJean Delvare div_from_reg(data->fan_div[i] + 1)); 80708e7e278SJean Delvare data->fan_div[i]++; 808ec3e5a16SGuenter Roeck w83627ehf_write_fan_div_common(dev, data, i); 80908e7e278SJean Delvare /* Preserve min limit if possible */ 810ec3e5a16SGuenter Roeck if ((data->has_fan_min & (1 << i)) 811ec3e5a16SGuenter Roeck && data->fan_min[i] >= 2 81208e7e278SJean Delvare && data->fan_min[i] != 255) 8131ea6dd38SDavid Hubbard w83627ehf_write_value(data, 814279af1a9SGuenter Roeck data->REG_FAN_MIN[i], 81508e7e278SJean Delvare (data->fan_min[i] /= 2)); 81608e7e278SJean Delvare } 81708e7e278SJean Delvare } 81808e7e278SJean Delvare 819ec3e5a16SGuenter Roeck w83627ehf_update_pwm_common(dev, data); 820ec3e5a16SGuenter Roeck 821da2e0255SGuenter Roeck for (i = 0; i < data->pwm_num; i++) { 822da2e0255SGuenter Roeck if (!(data->has_fan & (1 << i))) 823da2e0255SGuenter Roeck continue; 824da2e0255SGuenter Roeck 825ec3e5a16SGuenter Roeck data->fan_start_output[i] = 826ec3e5a16SGuenter Roeck w83627ehf_read_value(data, 827279af1a9SGuenter Roeck data->REG_FAN_START_OUTPUT[i]); 828ec3e5a16SGuenter Roeck data->fan_stop_output[i] = 829ec3e5a16SGuenter Roeck w83627ehf_read_value(data, 830279af1a9SGuenter Roeck data->REG_FAN_STOP_OUTPUT[i]); 831ec3e5a16SGuenter Roeck data->fan_stop_time[i] = 832ec3e5a16SGuenter Roeck w83627ehf_read_value(data, 833279af1a9SGuenter Roeck data->REG_FAN_STOP_TIME[i]); 834da2e0255SGuenter Roeck 835ec3e5a16SGuenter Roeck if (data->REG_FAN_MAX_OUTPUT && 836ec3e5a16SGuenter Roeck data->REG_FAN_MAX_OUTPUT[i] != 0xff) 837da2e0255SGuenter Roeck data->fan_max_output[i] = 838da2e0255SGuenter Roeck w83627ehf_read_value(data, 839da2e0255SGuenter Roeck data->REG_FAN_MAX_OUTPUT[i]); 840da2e0255SGuenter Roeck 841ec3e5a16SGuenter Roeck if (data->REG_FAN_STEP_OUTPUT && 842ec3e5a16SGuenter Roeck data->REG_FAN_STEP_OUTPUT[i] != 0xff) 843da2e0255SGuenter Roeck data->fan_step_output[i] = 844da2e0255SGuenter Roeck w83627ehf_read_value(data, 845da2e0255SGuenter Roeck data->REG_FAN_STEP_OUTPUT[i]); 846da2e0255SGuenter Roeck 84708c79950SRudolf Marek data->target_temp[i] = 8481ea6dd38SDavid Hubbard w83627ehf_read_value(data, 849279af1a9SGuenter Roeck data->REG_TARGET[i]) & 85008c79950SRudolf Marek (data->pwm_mode[i] == 1 ? 0x7f : 0xff); 85108c79950SRudolf Marek } 85208c79950SRudolf Marek 85308e7e278SJean Delvare /* Measured temperatures and limits */ 854d36cf32cSGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) { 855d36cf32cSGuenter Roeck if (!(data->have_temp & (1 << i))) 856d36cf32cSGuenter Roeck continue; 857ec3e5a16SGuenter Roeck data->temp[i] = w83627ehf_read_value(data, 858ec3e5a16SGuenter Roeck data->reg_temp[i]); 859ec3e5a16SGuenter Roeck if (data->reg_temp_over[i]) 860d36cf32cSGuenter Roeck data->temp_max[i] 861d36cf32cSGuenter Roeck = w83627ehf_read_value(data, 862ec3e5a16SGuenter Roeck data->reg_temp_over[i]); 863ec3e5a16SGuenter Roeck if (data->reg_temp_hyst[i]) 864d36cf32cSGuenter Roeck data->temp_max_hyst[i] 865d36cf32cSGuenter Roeck = w83627ehf_read_value(data, 866ec3e5a16SGuenter Roeck data->reg_temp_hyst[i]); 86708e7e278SJean Delvare } 86808e7e278SJean Delvare 8691ea6dd38SDavid Hubbard data->alarms = w83627ehf_read_value(data, 870a4589dbbSJean Delvare W83627EHF_REG_ALARM1) | 8711ea6dd38SDavid Hubbard (w83627ehf_read_value(data, 872a4589dbbSJean Delvare W83627EHF_REG_ALARM2) << 8) | 8731ea6dd38SDavid Hubbard (w83627ehf_read_value(data, 874a4589dbbSJean Delvare W83627EHF_REG_ALARM3) << 16); 875a4589dbbSJean Delvare 87608e7e278SJean Delvare data->last_updated = jiffies; 87708e7e278SJean Delvare data->valid = 1; 87808e7e278SJean Delvare } 87908e7e278SJean Delvare 8809a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 88108e7e278SJean Delvare return data; 88208e7e278SJean Delvare } 88308e7e278SJean Delvare 88408e7e278SJean Delvare /* 88508e7e278SJean Delvare * Sysfs callback functions 88608e7e278SJean Delvare */ 887cf0676feSRudolf Marek #define show_in_reg(reg) \ 888cf0676feSRudolf Marek static ssize_t \ 889cf0676feSRudolf Marek show_##reg(struct device *dev, struct device_attribute *attr, \ 890cf0676feSRudolf Marek char *buf) \ 891cf0676feSRudolf Marek { \ 892cf0676feSRudolf Marek struct w83627ehf_data *data = w83627ehf_update_device(dev); \ 893e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 894e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 895cf0676feSRudolf Marek int nr = sensor_attr->index; \ 896cf0676feSRudolf Marek return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \ 897cf0676feSRudolf Marek } 898cf0676feSRudolf Marek show_in_reg(in) 899cf0676feSRudolf Marek show_in_reg(in_min) 900cf0676feSRudolf Marek show_in_reg(in_max) 901cf0676feSRudolf Marek 902cf0676feSRudolf Marek #define store_in_reg(REG, reg) \ 903cf0676feSRudolf Marek static ssize_t \ 904cf0676feSRudolf Marek store_in_##reg(struct device *dev, struct device_attribute *attr, \ 905cf0676feSRudolf Marek const char *buf, size_t count) \ 906cf0676feSRudolf Marek { \ 9071ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); \ 908e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 909e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 910cf0676feSRudolf Marek int nr = sensor_attr->index; \ 911bce26c58SGuenter Roeck unsigned long val; \ 912bce26c58SGuenter Roeck int err; \ 913bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); \ 914bce26c58SGuenter Roeck if (err < 0) \ 915bce26c58SGuenter Roeck return err; \ 916cf0676feSRudolf Marek mutex_lock(&data->update_lock); \ 917cf0676feSRudolf Marek data->in_##reg[nr] = in_to_reg(val, nr); \ 9181ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \ 919cf0676feSRudolf Marek data->in_##reg[nr]); \ 920cf0676feSRudolf Marek mutex_unlock(&data->update_lock); \ 921cf0676feSRudolf Marek return count; \ 922cf0676feSRudolf Marek } 923cf0676feSRudolf Marek 924cf0676feSRudolf Marek store_in_reg(MIN, min) 925cf0676feSRudolf Marek store_in_reg(MAX, max) 926cf0676feSRudolf Marek 927e7e1ca6eSGuenter Roeck static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 928e7e1ca6eSGuenter Roeck char *buf) 929a4589dbbSJean Delvare { 930a4589dbbSJean Delvare struct w83627ehf_data *data = w83627ehf_update_device(dev); 931a4589dbbSJean Delvare struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 932a4589dbbSJean Delvare int nr = sensor_attr->index; 933a4589dbbSJean Delvare return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01); 934a4589dbbSJean Delvare } 935a4589dbbSJean Delvare 936cf0676feSRudolf Marek static struct sensor_device_attribute sda_in_input[] = { 937cf0676feSRudolf Marek SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), 938cf0676feSRudolf Marek SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), 939cf0676feSRudolf Marek SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), 940cf0676feSRudolf Marek SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), 941cf0676feSRudolf Marek SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), 942cf0676feSRudolf Marek SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), 943cf0676feSRudolf Marek SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), 944cf0676feSRudolf Marek SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), 945cf0676feSRudolf Marek SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), 946cf0676feSRudolf Marek SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9), 947cf0676feSRudolf Marek }; 948cf0676feSRudolf Marek 949a4589dbbSJean Delvare static struct sensor_device_attribute sda_in_alarm[] = { 950a4589dbbSJean Delvare SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), 951a4589dbbSJean Delvare SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), 952a4589dbbSJean Delvare SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), 953a4589dbbSJean Delvare SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), 954a4589dbbSJean Delvare SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8), 955a4589dbbSJean Delvare SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21), 956a4589dbbSJean Delvare SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20), 957a4589dbbSJean Delvare SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16), 958a4589dbbSJean Delvare SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17), 959a4589dbbSJean Delvare SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19), 960a4589dbbSJean Delvare }; 961a4589dbbSJean Delvare 962cf0676feSRudolf Marek static struct sensor_device_attribute sda_in_min[] = { 963cf0676feSRudolf Marek SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), 964cf0676feSRudolf Marek SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), 965cf0676feSRudolf Marek SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), 966cf0676feSRudolf Marek SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), 967cf0676feSRudolf Marek SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), 968cf0676feSRudolf Marek SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), 969cf0676feSRudolf Marek SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), 970cf0676feSRudolf Marek SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), 971cf0676feSRudolf Marek SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), 972cf0676feSRudolf Marek SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9), 973cf0676feSRudolf Marek }; 974cf0676feSRudolf Marek 975cf0676feSRudolf Marek static struct sensor_device_attribute sda_in_max[] = { 976cf0676feSRudolf Marek SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), 977cf0676feSRudolf Marek SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), 978cf0676feSRudolf Marek SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), 979cf0676feSRudolf Marek SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), 980cf0676feSRudolf Marek SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), 981cf0676feSRudolf Marek SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), 982cf0676feSRudolf Marek SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), 983cf0676feSRudolf Marek SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), 984cf0676feSRudolf Marek SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), 985cf0676feSRudolf Marek SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), 986cf0676feSRudolf Marek }; 987cf0676feSRudolf Marek 988ec3e5a16SGuenter Roeck static ssize_t 989ec3e5a16SGuenter Roeck show_fan(struct device *dev, struct device_attribute *attr, char *buf) 990ec3e5a16SGuenter Roeck { 991ec3e5a16SGuenter Roeck struct w83627ehf_data *data = w83627ehf_update_device(dev); 992ec3e5a16SGuenter Roeck struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 993ec3e5a16SGuenter Roeck int nr = sensor_attr->index; 9943382a918SGuenter Roeck return sprintf(buf, "%d\n", data->rpm[nr]); 99508e7e278SJean Delvare } 996ec3e5a16SGuenter Roeck 997ec3e5a16SGuenter Roeck static ssize_t 998ec3e5a16SGuenter Roeck show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) 999ec3e5a16SGuenter Roeck { 1000ec3e5a16SGuenter Roeck struct w83627ehf_data *data = w83627ehf_update_device(dev); 1001ec3e5a16SGuenter Roeck struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 1002ec3e5a16SGuenter Roeck int nr = sensor_attr->index; 1003ec3e5a16SGuenter Roeck return sprintf(buf, "%d\n", 100426bc440eSGuenter Roeck data->fan_from_reg_min(data->fan_min[nr], 100526bc440eSGuenter Roeck data->fan_div[nr])); 1006ec3e5a16SGuenter Roeck } 100708e7e278SJean Delvare 100808e7e278SJean Delvare static ssize_t 1009412fec82SYuan Mu show_fan_div(struct device *dev, struct device_attribute *attr, 1010412fec82SYuan Mu char *buf) 101108e7e278SJean Delvare { 101208e7e278SJean Delvare struct w83627ehf_data *data = w83627ehf_update_device(dev); 1013412fec82SYuan Mu struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 1014412fec82SYuan Mu int nr = sensor_attr->index; 1015412fec82SYuan Mu return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr])); 101608e7e278SJean Delvare } 101708e7e278SJean Delvare 101808e7e278SJean Delvare static ssize_t 1019412fec82SYuan Mu store_fan_min(struct device *dev, struct device_attribute *attr, 1020412fec82SYuan Mu const char *buf, size_t count) 102108e7e278SJean Delvare { 10221ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 1023412fec82SYuan Mu struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 1024412fec82SYuan Mu int nr = sensor_attr->index; 1025bce26c58SGuenter Roeck unsigned long val; 1026bce26c58SGuenter Roeck int err; 102708e7e278SJean Delvare unsigned int reg; 102808e7e278SJean Delvare u8 new_div; 102908e7e278SJean Delvare 1030bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); 1031bce26c58SGuenter Roeck if (err < 0) 1032bce26c58SGuenter Roeck return err; 1033bce26c58SGuenter Roeck 10349a61bf63SIngo Molnar mutex_lock(&data->update_lock); 103526bc440eSGuenter Roeck if (!data->has_fan_div) { 103626bc440eSGuenter Roeck /* 103726bc440eSGuenter Roeck * Only NCT6776F for now, so we know that this is a 13 bit 103826bc440eSGuenter Roeck * register 103926bc440eSGuenter Roeck */ 1040ec3e5a16SGuenter Roeck if (!val) { 1041ec3e5a16SGuenter Roeck val = 0xff1f; 1042ec3e5a16SGuenter Roeck } else { 1043ec3e5a16SGuenter Roeck if (val > 1350000U) 1044ec3e5a16SGuenter Roeck val = 135000U; 1045ec3e5a16SGuenter Roeck val = 1350000U / val; 1046ec3e5a16SGuenter Roeck val = (val & 0x1f) | ((val << 3) & 0xff00); 1047ec3e5a16SGuenter Roeck } 1048ec3e5a16SGuenter Roeck data->fan_min[nr] = val; 1049ec3e5a16SGuenter Roeck goto done; /* Leave fan divider alone */ 1050ec3e5a16SGuenter Roeck } 105108e7e278SJean Delvare if (!val) { 105208e7e278SJean Delvare /* No min limit, alarm disabled */ 105308e7e278SJean Delvare data->fan_min[nr] = 255; 105408e7e278SJean Delvare new_div = data->fan_div[nr]; /* No change */ 105508e7e278SJean Delvare dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); 105608e7e278SJean Delvare } else if ((reg = 1350000U / val) >= 128 * 255) { 105708e7e278SJean Delvare /* Speed below this value cannot possibly be represented, 105808e7e278SJean Delvare even with the highest divider (128) */ 105908e7e278SJean Delvare data->fan_min[nr] = 254; 106008e7e278SJean Delvare new_div = 7; /* 128 == (1 << 7) */ 1061bce26c58SGuenter Roeck dev_warn(dev, "fan%u low limit %lu below minimum %u, set to " 1062ec3e5a16SGuenter Roeck "minimum\n", nr + 1, val, 106326bc440eSGuenter Roeck data->fan_from_reg_min(254, 7)); 106408e7e278SJean Delvare } else if (!reg) { 106508e7e278SJean Delvare /* Speed above this value cannot possibly be represented, 106608e7e278SJean Delvare even with the lowest divider (1) */ 106708e7e278SJean Delvare data->fan_min[nr] = 1; 106808e7e278SJean Delvare new_div = 0; /* 1 == (1 << 0) */ 1069bce26c58SGuenter Roeck dev_warn(dev, "fan%u low limit %lu above maximum %u, set to " 1070ec3e5a16SGuenter Roeck "maximum\n", nr + 1, val, 107126bc440eSGuenter Roeck data->fan_from_reg_min(1, 0)); 107208e7e278SJean Delvare } else { 107308e7e278SJean Delvare /* Automatically pick the best divider, i.e. the one such 107408e7e278SJean Delvare that the min limit will correspond to a register value 107508e7e278SJean Delvare in the 96..192 range */ 107608e7e278SJean Delvare new_div = 0; 107708e7e278SJean Delvare while (reg > 192 && new_div < 7) { 107808e7e278SJean Delvare reg >>= 1; 107908e7e278SJean Delvare new_div++; 108008e7e278SJean Delvare } 108108e7e278SJean Delvare data->fan_min[nr] = reg; 108208e7e278SJean Delvare } 108308e7e278SJean Delvare 108408e7e278SJean Delvare /* Write both the fan clock divider (if it changed) and the new 108508e7e278SJean Delvare fan min (unconditionally) */ 108608e7e278SJean Delvare if (new_div != data->fan_div[nr]) { 108708e7e278SJean Delvare dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", 108808e7e278SJean Delvare nr + 1, div_from_reg(data->fan_div[nr]), 108908e7e278SJean Delvare div_from_reg(new_div)); 109008e7e278SJean Delvare data->fan_div[nr] = new_div; 1091ec3e5a16SGuenter Roeck w83627ehf_write_fan_div_common(dev, data, nr); 10926b3e4645SJean Delvare /* Give the chip time to sample a new speed value */ 10936b3e4645SJean Delvare data->last_updated = jiffies; 109408e7e278SJean Delvare } 1095ec3e5a16SGuenter Roeck done: 1096279af1a9SGuenter Roeck w83627ehf_write_value(data, data->REG_FAN_MIN[nr], 109708e7e278SJean Delvare data->fan_min[nr]); 10989a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 109908e7e278SJean Delvare 110008e7e278SJean Delvare return count; 110108e7e278SJean Delvare } 110208e7e278SJean Delvare 1103412fec82SYuan Mu static struct sensor_device_attribute sda_fan_input[] = { 1104412fec82SYuan Mu SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), 1105412fec82SYuan Mu SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), 1106412fec82SYuan Mu SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), 1107412fec82SYuan Mu SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3), 1108412fec82SYuan Mu SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4), 1109412fec82SYuan Mu }; 111008e7e278SJean Delvare 1111a4589dbbSJean Delvare static struct sensor_device_attribute sda_fan_alarm[] = { 1112a4589dbbSJean Delvare SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6), 1113a4589dbbSJean Delvare SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7), 1114a4589dbbSJean Delvare SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11), 1115a4589dbbSJean Delvare SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10), 1116a4589dbbSJean Delvare SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23), 1117a4589dbbSJean Delvare }; 1118a4589dbbSJean Delvare 1119412fec82SYuan Mu static struct sensor_device_attribute sda_fan_min[] = { 1120412fec82SYuan Mu SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, 1121412fec82SYuan Mu store_fan_min, 0), 1122412fec82SYuan Mu SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, 1123412fec82SYuan Mu store_fan_min, 1), 1124412fec82SYuan Mu SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, 1125412fec82SYuan Mu store_fan_min, 2), 1126412fec82SYuan Mu SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, 1127412fec82SYuan Mu store_fan_min, 3), 1128412fec82SYuan Mu SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, 1129412fec82SYuan Mu store_fan_min, 4), 1130412fec82SYuan Mu }; 113108e7e278SJean Delvare 1132412fec82SYuan Mu static struct sensor_device_attribute sda_fan_div[] = { 1133412fec82SYuan Mu SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0), 1134412fec82SYuan Mu SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1), 1135412fec82SYuan Mu SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2), 1136412fec82SYuan Mu SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3), 1137412fec82SYuan Mu SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4), 1138412fec82SYuan Mu }; 113908e7e278SJean Delvare 1140d36cf32cSGuenter Roeck static ssize_t 1141d36cf32cSGuenter Roeck show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) 1142d36cf32cSGuenter Roeck { 1143d36cf32cSGuenter Roeck struct w83627ehf_data *data = w83627ehf_update_device(dev); 1144d36cf32cSGuenter Roeck struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 1145d36cf32cSGuenter Roeck int nr = sensor_attr->index; 1146d36cf32cSGuenter Roeck return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); 1147d36cf32cSGuenter Roeck } 1148d36cf32cSGuenter Roeck 1149ec3e5a16SGuenter Roeck #define show_temp_reg(addr, reg) \ 115008e7e278SJean Delvare static ssize_t \ 1151412fec82SYuan Mu show_##reg(struct device *dev, struct device_attribute *attr, \ 1152412fec82SYuan Mu char *buf) \ 115308e7e278SJean Delvare { \ 115408e7e278SJean Delvare struct w83627ehf_data *data = w83627ehf_update_device(dev); \ 1155e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1156e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 1157412fec82SYuan Mu int nr = sensor_attr->index; \ 115808e7e278SJean Delvare return sprintf(buf, "%d\n", \ 1159ec3e5a16SGuenter Roeck temp_from_reg(data->addr[nr], data->reg[nr])); \ 116008e7e278SJean Delvare } 1161ec3e5a16SGuenter Roeck show_temp_reg(reg_temp, temp); 1162ec3e5a16SGuenter Roeck show_temp_reg(reg_temp_over, temp_max); 1163ec3e5a16SGuenter Roeck show_temp_reg(reg_temp_hyst, temp_max_hyst); 116408e7e278SJean Delvare 1165ec3e5a16SGuenter Roeck #define store_temp_reg(addr, reg) \ 116608e7e278SJean Delvare static ssize_t \ 1167412fec82SYuan Mu store_##reg(struct device *dev, struct device_attribute *attr, \ 1168412fec82SYuan Mu const char *buf, size_t count) \ 116908e7e278SJean Delvare { \ 11701ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); \ 1171e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1172e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 1173412fec82SYuan Mu int nr = sensor_attr->index; \ 1174bce26c58SGuenter Roeck int err; \ 1175bce26c58SGuenter Roeck long val; \ 1176bce26c58SGuenter Roeck err = strict_strtol(buf, 10, &val); \ 1177bce26c58SGuenter Roeck if (err < 0) \ 1178bce26c58SGuenter Roeck return err; \ 11799a61bf63SIngo Molnar mutex_lock(&data->update_lock); \ 1180ec3e5a16SGuenter Roeck data->reg[nr] = temp_to_reg(data->addr[nr], val); \ 1181ec3e5a16SGuenter Roeck w83627ehf_write_value(data, data->addr[nr], \ 118208e7e278SJean Delvare data->reg[nr]); \ 11839a61bf63SIngo Molnar mutex_unlock(&data->update_lock); \ 118408e7e278SJean Delvare return count; \ 118508e7e278SJean Delvare } 1186ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_over, temp_max); 1187ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_hyst, temp_max_hyst); 118808e7e278SJean Delvare 1189da667365SJean Delvare static ssize_t 1190da667365SJean Delvare show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) 1191da667365SJean Delvare { 1192da667365SJean Delvare struct w83627ehf_data *data = w83627ehf_update_device(dev); 1193da667365SJean Delvare struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 1194da667365SJean Delvare int nr = sensor_attr->index; 1195da667365SJean Delvare return sprintf(buf, "%d\n", (int)data->temp_type[nr]); 1196da667365SJean Delvare } 1197da667365SJean Delvare 1198a157d06dSGong Jun static struct sensor_device_attribute sda_temp_input[] = { 1199bce26c58SGuenter Roeck SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), 1200bce26c58SGuenter Roeck SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), 1201bce26c58SGuenter Roeck SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), 1202d36cf32cSGuenter Roeck SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3), 1203ec3e5a16SGuenter Roeck SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4), 1204ec3e5a16SGuenter Roeck SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5), 1205ec3e5a16SGuenter Roeck SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6), 1206ec3e5a16SGuenter Roeck SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7), 1207ec3e5a16SGuenter Roeck SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8), 1208d36cf32cSGuenter Roeck }; 1209d36cf32cSGuenter Roeck 1210d36cf32cSGuenter Roeck static struct sensor_device_attribute sda_temp_label[] = { 1211d36cf32cSGuenter Roeck SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0), 1212d36cf32cSGuenter Roeck SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1), 1213d36cf32cSGuenter Roeck SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2), 1214d36cf32cSGuenter Roeck SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3), 1215ec3e5a16SGuenter Roeck SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4), 1216ec3e5a16SGuenter Roeck SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5), 1217ec3e5a16SGuenter Roeck SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6), 1218ec3e5a16SGuenter Roeck SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7), 1219ec3e5a16SGuenter Roeck SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8), 1220a157d06dSGong Jun }; 1221a157d06dSGong Jun 1222a157d06dSGong Jun static struct sensor_device_attribute sda_temp_max[] = { 1223bce26c58SGuenter Roeck SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max, 1224412fec82SYuan Mu store_temp_max, 0), 1225bce26c58SGuenter Roeck SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, 1226412fec82SYuan Mu store_temp_max, 1), 1227bce26c58SGuenter Roeck SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, 1228bce26c58SGuenter Roeck store_temp_max, 2), 1229ec3e5a16SGuenter Roeck SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max, 1230ec3e5a16SGuenter Roeck store_temp_max, 3), 1231ec3e5a16SGuenter Roeck SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max, 1232ec3e5a16SGuenter Roeck store_temp_max, 4), 1233ec3e5a16SGuenter Roeck SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max, 1234ec3e5a16SGuenter Roeck store_temp_max, 5), 1235ec3e5a16SGuenter Roeck SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max, 1236ec3e5a16SGuenter Roeck store_temp_max, 6), 1237ec3e5a16SGuenter Roeck SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max, 1238ec3e5a16SGuenter Roeck store_temp_max, 7), 1239ec3e5a16SGuenter Roeck SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max, 1240ec3e5a16SGuenter Roeck store_temp_max, 8), 1241a157d06dSGong Jun }; 1242a157d06dSGong Jun 1243a157d06dSGong Jun static struct sensor_device_attribute sda_temp_max_hyst[] = { 1244bce26c58SGuenter Roeck SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1245412fec82SYuan Mu store_temp_max_hyst, 0), 1246bce26c58SGuenter Roeck SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1247412fec82SYuan Mu store_temp_max_hyst, 1), 1248bce26c58SGuenter Roeck SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1249bce26c58SGuenter Roeck store_temp_max_hyst, 2), 1250ec3e5a16SGuenter Roeck SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1251ec3e5a16SGuenter Roeck store_temp_max_hyst, 3), 1252ec3e5a16SGuenter Roeck SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1253ec3e5a16SGuenter Roeck store_temp_max_hyst, 4), 1254ec3e5a16SGuenter Roeck SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1255ec3e5a16SGuenter Roeck store_temp_max_hyst, 5), 1256ec3e5a16SGuenter Roeck SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1257ec3e5a16SGuenter Roeck store_temp_max_hyst, 6), 1258ec3e5a16SGuenter Roeck SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1259ec3e5a16SGuenter Roeck store_temp_max_hyst, 7), 1260ec3e5a16SGuenter Roeck SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, 1261ec3e5a16SGuenter Roeck store_temp_max_hyst, 8), 1262a157d06dSGong Jun }; 1263a157d06dSGong Jun 1264a157d06dSGong Jun static struct sensor_device_attribute sda_temp_alarm[] = { 1265a4589dbbSJean Delvare SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), 1266a4589dbbSJean Delvare SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), 1267a4589dbbSJean Delvare SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), 1268a157d06dSGong Jun }; 1269a157d06dSGong Jun 1270a157d06dSGong Jun static struct sensor_device_attribute sda_temp_type[] = { 1271da667365SJean Delvare SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), 1272da667365SJean Delvare SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), 1273da667365SJean Delvare SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), 1274412fec82SYuan Mu }; 127508e7e278SJean Delvare 127608c79950SRudolf Marek #define show_pwm_reg(reg) \ 127708c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 127808c79950SRudolf Marek char *buf) \ 127908c79950SRudolf Marek { \ 128008c79950SRudolf Marek struct w83627ehf_data *data = w83627ehf_update_device(dev); \ 1281e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1282e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 128308c79950SRudolf Marek int nr = sensor_attr->index; \ 128408c79950SRudolf Marek return sprintf(buf, "%d\n", data->reg[nr]); \ 128508c79950SRudolf Marek } 128608c79950SRudolf Marek 128708c79950SRudolf Marek show_pwm_reg(pwm_mode) 128808c79950SRudolf Marek show_pwm_reg(pwm_enable) 128908c79950SRudolf Marek show_pwm_reg(pwm) 129008c79950SRudolf Marek 129108c79950SRudolf Marek static ssize_t 129208c79950SRudolf Marek store_pwm_mode(struct device *dev, struct device_attribute *attr, 129308c79950SRudolf Marek const char *buf, size_t count) 129408c79950SRudolf Marek { 12951ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 129608c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 129708c79950SRudolf Marek int nr = sensor_attr->index; 1298bce26c58SGuenter Roeck unsigned long val; 1299bce26c58SGuenter Roeck int err; 130008c79950SRudolf Marek u16 reg; 130108c79950SRudolf Marek 1302bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); 1303bce26c58SGuenter Roeck if (err < 0) 1304bce26c58SGuenter Roeck return err; 1305bce26c58SGuenter Roeck 130608c79950SRudolf Marek if (val > 1) 130708c79950SRudolf Marek return -EINVAL; 130808c79950SRudolf Marek mutex_lock(&data->update_lock); 13091ea6dd38SDavid Hubbard reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); 131008c79950SRudolf Marek data->pwm_mode[nr] = val; 131108c79950SRudolf Marek reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]); 131208c79950SRudolf Marek if (!val) 131308c79950SRudolf Marek reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr]; 13141ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg); 131508c79950SRudolf Marek mutex_unlock(&data->update_lock); 131608c79950SRudolf Marek return count; 131708c79950SRudolf Marek } 131808c79950SRudolf Marek 131908c79950SRudolf Marek static ssize_t 132008c79950SRudolf Marek store_pwm(struct device *dev, struct device_attribute *attr, 132108c79950SRudolf Marek const char *buf, size_t count) 132208c79950SRudolf Marek { 13231ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 132408c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 132508c79950SRudolf Marek int nr = sensor_attr->index; 1326bce26c58SGuenter Roeck unsigned long val; 1327bce26c58SGuenter Roeck int err; 1328bce26c58SGuenter Roeck 1329bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); 1330bce26c58SGuenter Roeck if (err < 0) 1331bce26c58SGuenter Roeck return err; 1332bce26c58SGuenter Roeck 1333bce26c58SGuenter Roeck val = SENSORS_LIMIT(val, 0, 255); 133408c79950SRudolf Marek 133508c79950SRudolf Marek mutex_lock(&data->update_lock); 133608c79950SRudolf Marek data->pwm[nr] = val; 1337279af1a9SGuenter Roeck w83627ehf_write_value(data, data->REG_PWM[nr], val); 133808c79950SRudolf Marek mutex_unlock(&data->update_lock); 133908c79950SRudolf Marek return count; 134008c79950SRudolf Marek } 134108c79950SRudolf Marek 134208c79950SRudolf Marek static ssize_t 134308c79950SRudolf Marek store_pwm_enable(struct device *dev, struct device_attribute *attr, 134408c79950SRudolf Marek const char *buf, size_t count) 134508c79950SRudolf Marek { 13461ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 1347ec3e5a16SGuenter Roeck struct w83627ehf_sio_data *sio_data = dev->platform_data; 134808c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 134908c79950SRudolf Marek int nr = sensor_attr->index; 1350bce26c58SGuenter Roeck unsigned long val; 1351bce26c58SGuenter Roeck int err; 135208c79950SRudolf Marek u16 reg; 135308c79950SRudolf Marek 1354bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); 1355bce26c58SGuenter Roeck if (err < 0) 1356bce26c58SGuenter Roeck return err; 1357bce26c58SGuenter Roeck 1358b84bb518SGuenter Roeck if (!val || (val > 4 && val != data->pwm_enable_orig[nr])) 135908c79950SRudolf Marek return -EINVAL; 1360ec3e5a16SGuenter Roeck /* SmartFan III mode is not supported on NCT6776F */ 1361ec3e5a16SGuenter Roeck if (sio_data->kind == nct6776 && val == 4) 1362ec3e5a16SGuenter Roeck return -EINVAL; 1363ec3e5a16SGuenter Roeck 136408c79950SRudolf Marek mutex_lock(&data->update_lock); 136508c79950SRudolf Marek data->pwm_enable[nr] = val; 1366ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { 1367ec3e5a16SGuenter Roeck reg = w83627ehf_read_value(data, 1368ec3e5a16SGuenter Roeck NCT6775_REG_FAN_MODE[nr]); 1369ec3e5a16SGuenter Roeck reg &= 0x0f; 1370ec3e5a16SGuenter Roeck reg |= (val - 1) << 4; 1371ec3e5a16SGuenter Roeck w83627ehf_write_value(data, 1372ec3e5a16SGuenter Roeck NCT6775_REG_FAN_MODE[nr], reg); 1373ec3e5a16SGuenter Roeck } else { 1374ec3e5a16SGuenter Roeck reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); 137508c79950SRudolf Marek reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); 137608c79950SRudolf Marek reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; 13771ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg); 1378ec3e5a16SGuenter Roeck } 137908c79950SRudolf Marek mutex_unlock(&data->update_lock); 138008c79950SRudolf Marek return count; 138108c79950SRudolf Marek } 138208c79950SRudolf Marek 138308c79950SRudolf Marek 138408c79950SRudolf Marek #define show_tol_temp(reg) \ 138508c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 138608c79950SRudolf Marek char *buf) \ 138708c79950SRudolf Marek { \ 138808c79950SRudolf Marek struct w83627ehf_data *data = w83627ehf_update_device(dev); \ 1389e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1390e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 139108c79950SRudolf Marek int nr = sensor_attr->index; \ 1392bce26c58SGuenter Roeck return sprintf(buf, "%d\n", data->reg[nr] * 1000); \ 139308c79950SRudolf Marek } 139408c79950SRudolf Marek 139508c79950SRudolf Marek show_tol_temp(tolerance) 139608c79950SRudolf Marek show_tol_temp(target_temp) 139708c79950SRudolf Marek 139808c79950SRudolf Marek static ssize_t 139908c79950SRudolf Marek store_target_temp(struct device *dev, struct device_attribute *attr, 140008c79950SRudolf Marek const char *buf, size_t count) 140108c79950SRudolf Marek { 14021ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 140308c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 140408c79950SRudolf Marek int nr = sensor_attr->index; 1405bce26c58SGuenter Roeck long val; 1406bce26c58SGuenter Roeck int err; 1407bce26c58SGuenter Roeck 1408bce26c58SGuenter Roeck err = strict_strtol(buf, 10, &val); 1409bce26c58SGuenter Roeck if (err < 0) 1410bce26c58SGuenter Roeck return err; 1411bce26c58SGuenter Roeck 1412bce26c58SGuenter Roeck val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127); 141308c79950SRudolf Marek 141408c79950SRudolf Marek mutex_lock(&data->update_lock); 141508c79950SRudolf Marek data->target_temp[nr] = val; 1416279af1a9SGuenter Roeck w83627ehf_write_value(data, data->REG_TARGET[nr], val); 141708c79950SRudolf Marek mutex_unlock(&data->update_lock); 141808c79950SRudolf Marek return count; 141908c79950SRudolf Marek } 142008c79950SRudolf Marek 142108c79950SRudolf Marek static ssize_t 142208c79950SRudolf Marek store_tolerance(struct device *dev, struct device_attribute *attr, 142308c79950SRudolf Marek const char *buf, size_t count) 142408c79950SRudolf Marek { 14251ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 1426ec3e5a16SGuenter Roeck struct w83627ehf_sio_data *sio_data = dev->platform_data; 142708c79950SRudolf Marek struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 142808c79950SRudolf Marek int nr = sensor_attr->index; 142908c79950SRudolf Marek u16 reg; 1430bce26c58SGuenter Roeck long val; 1431bce26c58SGuenter Roeck int err; 1432bce26c58SGuenter Roeck 1433bce26c58SGuenter Roeck err = strict_strtol(buf, 10, &val); 1434bce26c58SGuenter Roeck if (err < 0) 1435bce26c58SGuenter Roeck return err; 1436bce26c58SGuenter Roeck 143708c79950SRudolf Marek /* Limit the temp to 0C - 15C */ 1438bce26c58SGuenter Roeck val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15); 143908c79950SRudolf Marek 144008c79950SRudolf Marek mutex_lock(&data->update_lock); 1441ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { 1442ec3e5a16SGuenter Roeck /* Limit tolerance further for NCT6776F */ 1443ec3e5a16SGuenter Roeck if (sio_data->kind == nct6776 && val > 7) 1444ec3e5a16SGuenter Roeck val = 7; 1445ec3e5a16SGuenter Roeck reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]); 1446ec3e5a16SGuenter Roeck reg = (reg & 0xf0) | val; 1447ec3e5a16SGuenter Roeck w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg); 1448ec3e5a16SGuenter Roeck } else { 14491ea6dd38SDavid Hubbard reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]); 145008c79950SRudolf Marek if (nr == 1) 145108c79950SRudolf Marek reg = (reg & 0x0f) | (val << 4); 145208c79950SRudolf Marek else 145308c79950SRudolf Marek reg = (reg & 0xf0) | val; 14541ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg); 1455ec3e5a16SGuenter Roeck } 1456ec3e5a16SGuenter Roeck data->tolerance[nr] = val; 145708c79950SRudolf Marek mutex_unlock(&data->update_lock); 145808c79950SRudolf Marek return count; 145908c79950SRudolf Marek } 146008c79950SRudolf Marek 146108c79950SRudolf Marek static struct sensor_device_attribute sda_pwm[] = { 146208c79950SRudolf Marek SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), 146308c79950SRudolf Marek SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), 146408c79950SRudolf Marek SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), 146508c79950SRudolf Marek SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3), 146608c79950SRudolf Marek }; 146708c79950SRudolf Marek 146808c79950SRudolf Marek static struct sensor_device_attribute sda_pwm_mode[] = { 146908c79950SRudolf Marek SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 147008c79950SRudolf Marek store_pwm_mode, 0), 147108c79950SRudolf Marek SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 147208c79950SRudolf Marek store_pwm_mode, 1), 147308c79950SRudolf Marek SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 147408c79950SRudolf Marek store_pwm_mode, 2), 147508c79950SRudolf Marek SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 147608c79950SRudolf Marek store_pwm_mode, 3), 147708c79950SRudolf Marek }; 147808c79950SRudolf Marek 147908c79950SRudolf Marek static struct sensor_device_attribute sda_pwm_enable[] = { 148008c79950SRudolf Marek SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 148108c79950SRudolf Marek store_pwm_enable, 0), 148208c79950SRudolf Marek SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 148308c79950SRudolf Marek store_pwm_enable, 1), 148408c79950SRudolf Marek SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 148508c79950SRudolf Marek store_pwm_enable, 2), 148608c79950SRudolf Marek SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 148708c79950SRudolf Marek store_pwm_enable, 3), 148808c79950SRudolf Marek }; 148908c79950SRudolf Marek 149008c79950SRudolf Marek static struct sensor_device_attribute sda_target_temp[] = { 149108c79950SRudolf Marek SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp, 149208c79950SRudolf Marek store_target_temp, 0), 149308c79950SRudolf Marek SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp, 149408c79950SRudolf Marek store_target_temp, 1), 149508c79950SRudolf Marek SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp, 149608c79950SRudolf Marek store_target_temp, 2), 149708c79950SRudolf Marek SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp, 149808c79950SRudolf Marek store_target_temp, 3), 149908c79950SRudolf Marek }; 150008c79950SRudolf Marek 150108c79950SRudolf Marek static struct sensor_device_attribute sda_tolerance[] = { 150208c79950SRudolf Marek SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance, 150308c79950SRudolf Marek store_tolerance, 0), 150408c79950SRudolf Marek SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance, 150508c79950SRudolf Marek store_tolerance, 1), 150608c79950SRudolf Marek SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance, 150708c79950SRudolf Marek store_tolerance, 2), 150808c79950SRudolf Marek SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance, 150908c79950SRudolf Marek store_tolerance, 3), 151008c79950SRudolf Marek }; 151108c79950SRudolf Marek 151208c79950SRudolf Marek /* Smart Fan registers */ 151308c79950SRudolf Marek 151408c79950SRudolf Marek #define fan_functions(reg, REG) \ 151508c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 151608c79950SRudolf Marek char *buf) \ 151708c79950SRudolf Marek { \ 151808c79950SRudolf Marek struct w83627ehf_data *data = w83627ehf_update_device(dev); \ 1519e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1520e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 152108c79950SRudolf Marek int nr = sensor_attr->index; \ 152208c79950SRudolf Marek return sprintf(buf, "%d\n", data->reg[nr]); \ 152308c79950SRudolf Marek } \ 152408c79950SRudolf Marek static ssize_t \ 152508c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \ 152608c79950SRudolf Marek const char *buf, size_t count) \ 152708c79950SRudolf Marek { \ 15281ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); \ 1529e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1530e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 153108c79950SRudolf Marek int nr = sensor_attr->index; \ 1532bce26c58SGuenter Roeck unsigned long val; \ 1533bce26c58SGuenter Roeck int err; \ 1534bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); \ 1535bce26c58SGuenter Roeck if (err < 0) \ 1536bce26c58SGuenter Roeck return err; \ 1537bce26c58SGuenter Roeck val = SENSORS_LIMIT(val, 1, 255); \ 153808c79950SRudolf Marek mutex_lock(&data->update_lock); \ 153908c79950SRudolf Marek data->reg[nr] = val; \ 1540da2e0255SGuenter Roeck w83627ehf_write_value(data, data->REG_##REG[nr], val); \ 154108c79950SRudolf Marek mutex_unlock(&data->update_lock); \ 154208c79950SRudolf Marek return count; \ 154308c79950SRudolf Marek } 154408c79950SRudolf Marek 154541e9a062SDaniel J Blueman fan_functions(fan_start_output, FAN_START_OUTPUT) 154641e9a062SDaniel J Blueman fan_functions(fan_stop_output, FAN_STOP_OUTPUT) 154741e9a062SDaniel J Blueman fan_functions(fan_max_output, FAN_MAX_OUTPUT) 154841e9a062SDaniel J Blueman fan_functions(fan_step_output, FAN_STEP_OUTPUT) 154908c79950SRudolf Marek 155008c79950SRudolf Marek #define fan_time_functions(reg, REG) \ 155108c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 155208c79950SRudolf Marek char *buf) \ 155308c79950SRudolf Marek { \ 155408c79950SRudolf Marek struct w83627ehf_data *data = w83627ehf_update_device(dev); \ 1555e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1556e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 155708c79950SRudolf Marek int nr = sensor_attr->index; \ 155808c79950SRudolf Marek return sprintf(buf, "%d\n", \ 1559e7e1ca6eSGuenter Roeck step_time_from_reg(data->reg[nr], \ 1560e7e1ca6eSGuenter Roeck data->pwm_mode[nr])); \ 156108c79950SRudolf Marek } \ 156208c79950SRudolf Marek \ 156308c79950SRudolf Marek static ssize_t \ 156408c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \ 156508c79950SRudolf Marek const char *buf, size_t count) \ 156608c79950SRudolf Marek { \ 15671ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); \ 1568e7e1ca6eSGuenter Roeck struct sensor_device_attribute *sensor_attr = \ 1569e7e1ca6eSGuenter Roeck to_sensor_dev_attr(attr); \ 157008c79950SRudolf Marek int nr = sensor_attr->index; \ 1571bce26c58SGuenter Roeck unsigned long val; \ 1572bce26c58SGuenter Roeck int err; \ 1573bce26c58SGuenter Roeck err = strict_strtoul(buf, 10, &val); \ 1574bce26c58SGuenter Roeck if (err < 0) \ 1575bce26c58SGuenter Roeck return err; \ 1576bce26c58SGuenter Roeck val = step_time_to_reg(val, data->pwm_mode[nr]); \ 157708c79950SRudolf Marek mutex_lock(&data->update_lock); \ 157808c79950SRudolf Marek data->reg[nr] = val; \ 15791ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \ 158008c79950SRudolf Marek mutex_unlock(&data->update_lock); \ 158108c79950SRudolf Marek return count; \ 158208c79950SRudolf Marek } \ 158308c79950SRudolf Marek 158408c79950SRudolf Marek fan_time_functions(fan_stop_time, FAN_STOP_TIME) 158508c79950SRudolf Marek 15861ea6dd38SDavid Hubbard static ssize_t show_name(struct device *dev, struct device_attribute *attr, 15871ea6dd38SDavid Hubbard char *buf) 15881ea6dd38SDavid Hubbard { 15891ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 15901ea6dd38SDavid Hubbard 15911ea6dd38SDavid Hubbard return sprintf(buf, "%s\n", data->name); 15921ea6dd38SDavid Hubbard } 15931ea6dd38SDavid Hubbard static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 159408c79950SRudolf Marek 159508c79950SRudolf Marek static struct sensor_device_attribute sda_sf3_arrays_fan4[] = { 159608c79950SRudolf Marek SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, 159708c79950SRudolf Marek store_fan_stop_time, 3), 159841e9a062SDaniel J Blueman SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, 159941e9a062SDaniel J Blueman store_fan_start_output, 3), 160041e9a062SDaniel J Blueman SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, 160141e9a062SDaniel J Blueman store_fan_stop_output, 3), 160241e9a062SDaniel J Blueman SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output, 160341e9a062SDaniel J Blueman store_fan_max_output, 3), 160441e9a062SDaniel J Blueman SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output, 160541e9a062SDaniel J Blueman store_fan_step_output, 3), 160608c79950SRudolf Marek }; 160708c79950SRudolf Marek 160808c79950SRudolf Marek static struct sensor_device_attribute sda_sf3_arrays[] = { 160908c79950SRudolf Marek SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, 161008c79950SRudolf Marek store_fan_stop_time, 0), 161108c79950SRudolf Marek SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, 161208c79950SRudolf Marek store_fan_stop_time, 1), 161308c79950SRudolf Marek SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, 161408c79950SRudolf Marek store_fan_stop_time, 2), 161541e9a062SDaniel J Blueman SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, 161641e9a062SDaniel J Blueman store_fan_start_output, 0), 161741e9a062SDaniel J Blueman SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, 161841e9a062SDaniel J Blueman store_fan_start_output, 1), 161941e9a062SDaniel J Blueman SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, 162041e9a062SDaniel J Blueman store_fan_start_output, 2), 162141e9a062SDaniel J Blueman SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, 162241e9a062SDaniel J Blueman store_fan_stop_output, 0), 162341e9a062SDaniel J Blueman SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, 162441e9a062SDaniel J Blueman store_fan_stop_output, 1), 162541e9a062SDaniel J Blueman SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, 162641e9a062SDaniel J Blueman store_fan_stop_output, 2), 1627da2e0255SGuenter Roeck }; 162841e9a062SDaniel J Blueman 1629da2e0255SGuenter Roeck 1630da2e0255SGuenter Roeck /* 1631da2e0255SGuenter Roeck * pwm1 and pwm3 don't support max and step settings on all chips. 1632da2e0255SGuenter Roeck * Need to check support while generating/removing attribute files. 1633da2e0255SGuenter Roeck */ 1634da2e0255SGuenter Roeck static struct sensor_device_attribute sda_sf3_max_step_arrays[] = { 1635da2e0255SGuenter Roeck SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output, 1636da2e0255SGuenter Roeck store_fan_max_output, 0), 1637da2e0255SGuenter Roeck SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output, 1638da2e0255SGuenter Roeck store_fan_step_output, 0), 163941e9a062SDaniel J Blueman SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output, 164041e9a062SDaniel J Blueman store_fan_max_output, 1), 164141e9a062SDaniel J Blueman SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output, 164241e9a062SDaniel J Blueman store_fan_step_output, 1), 1643da2e0255SGuenter Roeck SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output, 1644da2e0255SGuenter Roeck store_fan_max_output, 2), 1645da2e0255SGuenter Roeck SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output, 1646da2e0255SGuenter Roeck store_fan_step_output, 2), 164708c79950SRudolf Marek }; 164808c79950SRudolf Marek 1649fc18d6c0SJean Delvare static ssize_t 1650fc18d6c0SJean Delvare show_vid(struct device *dev, struct device_attribute *attr, char *buf) 1651fc18d6c0SJean Delvare { 1652fc18d6c0SJean Delvare struct w83627ehf_data *data = dev_get_drvdata(dev); 1653fc18d6c0SJean Delvare return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); 1654fc18d6c0SJean Delvare } 1655fc18d6c0SJean Delvare static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); 1656fc18d6c0SJean Delvare 165708e7e278SJean Delvare /* 16581ea6dd38SDavid Hubbard * Driver and device management 165908e7e278SJean Delvare */ 166008e7e278SJean Delvare 1661c18beb5bSDavid Hubbard static void w83627ehf_device_remove_files(struct device *dev) 1662c18beb5bSDavid Hubbard { 1663c18beb5bSDavid Hubbard /* some entries in the following arrays may not have been used in 1664c18beb5bSDavid Hubbard * device_create_file(), but device_remove_file() will ignore them */ 1665c18beb5bSDavid Hubbard int i; 16661ea6dd38SDavid Hubbard struct w83627ehf_data *data = dev_get_drvdata(dev); 1667c18beb5bSDavid Hubbard 1668c18beb5bSDavid Hubbard for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) 1669c18beb5bSDavid Hubbard device_remove_file(dev, &sda_sf3_arrays[i].dev_attr); 1670da2e0255SGuenter Roeck for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) { 1671da2e0255SGuenter Roeck struct sensor_device_attribute *attr = 1672da2e0255SGuenter Roeck &sda_sf3_max_step_arrays[i]; 1673ec3e5a16SGuenter Roeck if (data->REG_FAN_STEP_OUTPUT && 1674ec3e5a16SGuenter Roeck data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) 1675da2e0255SGuenter Roeck device_remove_file(dev, &attr->dev_attr); 1676da2e0255SGuenter Roeck } 1677c18beb5bSDavid Hubbard for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) 1678c18beb5bSDavid Hubbard device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); 16791ea6dd38SDavid Hubbard for (i = 0; i < data->in_num; i++) { 1680a157d06dSGong Jun if ((i == 6) && data->in6_skip) 1681a157d06dSGong Jun continue; 1682c18beb5bSDavid Hubbard device_remove_file(dev, &sda_in_input[i].dev_attr); 1683c18beb5bSDavid Hubbard device_remove_file(dev, &sda_in_alarm[i].dev_attr); 1684c18beb5bSDavid Hubbard device_remove_file(dev, &sda_in_min[i].dev_attr); 1685c18beb5bSDavid Hubbard device_remove_file(dev, &sda_in_max[i].dev_attr); 1686c18beb5bSDavid Hubbard } 1687c18beb5bSDavid Hubbard for (i = 0; i < 5; i++) { 1688c18beb5bSDavid Hubbard device_remove_file(dev, &sda_fan_input[i].dev_attr); 1689c18beb5bSDavid Hubbard device_remove_file(dev, &sda_fan_alarm[i].dev_attr); 1690c18beb5bSDavid Hubbard device_remove_file(dev, &sda_fan_div[i].dev_attr); 1691c18beb5bSDavid Hubbard device_remove_file(dev, &sda_fan_min[i].dev_attr); 1692c18beb5bSDavid Hubbard } 1693237c8d2fSGong Jun for (i = 0; i < data->pwm_num; i++) { 1694c18beb5bSDavid Hubbard device_remove_file(dev, &sda_pwm[i].dev_attr); 1695c18beb5bSDavid Hubbard device_remove_file(dev, &sda_pwm_mode[i].dev_attr); 1696c18beb5bSDavid Hubbard device_remove_file(dev, &sda_pwm_enable[i].dev_attr); 1697c18beb5bSDavid Hubbard device_remove_file(dev, &sda_target_temp[i].dev_attr); 1698c18beb5bSDavid Hubbard device_remove_file(dev, &sda_tolerance[i].dev_attr); 1699c18beb5bSDavid Hubbard } 1700d36cf32cSGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) { 1701d36cf32cSGuenter Roeck if (!(data->have_temp & (1 << i))) 1702a157d06dSGong Jun continue; 1703a157d06dSGong Jun device_remove_file(dev, &sda_temp_input[i].dev_attr); 1704d36cf32cSGuenter Roeck device_remove_file(dev, &sda_temp_label[i].dev_attr); 1705a157d06dSGong Jun device_remove_file(dev, &sda_temp_max[i].dev_attr); 1706a157d06dSGong Jun device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); 1707ec3e5a16SGuenter Roeck if (i > 2) 1708ec3e5a16SGuenter Roeck continue; 1709a157d06dSGong Jun device_remove_file(dev, &sda_temp_alarm[i].dev_attr); 1710a157d06dSGong Jun device_remove_file(dev, &sda_temp_type[i].dev_attr); 1711a157d06dSGong Jun } 17121ea6dd38SDavid Hubbard 17131ea6dd38SDavid Hubbard device_remove_file(dev, &dev_attr_name); 1714fc18d6c0SJean Delvare device_remove_file(dev, &dev_attr_cpu0_vid); 1715c18beb5bSDavid Hubbard } 1716c18beb5bSDavid Hubbard 17171ea6dd38SDavid Hubbard /* Get the monitoring functions started */ 1718*bf164c58SJean Delvare static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, 1719*bf164c58SJean Delvare enum kinds kind) 172008e7e278SJean Delvare { 172108e7e278SJean Delvare int i; 1722da667365SJean Delvare u8 tmp, diode; 172308e7e278SJean Delvare 172408e7e278SJean Delvare /* Start monitoring is needed */ 17251ea6dd38SDavid Hubbard tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG); 172608e7e278SJean Delvare if (!(tmp & 0x01)) 17271ea6dd38SDavid Hubbard w83627ehf_write_value(data, W83627EHF_REG_CONFIG, 172808e7e278SJean Delvare tmp | 0x01); 172908e7e278SJean Delvare 1730d36cf32cSGuenter Roeck /* Enable temperature sensors if needed */ 1731d36cf32cSGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) { 1732d36cf32cSGuenter Roeck if (!(data->have_temp & (1 << i))) 1733d36cf32cSGuenter Roeck continue; 1734ec3e5a16SGuenter Roeck if (!data->reg_temp_config[i]) 1735d36cf32cSGuenter Roeck continue; 17361ea6dd38SDavid Hubbard tmp = w83627ehf_read_value(data, 1737ec3e5a16SGuenter Roeck data->reg_temp_config[i]); 173808e7e278SJean Delvare if (tmp & 0x01) 17391ea6dd38SDavid Hubbard w83627ehf_write_value(data, 1740ec3e5a16SGuenter Roeck data->reg_temp_config[i], 174108e7e278SJean Delvare tmp & 0xfe); 174208e7e278SJean Delvare } 1743d3130f0eSJean Delvare 1744d3130f0eSJean Delvare /* Enable VBAT monitoring if needed */ 1745d3130f0eSJean Delvare tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT); 1746d3130f0eSJean Delvare if (!(tmp & 0x01)) 1747d3130f0eSJean Delvare w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01); 1748da667365SJean Delvare 1749da667365SJean Delvare /* Get thermal sensor types */ 1750*bf164c58SJean Delvare switch (kind) { 1751*bf164c58SJean Delvare case w83627ehf: 1752da667365SJean Delvare diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE); 1753*bf164c58SJean Delvare break; 1754*bf164c58SJean Delvare default: 1755*bf164c58SJean Delvare diode = 0x70; 1756*bf164c58SJean Delvare } 1757da667365SJean Delvare for (i = 0; i < 3; i++) { 1758da667365SJean Delvare if ((tmp & (0x02 << i))) 1759*bf164c58SJean Delvare data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3; 1760da667365SJean Delvare else 1761da667365SJean Delvare data->temp_type[i] = 4; /* thermistor */ 1762da667365SJean Delvare } 176308e7e278SJean Delvare } 176408e7e278SJean Delvare 1765ec3e5a16SGuenter Roeck static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, 1766ec3e5a16SGuenter Roeck int r1, int r2) 1767ec3e5a16SGuenter Roeck { 1768ec3e5a16SGuenter Roeck u16 tmp; 1769ec3e5a16SGuenter Roeck 1770ec3e5a16SGuenter Roeck tmp = data->temp_src[r1]; 1771ec3e5a16SGuenter Roeck data->temp_src[r1] = data->temp_src[r2]; 1772ec3e5a16SGuenter Roeck data->temp_src[r2] = tmp; 1773ec3e5a16SGuenter Roeck 1774ec3e5a16SGuenter Roeck tmp = data->reg_temp[r1]; 1775ec3e5a16SGuenter Roeck data->reg_temp[r1] = data->reg_temp[r2]; 1776ec3e5a16SGuenter Roeck data->reg_temp[r2] = tmp; 1777ec3e5a16SGuenter Roeck 1778ec3e5a16SGuenter Roeck tmp = data->reg_temp_over[r1]; 1779ec3e5a16SGuenter Roeck data->reg_temp_over[r1] = data->reg_temp_over[r2]; 1780ec3e5a16SGuenter Roeck data->reg_temp_over[r2] = tmp; 1781ec3e5a16SGuenter Roeck 1782ec3e5a16SGuenter Roeck tmp = data->reg_temp_hyst[r1]; 1783ec3e5a16SGuenter Roeck data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2]; 1784ec3e5a16SGuenter Roeck data->reg_temp_hyst[r2] = tmp; 1785ec3e5a16SGuenter Roeck 1786ec3e5a16SGuenter Roeck tmp = data->reg_temp_config[r1]; 1787ec3e5a16SGuenter Roeck data->reg_temp_config[r1] = data->reg_temp_config[r2]; 1788ec3e5a16SGuenter Roeck data->reg_temp_config[r2] = tmp; 1789ec3e5a16SGuenter Roeck } 1790ec3e5a16SGuenter Roeck 17911ea6dd38SDavid Hubbard static int __devinit w83627ehf_probe(struct platform_device *pdev) 179208e7e278SJean Delvare { 17931ea6dd38SDavid Hubbard struct device *dev = &pdev->dev; 17941ea6dd38SDavid Hubbard struct w83627ehf_sio_data *sio_data = dev->platform_data; 179508e7e278SJean Delvare struct w83627ehf_data *data; 17961ea6dd38SDavid Hubbard struct resource *res; 1797ec3e5a16SGuenter Roeck u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10; 179808e7e278SJean Delvare int i, err = 0; 179908e7e278SJean Delvare 18001ea6dd38SDavid Hubbard res = platform_get_resource(pdev, IORESOURCE_IO, 0); 18011ea6dd38SDavid Hubbard if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) { 180208e7e278SJean Delvare err = -EBUSY; 18031ea6dd38SDavid Hubbard dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", 18041ea6dd38SDavid Hubbard (unsigned long)res->start, 18051ea6dd38SDavid Hubbard (unsigned long)res->start + IOREGION_LENGTH - 1); 180608e7e278SJean Delvare goto exit; 180708e7e278SJean Delvare } 180808e7e278SJean Delvare 1809e7e1ca6eSGuenter Roeck data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL); 1810e7e1ca6eSGuenter Roeck if (!data) { 181108e7e278SJean Delvare err = -ENOMEM; 181208e7e278SJean Delvare goto exit_release; 181308e7e278SJean Delvare } 181408e7e278SJean Delvare 18151ea6dd38SDavid Hubbard data->addr = res->start; 18169a61bf63SIngo Molnar mutex_init(&data->lock); 18179a61bf63SIngo Molnar mutex_init(&data->update_lock); 18181ea6dd38SDavid Hubbard data->name = w83627ehf_device_names[sio_data->kind]; 18191ea6dd38SDavid Hubbard platform_set_drvdata(pdev, data); 182008e7e278SJean Delvare 1821237c8d2fSGong Jun /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ 1822237c8d2fSGong Jun data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; 1823ec3e5a16SGuenter Roeck /* 667HG, NCT6775F, and NCT6776F have 3 pwms */ 1824c39aedafSGuenter Roeck data->pwm_num = (sio_data->kind == w83667hg 1825ec3e5a16SGuenter Roeck || sio_data->kind == w83667hg_b 1826ec3e5a16SGuenter Roeck || sio_data->kind == nct6775 1827ec3e5a16SGuenter Roeck || sio_data->kind == nct6776) ? 3 : 4; 182808e7e278SJean Delvare 1829d36cf32cSGuenter Roeck data->have_temp = 0x07; 1830a157d06dSGong Jun /* Check temp3 configuration bit for 667HG */ 1831d36cf32cSGuenter Roeck if (sio_data->kind == w83667hg) { 1832d36cf32cSGuenter Roeck u8 reg; 1833d36cf32cSGuenter Roeck 1834d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]); 1835d36cf32cSGuenter Roeck if (reg & 0x01) 1836d36cf32cSGuenter Roeck data->have_temp &= ~(1 << 2); 1837d36cf32cSGuenter Roeck else 1838ec3e5a16SGuenter Roeck data->in6_skip = 1; /* either temp3 or in6 */ 1839ec3e5a16SGuenter Roeck } 1840ec3e5a16SGuenter Roeck 1841ec3e5a16SGuenter Roeck /* Deal with temperature register setup first. */ 1842ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { 1843ec3e5a16SGuenter Roeck int mask = 0; 1844ec3e5a16SGuenter Roeck 1845ec3e5a16SGuenter Roeck /* 1846ec3e5a16SGuenter Roeck * Display temperature sensor output only if it monitors 1847ec3e5a16SGuenter Roeck * a source other than one already reported. Always display 1848ec3e5a16SGuenter Roeck * first three temperature registers, though. 1849ec3e5a16SGuenter Roeck */ 1850ec3e5a16SGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) { 1851ec3e5a16SGuenter Roeck u8 src; 1852ec3e5a16SGuenter Roeck 1853ec3e5a16SGuenter Roeck data->reg_temp[i] = NCT6775_REG_TEMP[i]; 1854ec3e5a16SGuenter Roeck data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i]; 1855ec3e5a16SGuenter Roeck data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i]; 1856ec3e5a16SGuenter Roeck data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i]; 1857ec3e5a16SGuenter Roeck 1858ec3e5a16SGuenter Roeck src = w83627ehf_read_value(data, 1859ec3e5a16SGuenter Roeck NCT6775_REG_TEMP_SOURCE[i]); 1860ec3e5a16SGuenter Roeck src &= 0x1f; 1861ec3e5a16SGuenter Roeck if (src && !(mask & (1 << src))) { 1862ec3e5a16SGuenter Roeck data->have_temp |= 1 << i; 1863ec3e5a16SGuenter Roeck mask |= 1 << src; 1864ec3e5a16SGuenter Roeck } 1865ec3e5a16SGuenter Roeck 1866ec3e5a16SGuenter Roeck data->temp_src[i] = src; 1867ec3e5a16SGuenter Roeck 1868ec3e5a16SGuenter Roeck /* 1869ec3e5a16SGuenter Roeck * Now do some register swapping if index 0..2 don't 1870ec3e5a16SGuenter Roeck * point to SYSTIN(1), CPUIN(2), and AUXIN(3). 1871ec3e5a16SGuenter Roeck * Idea is to have the first three attributes 1872ec3e5a16SGuenter Roeck * report SYSTIN, CPUIN, and AUXIN if possible 1873ec3e5a16SGuenter Roeck * without overriding the basic system configuration. 1874ec3e5a16SGuenter Roeck */ 1875ec3e5a16SGuenter Roeck if (i > 0 && data->temp_src[0] != 1 1876ec3e5a16SGuenter Roeck && data->temp_src[i] == 1) 1877ec3e5a16SGuenter Roeck w82627ehf_swap_tempreg(data, 0, i); 1878ec3e5a16SGuenter Roeck if (i > 1 && data->temp_src[1] != 2 1879ec3e5a16SGuenter Roeck && data->temp_src[i] == 2) 1880ec3e5a16SGuenter Roeck w82627ehf_swap_tempreg(data, 1, i); 1881ec3e5a16SGuenter Roeck if (i > 2 && data->temp_src[2] != 3 1882ec3e5a16SGuenter Roeck && data->temp_src[i] == 3) 1883ec3e5a16SGuenter Roeck w82627ehf_swap_tempreg(data, 2, i); 1884ec3e5a16SGuenter Roeck } 1885ec3e5a16SGuenter Roeck if (sio_data->kind == nct6776) { 1886ec3e5a16SGuenter Roeck /* 1887ec3e5a16SGuenter Roeck * On NCT6776, AUXTIN and VIN3 pins are shared. 1888ec3e5a16SGuenter Roeck * Only way to detect it is to check if AUXTIN is used 1889ec3e5a16SGuenter Roeck * as a temperature source, and if that source is 1890ec3e5a16SGuenter Roeck * enabled. 1891ec3e5a16SGuenter Roeck * 1892ec3e5a16SGuenter Roeck * If that is the case, disable in6, which reports VIN3. 1893ec3e5a16SGuenter Roeck * Otherwise disable temp3. 1894ec3e5a16SGuenter Roeck */ 1895ec3e5a16SGuenter Roeck if (data->temp_src[2] == 3) { 1896ec3e5a16SGuenter Roeck u8 reg; 1897ec3e5a16SGuenter Roeck 1898ec3e5a16SGuenter Roeck if (data->reg_temp_config[2]) 1899ec3e5a16SGuenter Roeck reg = w83627ehf_read_value(data, 1900ec3e5a16SGuenter Roeck data->reg_temp_config[2]); 1901ec3e5a16SGuenter Roeck else 1902ec3e5a16SGuenter Roeck reg = 0; /* Assume AUXTIN is used */ 1903ec3e5a16SGuenter Roeck 1904ec3e5a16SGuenter Roeck if (reg & 0x01) 1905ec3e5a16SGuenter Roeck data->have_temp &= ~(1 << 2); 1906ec3e5a16SGuenter Roeck else 1907ec3e5a16SGuenter Roeck data->in6_skip = 1; 1908ec3e5a16SGuenter Roeck } 1909ec3e5a16SGuenter Roeck data->temp_label = nct6776_temp_label; 191002309ad2SGuenter Roeck } else { 191102309ad2SGuenter Roeck data->temp_label = nct6775_temp_label; 191202309ad2SGuenter Roeck } 1913d36cf32cSGuenter Roeck } else if (sio_data->kind == w83667hg_b) { 1914d36cf32cSGuenter Roeck u8 reg; 1915d36cf32cSGuenter Roeck 1916ec3e5a16SGuenter Roeck /* 1917ec3e5a16SGuenter Roeck * Temperature sources are selected with bank 0, registers 0x49 1918ec3e5a16SGuenter Roeck * and 0x4a. 1919ec3e5a16SGuenter Roeck */ 1920ec3e5a16SGuenter Roeck for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) { 1921ec3e5a16SGuenter Roeck data->reg_temp[i] = W83627EHF_REG_TEMP[i]; 1922ec3e5a16SGuenter Roeck data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; 1923ec3e5a16SGuenter Roeck data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; 1924ec3e5a16SGuenter Roeck data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; 1925ec3e5a16SGuenter Roeck } 1926d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, 0x4a); 1927d36cf32cSGuenter Roeck data->temp_src[0] = reg >> 5; 1928d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, 0x49); 1929d36cf32cSGuenter Roeck data->temp_src[1] = reg & 0x07; 1930d36cf32cSGuenter Roeck data->temp_src[2] = (reg >> 4) & 0x07; 1931d36cf32cSGuenter Roeck 1932d36cf32cSGuenter Roeck /* 1933d36cf32cSGuenter Roeck * W83667HG-B has another temperature register at 0x7e. 1934d36cf32cSGuenter Roeck * The temperature source is selected with register 0x7d. 1935d36cf32cSGuenter Roeck * Support it if the source differs from already reported 1936d36cf32cSGuenter Roeck * sources. 1937d36cf32cSGuenter Roeck */ 1938d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, 0x7d); 1939d36cf32cSGuenter Roeck reg &= 0x07; 1940d36cf32cSGuenter Roeck if (reg != data->temp_src[0] && reg != data->temp_src[1] 1941d36cf32cSGuenter Roeck && reg != data->temp_src[2]) { 1942d36cf32cSGuenter Roeck data->temp_src[3] = reg; 1943d36cf32cSGuenter Roeck data->have_temp |= 1 << 3; 1944d36cf32cSGuenter Roeck } 1945d36cf32cSGuenter Roeck 1946d36cf32cSGuenter Roeck /* 1947d36cf32cSGuenter Roeck * Chip supports either AUXTIN or VIN3. Try to find out which 1948d36cf32cSGuenter Roeck * one. 1949d36cf32cSGuenter Roeck */ 1950d36cf32cSGuenter Roeck reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]); 1951d36cf32cSGuenter Roeck if (data->temp_src[2] == 2 && (reg & 0x01)) 1952d36cf32cSGuenter Roeck data->have_temp &= ~(1 << 2); 1953d36cf32cSGuenter Roeck 1954d36cf32cSGuenter Roeck if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2))) 1955d36cf32cSGuenter Roeck || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3)))) 1956d36cf32cSGuenter Roeck data->in6_skip = 1; 1957d36cf32cSGuenter Roeck 1958d36cf32cSGuenter Roeck data->temp_label = w83667hg_b_temp_label; 1959ec3e5a16SGuenter Roeck } else { 1960ec3e5a16SGuenter Roeck /* Temperature sources are fixed */ 1961ec3e5a16SGuenter Roeck for (i = 0; i < 3; i++) { 1962ec3e5a16SGuenter Roeck data->reg_temp[i] = W83627EHF_REG_TEMP[i]; 1963ec3e5a16SGuenter Roeck data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; 1964ec3e5a16SGuenter Roeck data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; 1965ec3e5a16SGuenter Roeck data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; 1966ec3e5a16SGuenter Roeck } 1967a157d06dSGong Jun } 1968a157d06dSGong Jun 1969ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775) { 197026bc440eSGuenter Roeck data->has_fan_div = true; 197126bc440eSGuenter Roeck data->fan_from_reg = fan_from_reg16; 197226bc440eSGuenter Roeck data->fan_from_reg_min = fan_from_reg8; 1973ec3e5a16SGuenter Roeck data->REG_PWM = NCT6775_REG_PWM; 1974ec3e5a16SGuenter Roeck data->REG_TARGET = NCT6775_REG_TARGET; 197526bc440eSGuenter Roeck data->REG_FAN = NCT6775_REG_FAN; 1976ec3e5a16SGuenter Roeck data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; 1977ec3e5a16SGuenter Roeck data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT; 1978ec3e5a16SGuenter Roeck data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT; 1979ec3e5a16SGuenter Roeck data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME; 1980ec3e5a16SGuenter Roeck data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT; 1981ec3e5a16SGuenter Roeck data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT; 1982ec3e5a16SGuenter Roeck } else if (sio_data->kind == nct6776) { 198326bc440eSGuenter Roeck data->has_fan_div = false; 198426bc440eSGuenter Roeck data->fan_from_reg = fan_from_reg13; 198526bc440eSGuenter Roeck data->fan_from_reg_min = fan_from_reg13; 1986ec3e5a16SGuenter Roeck data->REG_PWM = NCT6775_REG_PWM; 1987ec3e5a16SGuenter Roeck data->REG_TARGET = NCT6775_REG_TARGET; 198826bc440eSGuenter Roeck data->REG_FAN = NCT6775_REG_FAN; 1989ec3e5a16SGuenter Roeck data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; 1990ec3e5a16SGuenter Roeck data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT; 1991ec3e5a16SGuenter Roeck data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT; 1992ec3e5a16SGuenter Roeck data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME; 1993ec3e5a16SGuenter Roeck } else if (sio_data->kind == w83667hg_b) { 199426bc440eSGuenter Roeck data->has_fan_div = true; 199526bc440eSGuenter Roeck data->fan_from_reg = fan_from_reg8; 199626bc440eSGuenter Roeck data->fan_from_reg_min = fan_from_reg8; 1997279af1a9SGuenter Roeck data->REG_PWM = W83627EHF_REG_PWM; 1998279af1a9SGuenter Roeck data->REG_TARGET = W83627EHF_REG_TARGET; 1999279af1a9SGuenter Roeck data->REG_FAN = W83627EHF_REG_FAN; 2000279af1a9SGuenter Roeck data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; 2001da2e0255SGuenter Roeck data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; 2002da2e0255SGuenter Roeck data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT; 2003279af1a9SGuenter Roeck data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME; 2004c39aedafSGuenter Roeck data->REG_FAN_MAX_OUTPUT = 2005c39aedafSGuenter Roeck W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B; 2006c39aedafSGuenter Roeck data->REG_FAN_STEP_OUTPUT = 2007c39aedafSGuenter Roeck W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B; 2008c39aedafSGuenter Roeck } else { 200926bc440eSGuenter Roeck data->has_fan_div = true; 201026bc440eSGuenter Roeck data->fan_from_reg = fan_from_reg8; 201126bc440eSGuenter Roeck data->fan_from_reg_min = fan_from_reg8; 2012ec3e5a16SGuenter Roeck data->REG_PWM = W83627EHF_REG_PWM; 2013ec3e5a16SGuenter Roeck data->REG_TARGET = W83627EHF_REG_TARGET; 2014ec3e5a16SGuenter Roeck data->REG_FAN = W83627EHF_REG_FAN; 2015ec3e5a16SGuenter Roeck data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN; 2016ec3e5a16SGuenter Roeck data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; 2017ec3e5a16SGuenter Roeck data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT; 2018ec3e5a16SGuenter Roeck data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME; 2019c39aedafSGuenter Roeck data->REG_FAN_MAX_OUTPUT = 2020c39aedafSGuenter Roeck W83627EHF_REG_FAN_MAX_OUTPUT_COMMON; 2021c39aedafSGuenter Roeck data->REG_FAN_STEP_OUTPUT = 2022c39aedafSGuenter Roeck W83627EHF_REG_FAN_STEP_OUTPUT_COMMON; 2023c39aedafSGuenter Roeck } 2024da2e0255SGuenter Roeck 202508e7e278SJean Delvare /* Initialize the chip */ 2026*bf164c58SJean Delvare w83627ehf_init_device(data, sio_data->kind); 202708e7e278SJean Delvare 2028fc18d6c0SJean Delvare data->vrm = vid_which_vrm(); 2029fc18d6c0SJean Delvare superio_enter(sio_data->sioreg); 203058e6e781SJean Delvare /* Read VID value */ 2031ec3e5a16SGuenter Roeck if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b || 2032ec3e5a16SGuenter Roeck sio_data->kind == nct6775 || sio_data->kind == nct6776) { 2033237c8d2fSGong Jun /* W83667HG has different pins for VID input and output, so 2034237c8d2fSGong Jun we can get the VID input values directly at logical device D 2035237c8d2fSGong Jun 0xe3. */ 2036237c8d2fSGong Jun superio_select(sio_data->sioreg, W83667HG_LD_VID); 2037237c8d2fSGong Jun data->vid = superio_inb(sio_data->sioreg, 0xe3); 2038237c8d2fSGong Jun err = device_create_file(dev, &dev_attr_cpu0_vid); 2039237c8d2fSGong Jun if (err) 2040237c8d2fSGong Jun goto exit_release; 2041237c8d2fSGong Jun } else { 204258e6e781SJean Delvare superio_select(sio_data->sioreg, W83627EHF_LD_HWM); 204358e6e781SJean Delvare if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { 2044237c8d2fSGong Jun /* Set VID input sensibility if needed. In theory the 2045237c8d2fSGong Jun BIOS should have set it, but in practice it's not 2046237c8d2fSGong Jun always the case. We only do it for the W83627EHF/EHG 2047237c8d2fSGong Jun because the W83627DHG is more complex in this 2048237c8d2fSGong Jun respect. */ 204958e6e781SJean Delvare if (sio_data->kind == w83627ehf) { 205058e6e781SJean Delvare en_vrm10 = superio_inb(sio_data->sioreg, 205158e6e781SJean Delvare SIO_REG_EN_VRM10); 205258e6e781SJean Delvare if ((en_vrm10 & 0x08) && data->vrm == 90) { 2053237c8d2fSGong Jun dev_warn(dev, "Setting VID input " 2054237c8d2fSGong Jun "voltage to TTL\n"); 2055237c8d2fSGong Jun superio_outb(sio_data->sioreg, 2056237c8d2fSGong Jun SIO_REG_EN_VRM10, 2057fc18d6c0SJean Delvare en_vrm10 & ~0x08); 2058237c8d2fSGong Jun } else if (!(en_vrm10 & 0x08) 2059237c8d2fSGong Jun && data->vrm == 100) { 2060237c8d2fSGong Jun dev_warn(dev, "Setting VID input " 2061237c8d2fSGong Jun "voltage to VRM10\n"); 2062237c8d2fSGong Jun superio_outb(sio_data->sioreg, 2063237c8d2fSGong Jun SIO_REG_EN_VRM10, 2064fc18d6c0SJean Delvare en_vrm10 | 0x08); 2065fc18d6c0SJean Delvare } 206658e6e781SJean Delvare } 206758e6e781SJean Delvare 2068237c8d2fSGong Jun data->vid = superio_inb(sio_data->sioreg, 2069237c8d2fSGong Jun SIO_REG_VID_DATA); 2070cbe311f2SJean Delvare if (sio_data->kind == w83627ehf) /* 6 VID pins only */ 2071cbe311f2SJean Delvare data->vid &= 0x3f; 2072cbe311f2SJean Delvare 2073cbe311f2SJean Delvare err = device_create_file(dev, &dev_attr_cpu0_vid); 2074cbe311f2SJean Delvare if (err) 2075cbe311f2SJean Delvare goto exit_release; 207658e6e781SJean Delvare } else { 2077fc18d6c0SJean Delvare dev_info(dev, "VID pins in output mode, CPU VID not " 2078fc18d6c0SJean Delvare "available\n"); 2079fc18d6c0SJean Delvare } 2080237c8d2fSGong Jun } 2081fc18d6c0SJean Delvare 208208c79950SRudolf Marek /* fan4 and fan5 share some pins with the GPIO and serial flash */ 2083ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775) { 2084ec3e5a16SGuenter Roeck /* On NCT6775, fan4 shares pins with the fdc interface */ 2085ec3e5a16SGuenter Roeck fan3pin = 1; 2086ec3e5a16SGuenter Roeck fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); 2087ec3e5a16SGuenter Roeck fan4min = 0; 2088ec3e5a16SGuenter Roeck fan5pin = 0; 2089ec3e5a16SGuenter Roeck } else if (sio_data->kind == nct6776) { 2090ec3e5a16SGuenter Roeck fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); 2091ec3e5a16SGuenter Roeck fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); 2092ec3e5a16SGuenter Roeck fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); 2093ec3e5a16SGuenter Roeck fan4min = fan4pin; 2094ec3e5a16SGuenter Roeck } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { 2095ec3e5a16SGuenter Roeck fan3pin = 1; 2096237c8d2fSGong Jun fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; 2097ec3e5a16SGuenter Roeck fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; 2098ec3e5a16SGuenter Roeck fan4min = fan4pin; 2099237c8d2fSGong Jun } else { 2100ec3e5a16SGuenter Roeck fan3pin = 1; 2101237c8d2fSGong Jun fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); 2102ec3e5a16SGuenter Roeck fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); 2103ec3e5a16SGuenter Roeck fan4min = fan4pin; 2104237c8d2fSGong Jun } 2105d42e869aSIan Dobson 2106d42e869aSIan Dobson if (fan_debounce && 2107d42e869aSIan Dobson (sio_data->kind == nct6775 || sio_data->kind == nct6776)) { 2108d42e869aSIan Dobson u8 tmp; 2109d42e869aSIan Dobson 2110d42e869aSIan Dobson superio_select(sio_data->sioreg, W83627EHF_LD_HWM); 2111d42e869aSIan Dobson tmp = superio_inb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE); 2112d42e869aSIan Dobson if (sio_data->kind == nct6776) 2113d42e869aSIan Dobson superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE, 2114d42e869aSIan Dobson 0x3e | tmp); 2115d42e869aSIan Dobson else 2116d42e869aSIan Dobson superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE, 2117d42e869aSIan Dobson 0x1e | tmp); 2118d42e869aSIan Dobson pr_info("Enabled fan debounce for chip %s\n", data->name); 2119d42e869aSIan Dobson } 2120d42e869aSIan Dobson 21211ea6dd38SDavid Hubbard superio_exit(sio_data->sioreg); 212208c79950SRudolf Marek 212308e7e278SJean Delvare /* It looks like fan4 and fan5 pins can be alternatively used 212414992c7eSRudolf Marek as fan on/off switches, but fan5 control is write only :/ 212514992c7eSRudolf Marek We assume that if the serial interface is disabled, designers 212614992c7eSRudolf Marek connected fan5 as input unless they are emitting log 1, which 212714992c7eSRudolf Marek is not the default. */ 212808c79950SRudolf Marek 2129ec3e5a16SGuenter Roeck data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */ 2130ec3e5a16SGuenter Roeck 2131ec3e5a16SGuenter Roeck data->has_fan |= (fan3pin << 2); 2132ec3e5a16SGuenter Roeck data->has_fan_min |= (fan3pin << 2); 2133ec3e5a16SGuenter Roeck 2134ec3e5a16SGuenter Roeck /* 2135ec3e5a16SGuenter Roeck * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register 2136ec3e5a16SGuenter Roeck */ 2137ec3e5a16SGuenter Roeck if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { 2138ec3e5a16SGuenter Roeck data->has_fan |= (fan4pin << 3) | (fan5pin << 4); 2139ec3e5a16SGuenter Roeck data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); 2140ec3e5a16SGuenter Roeck } else { 21411ea6dd38SDavid Hubbard i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); 2142ec3e5a16SGuenter Roeck if ((i & (1 << 2)) && fan4pin) { 214308e7e278SJean Delvare data->has_fan |= (1 << 3); 2144ec3e5a16SGuenter Roeck data->has_fan_min |= (1 << 3); 2145ec3e5a16SGuenter Roeck } 2146ec3e5a16SGuenter Roeck if (!(i & (1 << 1)) && fan5pin) { 214708e7e278SJean Delvare data->has_fan |= (1 << 4); 2148ec3e5a16SGuenter Roeck data->has_fan_min |= (1 << 4); 2149ec3e5a16SGuenter Roeck } 2150ec3e5a16SGuenter Roeck } 215108e7e278SJean Delvare 2152ea7be66cSMark M. Hoffman /* Read fan clock dividers immediately */ 2153ec3e5a16SGuenter Roeck w83627ehf_update_fan_div_common(dev, data); 2154ec3e5a16SGuenter Roeck 2155ec3e5a16SGuenter Roeck /* Read pwm data to save original values */ 2156ec3e5a16SGuenter Roeck w83627ehf_update_pwm_common(dev, data); 2157ec3e5a16SGuenter Roeck for (i = 0; i < data->pwm_num; i++) 2158ec3e5a16SGuenter Roeck data->pwm_enable_orig[i] = data->pwm_enable[i]; 2159ea7be66cSMark M. Hoffman 2160b84bb518SGuenter Roeck /* Read pwm data to save original values */ 2161b84bb518SGuenter Roeck w83627ehf_update_pwm_common(dev, data); 2162b84bb518SGuenter Roeck for (i = 0; i < data->pwm_num; i++) 2163b84bb518SGuenter Roeck data->pwm_enable_orig[i] = data->pwm_enable[i]; 2164b84bb518SGuenter Roeck 216508e7e278SJean Delvare /* Register sysfs hooks */ 2166e7e1ca6eSGuenter Roeck for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) { 2167e7e1ca6eSGuenter Roeck err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr); 2168e7e1ca6eSGuenter Roeck if (err) 2169c18beb5bSDavid Hubbard goto exit_remove; 2170e7e1ca6eSGuenter Roeck } 217108c79950SRudolf Marek 2172da2e0255SGuenter Roeck for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) { 2173da2e0255SGuenter Roeck struct sensor_device_attribute *attr = 2174da2e0255SGuenter Roeck &sda_sf3_max_step_arrays[i]; 2175ec3e5a16SGuenter Roeck if (data->REG_FAN_STEP_OUTPUT && 2176ec3e5a16SGuenter Roeck data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) { 2177da2e0255SGuenter Roeck err = device_create_file(dev, &attr->dev_attr); 2178da2e0255SGuenter Roeck if (err) 2179da2e0255SGuenter Roeck goto exit_remove; 2180da2e0255SGuenter Roeck } 2181da2e0255SGuenter Roeck } 218208c79950SRudolf Marek /* if fan4 is enabled create the sf3 files for it */ 2183237c8d2fSGong Jun if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4) 2184c18beb5bSDavid Hubbard for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { 2185e7e1ca6eSGuenter Roeck err = device_create_file(dev, 2186e7e1ca6eSGuenter Roeck &sda_sf3_arrays_fan4[i].dev_attr); 2187e7e1ca6eSGuenter Roeck if (err) 2188c18beb5bSDavid Hubbard goto exit_remove; 2189c18beb5bSDavid Hubbard } 219008c79950SRudolf Marek 2191a157d06dSGong Jun for (i = 0; i < data->in_num; i++) { 2192a157d06dSGong Jun if ((i == 6) && data->in6_skip) 2193a157d06dSGong Jun continue; 2194c18beb5bSDavid Hubbard if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) 2195c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2196c18beb5bSDavid Hubbard &sda_in_alarm[i].dev_attr)) 2197c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2198c18beb5bSDavid Hubbard &sda_in_min[i].dev_attr)) 2199c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2200c18beb5bSDavid Hubbard &sda_in_max[i].dev_attr))) 2201c18beb5bSDavid Hubbard goto exit_remove; 2202a157d06dSGong Jun } 2203cf0676feSRudolf Marek 2204412fec82SYuan Mu for (i = 0; i < 5; i++) { 220508c79950SRudolf Marek if (data->has_fan & (1 << i)) { 2206c18beb5bSDavid Hubbard if ((err = device_create_file(dev, 2207c18beb5bSDavid Hubbard &sda_fan_input[i].dev_attr)) 2208c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2209ec3e5a16SGuenter Roeck &sda_fan_alarm[i].dev_attr))) 2210c18beb5bSDavid Hubbard goto exit_remove; 2211ec3e5a16SGuenter Roeck if (sio_data->kind != nct6776) { 2212ec3e5a16SGuenter Roeck err = device_create_file(dev, 2213ec3e5a16SGuenter Roeck &sda_fan_div[i].dev_attr); 2214ec3e5a16SGuenter Roeck if (err) 2215ec3e5a16SGuenter Roeck goto exit_remove; 2216ec3e5a16SGuenter Roeck } 2217ec3e5a16SGuenter Roeck if (data->has_fan_min & (1 << i)) { 2218ec3e5a16SGuenter Roeck err = device_create_file(dev, 2219ec3e5a16SGuenter Roeck &sda_fan_min[i].dev_attr); 2220ec3e5a16SGuenter Roeck if (err) 2221ec3e5a16SGuenter Roeck goto exit_remove; 2222ec3e5a16SGuenter Roeck } 2223237c8d2fSGong Jun if (i < data->pwm_num && 2224c18beb5bSDavid Hubbard ((err = device_create_file(dev, 2225c18beb5bSDavid Hubbard &sda_pwm[i].dev_attr)) 2226c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2227c18beb5bSDavid Hubbard &sda_pwm_mode[i].dev_attr)) 2228c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2229c18beb5bSDavid Hubbard &sda_pwm_enable[i].dev_attr)) 2230c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2231c18beb5bSDavid Hubbard &sda_target_temp[i].dev_attr)) 2232c18beb5bSDavid Hubbard || (err = device_create_file(dev, 2233c18beb5bSDavid Hubbard &sda_tolerance[i].dev_attr)))) 2234c18beb5bSDavid Hubbard goto exit_remove; 223508e7e278SJean Delvare } 223608c79950SRudolf Marek } 223708c79950SRudolf Marek 2238d36cf32cSGuenter Roeck for (i = 0; i < NUM_REG_TEMP; i++) { 2239d36cf32cSGuenter Roeck if (!(data->have_temp & (1 << i))) 2240a157d06dSGong Jun continue; 2241d36cf32cSGuenter Roeck err = device_create_file(dev, &sda_temp_input[i].dev_attr); 2242d36cf32cSGuenter Roeck if (err) 2243d36cf32cSGuenter Roeck goto exit_remove; 2244d36cf32cSGuenter Roeck if (data->temp_label) { 2245d36cf32cSGuenter Roeck err = device_create_file(dev, 2246d36cf32cSGuenter Roeck &sda_temp_label[i].dev_attr); 2247d36cf32cSGuenter Roeck if (err) 2248d36cf32cSGuenter Roeck goto exit_remove; 2249d36cf32cSGuenter Roeck } 2250ec3e5a16SGuenter Roeck if (data->reg_temp_over[i]) { 2251ec3e5a16SGuenter Roeck err = device_create_file(dev, 2252ec3e5a16SGuenter Roeck &sda_temp_max[i].dev_attr); 2253ec3e5a16SGuenter Roeck if (err) 2254ec3e5a16SGuenter Roeck goto exit_remove; 2255ec3e5a16SGuenter Roeck } 2256ec3e5a16SGuenter Roeck if (data->reg_temp_hyst[i]) { 2257ec3e5a16SGuenter Roeck err = device_create_file(dev, 2258ec3e5a16SGuenter Roeck &sda_temp_max_hyst[i].dev_attr); 2259ec3e5a16SGuenter Roeck if (err) 2260ec3e5a16SGuenter Roeck goto exit_remove; 2261ec3e5a16SGuenter Roeck } 2262d36cf32cSGuenter Roeck if (i > 2) 2263ec3e5a16SGuenter Roeck continue; 2264ec3e5a16SGuenter Roeck if ((err = device_create_file(dev, 2265a157d06dSGong Jun &sda_temp_alarm[i].dev_attr)) 2266a157d06dSGong Jun || (err = device_create_file(dev, 2267a157d06dSGong Jun &sda_temp_type[i].dev_attr))) 2268c18beb5bSDavid Hubbard goto exit_remove; 2269a157d06dSGong Jun } 2270c18beb5bSDavid Hubbard 22711ea6dd38SDavid Hubbard err = device_create_file(dev, &dev_attr_name); 22721ea6dd38SDavid Hubbard if (err) 22731ea6dd38SDavid Hubbard goto exit_remove; 22741ea6dd38SDavid Hubbard 22751beeffe4STony Jones data->hwmon_dev = hwmon_device_register(dev); 22761beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) { 22771beeffe4STony Jones err = PTR_ERR(data->hwmon_dev); 2278c18beb5bSDavid Hubbard goto exit_remove; 2279c18beb5bSDavid Hubbard } 228008e7e278SJean Delvare 228108e7e278SJean Delvare return 0; 228208e7e278SJean Delvare 2283c18beb5bSDavid Hubbard exit_remove: 2284c18beb5bSDavid Hubbard w83627ehf_device_remove_files(dev); 228508e7e278SJean Delvare kfree(data); 22861ea6dd38SDavid Hubbard platform_set_drvdata(pdev, NULL); 228708e7e278SJean Delvare exit_release: 22881ea6dd38SDavid Hubbard release_region(res->start, IOREGION_LENGTH); 228908e7e278SJean Delvare exit: 229008e7e278SJean Delvare return err; 229108e7e278SJean Delvare } 229208e7e278SJean Delvare 22931ea6dd38SDavid Hubbard static int __devexit w83627ehf_remove(struct platform_device *pdev) 229408e7e278SJean Delvare { 22951ea6dd38SDavid Hubbard struct w83627ehf_data *data = platform_get_drvdata(pdev); 229608e7e278SJean Delvare 22971beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev); 22981ea6dd38SDavid Hubbard w83627ehf_device_remove_files(&pdev->dev); 22991ea6dd38SDavid Hubbard release_region(data->addr, IOREGION_LENGTH); 23001ea6dd38SDavid Hubbard platform_set_drvdata(pdev, NULL); 2301943b0830SMark M. Hoffman kfree(data); 230208e7e278SJean Delvare 230308e7e278SJean Delvare return 0; 230408e7e278SJean Delvare } 230508e7e278SJean Delvare 23061ea6dd38SDavid Hubbard static struct platform_driver w83627ehf_driver = { 2307cdaf7934SLaurent Riffard .driver = { 230887218842SJean Delvare .owner = THIS_MODULE, 23091ea6dd38SDavid Hubbard .name = DRVNAME, 2310cdaf7934SLaurent Riffard }, 23111ea6dd38SDavid Hubbard .probe = w83627ehf_probe, 23121ea6dd38SDavid Hubbard .remove = __devexit_p(w83627ehf_remove), 231308e7e278SJean Delvare }; 231408e7e278SJean Delvare 23151ea6dd38SDavid Hubbard /* w83627ehf_find() looks for a '627 in the Super-I/O config space */ 23161ea6dd38SDavid Hubbard static int __init w83627ehf_find(int sioaddr, unsigned short *addr, 23171ea6dd38SDavid Hubbard struct w83627ehf_sio_data *sio_data) 231808e7e278SJean Delvare { 23191ea6dd38SDavid Hubbard static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; 23201ea6dd38SDavid Hubbard static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; 23211ea6dd38SDavid Hubbard static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; 2322c1e48dceSJean Delvare static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; 2323237c8d2fSGong Jun static const char __initdata sio_name_W83667HG[] = "W83667HG"; 2324c39aedafSGuenter Roeck static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B"; 2325ec3e5a16SGuenter Roeck static const char __initdata sio_name_NCT6775[] = "NCT6775F"; 2326ec3e5a16SGuenter Roeck static const char __initdata sio_name_NCT6776[] = "NCT6776F"; 23271ea6dd38SDavid Hubbard 232808e7e278SJean Delvare u16 val; 23291ea6dd38SDavid Hubbard const char *sio_name; 233008e7e278SJean Delvare 23311ea6dd38SDavid Hubbard superio_enter(sioaddr); 233208e7e278SJean Delvare 233367b671bcSJean Delvare if (force_id) 233467b671bcSJean Delvare val = force_id; 233567b671bcSJean Delvare else 23361ea6dd38SDavid Hubbard val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) 23371ea6dd38SDavid Hubbard | superio_inb(sioaddr, SIO_REG_DEVID + 1); 2338657c93b1SDavid Hubbard switch (val & SIO_ID_MASK) { 2339657c93b1SDavid Hubbard case SIO_W83627EHF_ID: 23401ea6dd38SDavid Hubbard sio_data->kind = w83627ehf; 23411ea6dd38SDavid Hubbard sio_name = sio_name_W83627EHF; 23421ea6dd38SDavid Hubbard break; 2343657c93b1SDavid Hubbard case SIO_W83627EHG_ID: 23441ea6dd38SDavid Hubbard sio_data->kind = w83627ehf; 23451ea6dd38SDavid Hubbard sio_name = sio_name_W83627EHG; 23461ea6dd38SDavid Hubbard break; 23471ea6dd38SDavid Hubbard case SIO_W83627DHG_ID: 23481ea6dd38SDavid Hubbard sio_data->kind = w83627dhg; 23491ea6dd38SDavid Hubbard sio_name = sio_name_W83627DHG; 2350657c93b1SDavid Hubbard break; 2351c1e48dceSJean Delvare case SIO_W83627DHG_P_ID: 2352c1e48dceSJean Delvare sio_data->kind = w83627dhg_p; 2353c1e48dceSJean Delvare sio_name = sio_name_W83627DHG_P; 2354c1e48dceSJean Delvare break; 2355237c8d2fSGong Jun case SIO_W83667HG_ID: 2356237c8d2fSGong Jun sio_data->kind = w83667hg; 2357237c8d2fSGong Jun sio_name = sio_name_W83667HG; 2358237c8d2fSGong Jun break; 2359c39aedafSGuenter Roeck case SIO_W83667HG_B_ID: 2360c39aedafSGuenter Roeck sio_data->kind = w83667hg_b; 2361c39aedafSGuenter Roeck sio_name = sio_name_W83667HG_B; 2362c39aedafSGuenter Roeck break; 2363ec3e5a16SGuenter Roeck case SIO_NCT6775_ID: 2364ec3e5a16SGuenter Roeck sio_data->kind = nct6775; 2365ec3e5a16SGuenter Roeck sio_name = sio_name_NCT6775; 2366ec3e5a16SGuenter Roeck break; 2367ec3e5a16SGuenter Roeck case SIO_NCT6776_ID: 2368ec3e5a16SGuenter Roeck sio_data->kind = nct6776; 2369ec3e5a16SGuenter Roeck sio_name = sio_name_NCT6776; 2370ec3e5a16SGuenter Roeck break; 2371657c93b1SDavid Hubbard default: 23729f66036bSJean Delvare if (val != 0xffff) 2373abdc6fd1SJoe Perches pr_debug("unsupported chip ID: 0x%04x\n", val); 23741ea6dd38SDavid Hubbard superio_exit(sioaddr); 237508e7e278SJean Delvare return -ENODEV; 237608e7e278SJean Delvare } 237708e7e278SJean Delvare 23781ea6dd38SDavid Hubbard /* We have a known chip, find the HWM I/O address */ 23791ea6dd38SDavid Hubbard superio_select(sioaddr, W83627EHF_LD_HWM); 23801ea6dd38SDavid Hubbard val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) 23811ea6dd38SDavid Hubbard | superio_inb(sioaddr, SIO_REG_ADDR + 1); 23821a641fceSJean Delvare *addr = val & IOREGION_ALIGNMENT; 23832d8672c5SJean Delvare if (*addr == 0) { 2384abdc6fd1SJoe Perches pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n"); 23851ea6dd38SDavid Hubbard superio_exit(sioaddr); 238608e7e278SJean Delvare return -ENODEV; 238708e7e278SJean Delvare } 238808e7e278SJean Delvare 238908e7e278SJean Delvare /* Activate logical device if needed */ 23901ea6dd38SDavid Hubbard val = superio_inb(sioaddr, SIO_REG_ENABLE); 2391475ef855SDavid Hubbard if (!(val & 0x01)) { 2392e7e1ca6eSGuenter Roeck pr_warn("Forcibly enabling Super-I/O. " 2393e7e1ca6eSGuenter Roeck "Sensor is probably unusable.\n"); 23941ea6dd38SDavid Hubbard superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); 2395475ef855SDavid Hubbard } 239608e7e278SJean Delvare 23971ea6dd38SDavid Hubbard superio_exit(sioaddr); 2398abdc6fd1SJoe Perches pr_info("Found %s chip at %#x\n", sio_name, *addr); 23991ea6dd38SDavid Hubbard sio_data->sioreg = sioaddr; 24001ea6dd38SDavid Hubbard 240108e7e278SJean Delvare return 0; 240208e7e278SJean Delvare } 240308e7e278SJean Delvare 24041ea6dd38SDavid Hubbard /* when Super-I/O functions move to a separate file, the Super-I/O 24051ea6dd38SDavid Hubbard * bus will manage the lifetime of the device and this module will only keep 24061ea6dd38SDavid Hubbard * track of the w83627ehf driver. But since we platform_device_alloc(), we 24071ea6dd38SDavid Hubbard * must keep track of the device */ 24081ea6dd38SDavid Hubbard static struct platform_device *pdev; 24091ea6dd38SDavid Hubbard 241008e7e278SJean Delvare static int __init sensors_w83627ehf_init(void) 241108e7e278SJean Delvare { 24121ea6dd38SDavid Hubbard int err; 24131ea6dd38SDavid Hubbard unsigned short address; 24141ea6dd38SDavid Hubbard struct resource res; 24151ea6dd38SDavid Hubbard struct w83627ehf_sio_data sio_data; 24161ea6dd38SDavid Hubbard 24171ea6dd38SDavid Hubbard /* initialize sio_data->kind and sio_data->sioreg. 24181ea6dd38SDavid Hubbard * 24191ea6dd38SDavid Hubbard * when Super-I/O functions move to a separate file, the Super-I/O 24201ea6dd38SDavid Hubbard * driver will probe 0x2e and 0x4e and auto-detect the presence of a 24211ea6dd38SDavid Hubbard * w83627ehf hardware monitor, and call probe() */ 24221ea6dd38SDavid Hubbard if (w83627ehf_find(0x2e, &address, &sio_data) && 24231ea6dd38SDavid Hubbard w83627ehf_find(0x4e, &address, &sio_data)) 242408e7e278SJean Delvare return -ENODEV; 242508e7e278SJean Delvare 24261ea6dd38SDavid Hubbard err = platform_driver_register(&w83627ehf_driver); 24271ea6dd38SDavid Hubbard if (err) 24281ea6dd38SDavid Hubbard goto exit; 24291ea6dd38SDavid Hubbard 2430e7e1ca6eSGuenter Roeck pdev = platform_device_alloc(DRVNAME, address); 2431e7e1ca6eSGuenter Roeck if (!pdev) { 24321ea6dd38SDavid Hubbard err = -ENOMEM; 2433abdc6fd1SJoe Perches pr_err("Device allocation failed\n"); 24341ea6dd38SDavid Hubbard goto exit_unregister; 24351ea6dd38SDavid Hubbard } 24361ea6dd38SDavid Hubbard 24371ea6dd38SDavid Hubbard err = platform_device_add_data(pdev, &sio_data, 24381ea6dd38SDavid Hubbard sizeof(struct w83627ehf_sio_data)); 24391ea6dd38SDavid Hubbard if (err) { 2440abdc6fd1SJoe Perches pr_err("Platform data allocation failed\n"); 24411ea6dd38SDavid Hubbard goto exit_device_put; 24421ea6dd38SDavid Hubbard } 24431ea6dd38SDavid Hubbard 24441ea6dd38SDavid Hubbard memset(&res, 0, sizeof(res)); 24451ea6dd38SDavid Hubbard res.name = DRVNAME; 24461ea6dd38SDavid Hubbard res.start = address + IOREGION_OFFSET; 24471ea6dd38SDavid Hubbard res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; 24481ea6dd38SDavid Hubbard res.flags = IORESOURCE_IO; 2449b9acb64aSJean Delvare 2450b9acb64aSJean Delvare err = acpi_check_resource_conflict(&res); 2451b9acb64aSJean Delvare if (err) 245218632f84SHans de Goede goto exit_device_put; 2453b9acb64aSJean Delvare 24541ea6dd38SDavid Hubbard err = platform_device_add_resources(pdev, &res, 1); 24551ea6dd38SDavid Hubbard if (err) { 2456abdc6fd1SJoe Perches pr_err("Device resource addition failed (%d)\n", err); 24571ea6dd38SDavid Hubbard goto exit_device_put; 24581ea6dd38SDavid Hubbard } 24591ea6dd38SDavid Hubbard 24601ea6dd38SDavid Hubbard /* platform_device_add calls probe() */ 24611ea6dd38SDavid Hubbard err = platform_device_add(pdev); 24621ea6dd38SDavid Hubbard if (err) { 2463abdc6fd1SJoe Perches pr_err("Device addition failed (%d)\n", err); 24641ea6dd38SDavid Hubbard goto exit_device_put; 24651ea6dd38SDavid Hubbard } 24661ea6dd38SDavid Hubbard 24671ea6dd38SDavid Hubbard return 0; 24681ea6dd38SDavid Hubbard 24691ea6dd38SDavid Hubbard exit_device_put: 24701ea6dd38SDavid Hubbard platform_device_put(pdev); 24711ea6dd38SDavid Hubbard exit_unregister: 24721ea6dd38SDavid Hubbard platform_driver_unregister(&w83627ehf_driver); 24731ea6dd38SDavid Hubbard exit: 24741ea6dd38SDavid Hubbard return err; 247508e7e278SJean Delvare } 247608e7e278SJean Delvare 247708e7e278SJean Delvare static void __exit sensors_w83627ehf_exit(void) 247808e7e278SJean Delvare { 24791ea6dd38SDavid Hubbard platform_device_unregister(pdev); 24801ea6dd38SDavid Hubbard platform_driver_unregister(&w83627ehf_driver); 248108e7e278SJean Delvare } 248208e7e278SJean Delvare 248308e7e278SJean Delvare MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); 248408e7e278SJean Delvare MODULE_DESCRIPTION("W83627EHF driver"); 248508e7e278SJean Delvare MODULE_LICENSE("GPL"); 248608e7e278SJean Delvare 248708e7e278SJean Delvare module_init(sensors_w83627ehf_init); 248808e7e278SJean Delvare module_exit(sensors_w83627ehf_exit); 2489