1*c3963bc0SZev Weiss // SPDX-License-Identifier: GPL-2.0-or-later 2*c3963bc0SZev Weiss /* 3*c3963bc0SZev Weiss * nct6775 - Driver for the hardware monitoring functionality of 4*c3963bc0SZev Weiss * Nuvoton NCT677x Super-I/O chips 5*c3963bc0SZev Weiss * 6*c3963bc0SZev Weiss * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net> 7*c3963bc0SZev Weiss * 8*c3963bc0SZev Weiss * Derived from w83627ehf driver 9*c3963bc0SZev Weiss * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de> 10*c3963bc0SZev Weiss * Copyright (C) 2006 Yuan Mu (Winbond), 11*c3963bc0SZev Weiss * Rudolf Marek <r.marek@assembler.cz> 12*c3963bc0SZev Weiss * David Hubbard <david.c.hubbard@gmail.com> 13*c3963bc0SZev Weiss * Daniel J Blueman <daniel.blueman@gmail.com> 14*c3963bc0SZev Weiss * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00) 15*c3963bc0SZev Weiss * 16*c3963bc0SZev Weiss * Shamelessly ripped from the w83627hf driver 17*c3963bc0SZev Weiss * Copyright (C) 2003 Mark Studebaker 18*c3963bc0SZev Weiss * 19*c3963bc0SZev Weiss * Supports the following chips: 20*c3963bc0SZev Weiss * 21*c3963bc0SZev Weiss * Chip #vin #fan #pwm #temp chip IDs man ID 22*c3963bc0SZev Weiss * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3 23*c3963bc0SZev Weiss * nct6116d 9 5 5 3+3 0xd280 0xc1 0x5ca3 24*c3963bc0SZev Weiss * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3 25*c3963bc0SZev Weiss * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3 26*c3963bc0SZev Weiss * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3 27*c3963bc0SZev Weiss * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3 28*c3963bc0SZev Weiss * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3 29*c3963bc0SZev Weiss * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3 30*c3963bc0SZev Weiss * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3 31*c3963bc0SZev Weiss * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3 32*c3963bc0SZev Weiss * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3 33*c3963bc0SZev Weiss * (0xd451) 34*c3963bc0SZev Weiss * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3 35*c3963bc0SZev Weiss * (0xd429) 36*c3963bc0SZev Weiss * 37*c3963bc0SZev Weiss * #temp lists the number of monitored temperature sources (first value) plus 38*c3963bc0SZev Weiss * the number of directly connectable temperature sensors (second value). 39*c3963bc0SZev Weiss */ 40*c3963bc0SZev Weiss 41*c3963bc0SZev Weiss #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 42*c3963bc0SZev Weiss 43*c3963bc0SZev Weiss #include <linux/module.h> 44*c3963bc0SZev Weiss #include <linux/init.h> 45*c3963bc0SZev Weiss #include <linux/slab.h> 46*c3963bc0SZev Weiss #include <linux/jiffies.h> 47*c3963bc0SZev Weiss #include <linux/hwmon.h> 48*c3963bc0SZev Weiss #include <linux/hwmon-sysfs.h> 49*c3963bc0SZev Weiss #include <linux/err.h> 50*c3963bc0SZev Weiss #include <linux/mutex.h> 51*c3963bc0SZev Weiss #include <linux/bitops.h> 52*c3963bc0SZev Weiss #include <linux/nospec.h> 53*c3963bc0SZev Weiss #include <linux/regmap.h> 54*c3963bc0SZev Weiss #include "lm75.h" 55*c3963bc0SZev Weiss #include "nct6775.h" 56*c3963bc0SZev Weiss 57*c3963bc0SZev Weiss #undef DEFAULT_SYMBOL_NAMESPACE 58*c3963bc0SZev Weiss #define DEFAULT_SYMBOL_NAMESPACE HWMON_NCT6775 59*c3963bc0SZev Weiss 60*c3963bc0SZev Weiss #define USE_ALTERNATE 61*c3963bc0SZev Weiss 62*c3963bc0SZev Weiss /* used to set data->name = nct6775_device_names[data->sio_kind] */ 63*c3963bc0SZev Weiss static const char * const nct6775_device_names[] = { 64*c3963bc0SZev Weiss "nct6106", 65*c3963bc0SZev Weiss "nct6116", 66*c3963bc0SZev Weiss "nct6775", 67*c3963bc0SZev Weiss "nct6776", 68*c3963bc0SZev Weiss "nct6779", 69*c3963bc0SZev Weiss "nct6791", 70*c3963bc0SZev Weiss "nct6792", 71*c3963bc0SZev Weiss "nct6793", 72*c3963bc0SZev Weiss "nct6795", 73*c3963bc0SZev Weiss "nct6796", 74*c3963bc0SZev Weiss "nct6797", 75*c3963bc0SZev Weiss "nct6798", 76*c3963bc0SZev Weiss }; 77*c3963bc0SZev Weiss 78*c3963bc0SZev Weiss /* Common and NCT6775 specific data */ 79*c3963bc0SZev Weiss 80*c3963bc0SZev Weiss /* Voltage min/max registers for nr=7..14 are in bank 5 */ 81*c3963bc0SZev Weiss 82*c3963bc0SZev Weiss static const u16 NCT6775_REG_IN_MAX[] = { 83*c3963bc0SZev Weiss 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a, 84*c3963bc0SZev Weiss 0x55c, 0x55e, 0x560, 0x562 }; 85*c3963bc0SZev Weiss static const u16 NCT6775_REG_IN_MIN[] = { 86*c3963bc0SZev Weiss 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b, 87*c3963bc0SZev Weiss 0x55d, 0x55f, 0x561, 0x563 }; 88*c3963bc0SZev Weiss static const u16 NCT6775_REG_IN[] = { 89*c3963bc0SZev Weiss 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552 90*c3963bc0SZev Weiss }; 91*c3963bc0SZev Weiss 92*c3963bc0SZev Weiss #define NCT6775_REG_VBAT 0x5D 93*c3963bc0SZev Weiss #define NCT6775_REG_DIODE 0x5E 94*c3963bc0SZev Weiss #define NCT6775_DIODE_MASK 0x02 95*c3963bc0SZev Weiss 96*c3963bc0SZev Weiss static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B }; 97*c3963bc0SZev Weiss 98*c3963bc0SZev Weiss /* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */ 99*c3963bc0SZev Weiss 100*c3963bc0SZev Weiss static const s8 NCT6775_ALARM_BITS[] = { 101*c3963bc0SZev Weiss 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ 102*c3963bc0SZev Weiss 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */ 103*c3963bc0SZev Weiss -1, /* unused */ 104*c3963bc0SZev Weiss 6, 7, 11, -1, -1, /* fan1..fan5 */ 105*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 106*c3963bc0SZev Weiss 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 107*c3963bc0SZev Weiss 12, -1 }; /* intrusion0, intrusion1 */ 108*c3963bc0SZev Weiss 109*c3963bc0SZev Weiss static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e }; 110*c3963bc0SZev Weiss 111*c3963bc0SZev Weiss /* 112*c3963bc0SZev Weiss * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures, 113*c3963bc0SZev Weiss * 30..31 intrusion 114*c3963bc0SZev Weiss */ 115*c3963bc0SZev Weiss static const s8 NCT6775_BEEP_BITS[] = { 116*c3963bc0SZev Weiss 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */ 117*c3963bc0SZev Weiss 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */ 118*c3963bc0SZev Weiss 21, /* global beep enable */ 119*c3963bc0SZev Weiss 6, 7, 11, 28, -1, /* fan1..fan5 */ 120*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 121*c3963bc0SZev Weiss 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 122*c3963bc0SZev Weiss 12, -1 }; /* intrusion0, intrusion1 */ 123*c3963bc0SZev Weiss 124*c3963bc0SZev Weiss /* DC or PWM output fan configuration */ 125*c3963bc0SZev Weiss static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 }; 126*c3963bc0SZev Weiss static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 }; 127*c3963bc0SZev Weiss 128*c3963bc0SZev Weiss /* Advanced Fan control, some values are common for all fans */ 129*c3963bc0SZev Weiss 130*c3963bc0SZev Weiss static const u16 NCT6775_REG_TARGET[] = { 131*c3963bc0SZev Weiss 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 }; 132*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_MODE[] = { 133*c3963bc0SZev Weiss 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 }; 134*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = { 135*c3963bc0SZev Weiss 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 }; 136*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = { 137*c3963bc0SZev Weiss 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 }; 138*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 139*c3963bc0SZev Weiss 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 }; 140*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 141*c3963bc0SZev Weiss 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 }; 142*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a }; 143*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b }; 144*c3963bc0SZev Weiss 145*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 146*c3963bc0SZev Weiss 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 }; 147*c3963bc0SZev Weiss static const u16 NCT6775_REG_PWM[] = { 148*c3963bc0SZev Weiss 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 }; 149*c3963bc0SZev Weiss static const u16 NCT6775_REG_PWM_READ[] = { 150*c3963bc0SZev Weiss 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 }; 151*c3963bc0SZev Weiss 152*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; 153*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d }; 154*c3963bc0SZev Weiss static const u16 NCT6775_REG_FAN_PULSES[NUM_FAN] = { 155*c3963bc0SZev Weiss 0x641, 0x642, 0x643, 0x644 }; 156*c3963bc0SZev Weiss static const u16 NCT6775_FAN_PULSE_SHIFT[NUM_FAN] = { }; 157*c3963bc0SZev Weiss 158*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP[] = { 159*c3963bc0SZev Weiss 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d }; 160*c3963bc0SZev Weiss 161*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 }; 162*c3963bc0SZev Weiss 163*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 164*c3963bc0SZev Weiss 0, 0x152, 0x252, 0x628, 0x629, 0x62A }; 165*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 166*c3963bc0SZev Weiss 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D }; 167*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 168*c3963bc0SZev Weiss 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C }; 169*c3963bc0SZev Weiss 170*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 171*c3963bc0SZev Weiss 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 }; 172*c3963bc0SZev Weiss 173*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_SEL[] = { 174*c3963bc0SZev Weiss 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 }; 175*c3963bc0SZev Weiss 176*c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = { 177*c3963bc0SZev Weiss 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 }; 178*c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = { 179*c3963bc0SZev Weiss 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a }; 180*c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = { 181*c3963bc0SZev Weiss 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b }; 182*c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = { 183*c3963bc0SZev Weiss 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c }; 184*c3963bc0SZev Weiss static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = { 185*c3963bc0SZev Weiss 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d }; 186*c3963bc0SZev Weiss 187*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 }; 188*c3963bc0SZev Weiss 189*c3963bc0SZev Weiss static const u16 NCT6775_REG_AUTO_TEMP[] = { 190*c3963bc0SZev Weiss 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 }; 191*c3963bc0SZev Weiss static const u16 NCT6775_REG_AUTO_PWM[] = { 192*c3963bc0SZev Weiss 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 }; 193*c3963bc0SZev Weiss 194*c3963bc0SZev Weiss #define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p)) 195*c3963bc0SZev Weiss #define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p)) 196*c3963bc0SZev Weiss 197*c3963bc0SZev Weiss static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 }; 198*c3963bc0SZev Weiss 199*c3963bc0SZev Weiss static const u16 NCT6775_REG_CRITICAL_TEMP[] = { 200*c3963bc0SZev Weiss 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 }; 201*c3963bc0SZev Weiss static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = { 202*c3963bc0SZev Weiss 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 }; 203*c3963bc0SZev Weiss 204*c3963bc0SZev Weiss static const char *const nct6775_temp_label[] = { 205*c3963bc0SZev Weiss "", 206*c3963bc0SZev Weiss "SYSTIN", 207*c3963bc0SZev Weiss "CPUTIN", 208*c3963bc0SZev Weiss "AUXTIN", 209*c3963bc0SZev Weiss "AMD SB-TSI", 210*c3963bc0SZev Weiss "PECI Agent 0", 211*c3963bc0SZev Weiss "PECI Agent 1", 212*c3963bc0SZev Weiss "PECI Agent 2", 213*c3963bc0SZev Weiss "PECI Agent 3", 214*c3963bc0SZev Weiss "PECI Agent 4", 215*c3963bc0SZev Weiss "PECI Agent 5", 216*c3963bc0SZev Weiss "PECI Agent 6", 217*c3963bc0SZev Weiss "PECI Agent 7", 218*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 219*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 220*c3963bc0SZev Weiss "PCH_CPU_TEMP", 221*c3963bc0SZev Weiss "PCH_MCH_TEMP", 222*c3963bc0SZev Weiss "PCH_DIM0_TEMP", 223*c3963bc0SZev Weiss "PCH_DIM1_TEMP", 224*c3963bc0SZev Weiss "PCH_DIM2_TEMP", 225*c3963bc0SZev Weiss "PCH_DIM3_TEMP" 226*c3963bc0SZev Weiss }; 227*c3963bc0SZev Weiss 228*c3963bc0SZev Weiss #define NCT6775_TEMP_MASK 0x001ffffe 229*c3963bc0SZev Weiss #define NCT6775_VIRT_TEMP_MASK 0x00000000 230*c3963bc0SZev Weiss 231*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = { 232*c3963bc0SZev Weiss [13] = 0x661, 233*c3963bc0SZev Weiss [14] = 0x662, 234*c3963bc0SZev Weiss [15] = 0x664, 235*c3963bc0SZev Weiss }; 236*c3963bc0SZev Weiss 237*c3963bc0SZev Weiss static const u16 NCT6775_REG_TEMP_CRIT[32] = { 238*c3963bc0SZev Weiss [4] = 0xa00, 239*c3963bc0SZev Weiss [5] = 0xa01, 240*c3963bc0SZev Weiss [6] = 0xa02, 241*c3963bc0SZev Weiss [7] = 0xa03, 242*c3963bc0SZev Weiss [8] = 0xa04, 243*c3963bc0SZev Weiss [9] = 0xa05, 244*c3963bc0SZev Weiss [10] = 0xa06, 245*c3963bc0SZev Weiss [11] = 0xa07 246*c3963bc0SZev Weiss }; 247*c3963bc0SZev Weiss 248*c3963bc0SZev Weiss static const u16 NCT6775_REG_TSI_TEMP[] = { 0x669 }; 249*c3963bc0SZev Weiss 250*c3963bc0SZev Weiss /* NCT6776 specific data */ 251*c3963bc0SZev Weiss 252*c3963bc0SZev Weiss /* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */ 253*c3963bc0SZev Weiss #define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME 254*c3963bc0SZev Weiss #define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME 255*c3963bc0SZev Weiss 256*c3963bc0SZev Weiss static const s8 NCT6776_ALARM_BITS[] = { 257*c3963bc0SZev Weiss 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ 258*c3963bc0SZev Weiss 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */ 259*c3963bc0SZev Weiss -1, /* unused */ 260*c3963bc0SZev Weiss 6, 7, 11, 10, 23, /* fan1..fan5 */ 261*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 262*c3963bc0SZev Weiss 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 263*c3963bc0SZev Weiss 12, 9 }; /* intrusion0, intrusion1 */ 264*c3963bc0SZev Weiss 265*c3963bc0SZev Weiss static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 }; 266*c3963bc0SZev Weiss 267*c3963bc0SZev Weiss static const s8 NCT6776_BEEP_BITS[] = { 268*c3963bc0SZev Weiss 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */ 269*c3963bc0SZev Weiss 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */ 270*c3963bc0SZev Weiss 24, /* global beep enable */ 271*c3963bc0SZev Weiss 25, 26, 27, 28, 29, /* fan1..fan5 */ 272*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 273*c3963bc0SZev Weiss 16, 17, 18, 19, 20, 21, /* temp1..temp6 */ 274*c3963bc0SZev Weiss 30, 31 }; /* intrusion0, intrusion1 */ 275*c3963bc0SZev Weiss 276*c3963bc0SZev Weiss static const u16 NCT6776_REG_TOLERANCE_H[] = { 277*c3963bc0SZev Weiss 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c }; 278*c3963bc0SZev Weiss 279*c3963bc0SZev Weiss static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 }; 280*c3963bc0SZev Weiss static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 }; 281*c3963bc0SZev Weiss 282*c3963bc0SZev Weiss static const u16 NCT6776_REG_FAN_MIN[] = { 283*c3963bc0SZev Weiss 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c }; 284*c3963bc0SZev Weiss static const u16 NCT6776_REG_FAN_PULSES[NUM_FAN] = { 285*c3963bc0SZev Weiss 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 }; 286*c3963bc0SZev Weiss 287*c3963bc0SZev Weiss static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = { 288*c3963bc0SZev Weiss 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e }; 289*c3963bc0SZev Weiss 290*c3963bc0SZev Weiss static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 291*c3963bc0SZev Weiss 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A }; 292*c3963bc0SZev Weiss 293*c3963bc0SZev Weiss static const char *const nct6776_temp_label[] = { 294*c3963bc0SZev Weiss "", 295*c3963bc0SZev Weiss "SYSTIN", 296*c3963bc0SZev Weiss "CPUTIN", 297*c3963bc0SZev Weiss "AUXTIN", 298*c3963bc0SZev Weiss "SMBUSMASTER 0", 299*c3963bc0SZev Weiss "SMBUSMASTER 1", 300*c3963bc0SZev Weiss "SMBUSMASTER 2", 301*c3963bc0SZev Weiss "SMBUSMASTER 3", 302*c3963bc0SZev Weiss "SMBUSMASTER 4", 303*c3963bc0SZev Weiss "SMBUSMASTER 5", 304*c3963bc0SZev Weiss "SMBUSMASTER 6", 305*c3963bc0SZev Weiss "SMBUSMASTER 7", 306*c3963bc0SZev Weiss "PECI Agent 0", 307*c3963bc0SZev Weiss "PECI Agent 1", 308*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 309*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 310*c3963bc0SZev Weiss "PCH_CPU_TEMP", 311*c3963bc0SZev Weiss "PCH_MCH_TEMP", 312*c3963bc0SZev Weiss "PCH_DIM0_TEMP", 313*c3963bc0SZev Weiss "PCH_DIM1_TEMP", 314*c3963bc0SZev Weiss "PCH_DIM2_TEMP", 315*c3963bc0SZev Weiss "PCH_DIM3_TEMP", 316*c3963bc0SZev Weiss "BYTE_TEMP" 317*c3963bc0SZev Weiss }; 318*c3963bc0SZev Weiss 319*c3963bc0SZev Weiss #define NCT6776_TEMP_MASK 0x007ffffe 320*c3963bc0SZev Weiss #define NCT6776_VIRT_TEMP_MASK 0x00000000 321*c3963bc0SZev Weiss 322*c3963bc0SZev Weiss static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = { 323*c3963bc0SZev Weiss [14] = 0x401, 324*c3963bc0SZev Weiss [15] = 0x402, 325*c3963bc0SZev Weiss [16] = 0x404, 326*c3963bc0SZev Weiss }; 327*c3963bc0SZev Weiss 328*c3963bc0SZev Weiss static const u16 NCT6776_REG_TEMP_CRIT[32] = { 329*c3963bc0SZev Weiss [11] = 0x709, 330*c3963bc0SZev Weiss [12] = 0x70a, 331*c3963bc0SZev Weiss }; 332*c3963bc0SZev Weiss 333*c3963bc0SZev Weiss static const u16 NCT6776_REG_TSI_TEMP[] = { 334*c3963bc0SZev Weiss 0x409, 0x40b, 0x40d, 0x40f, 0x411, 0x413, 0x415, 0x417 }; 335*c3963bc0SZev Weiss 336*c3963bc0SZev Weiss /* NCT6779 specific data */ 337*c3963bc0SZev Weiss 338*c3963bc0SZev Weiss static const u16 NCT6779_REG_IN[] = { 339*c3963bc0SZev Weiss 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487, 340*c3963bc0SZev Weiss 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e }; 341*c3963bc0SZev Weiss 342*c3963bc0SZev Weiss static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = { 343*c3963bc0SZev Weiss 0x459, 0x45A, 0x45B, 0x568 }; 344*c3963bc0SZev Weiss 345*c3963bc0SZev Weiss static const s8 NCT6779_ALARM_BITS[] = { 346*c3963bc0SZev Weiss 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ 347*c3963bc0SZev Weiss 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */ 348*c3963bc0SZev Weiss -1, /* unused */ 349*c3963bc0SZev Weiss 6, 7, 11, 10, 23, /* fan1..fan5 */ 350*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 351*c3963bc0SZev Weiss 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 352*c3963bc0SZev Weiss 12, 9 }; /* intrusion0, intrusion1 */ 353*c3963bc0SZev Weiss 354*c3963bc0SZev Weiss static const s8 NCT6779_BEEP_BITS[] = { 355*c3963bc0SZev Weiss 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */ 356*c3963bc0SZev Weiss 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */ 357*c3963bc0SZev Weiss 24, /* global beep enable */ 358*c3963bc0SZev Weiss 25, 26, 27, 28, 29, /* fan1..fan5 */ 359*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 360*c3963bc0SZev Weiss 16, 17, -1, -1, -1, -1, /* temp1..temp6 */ 361*c3963bc0SZev Weiss 30, 31 }; /* intrusion0, intrusion1 */ 362*c3963bc0SZev Weiss 363*c3963bc0SZev Weiss static const u16 NCT6779_REG_FAN[] = { 364*c3963bc0SZev Weiss 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce }; 365*c3963bc0SZev Weiss static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = { 366*c3963bc0SZev Weiss 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f }; 367*c3963bc0SZev Weiss 368*c3963bc0SZev Weiss static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = { 369*c3963bc0SZev Weiss 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 }; 370*c3963bc0SZev Weiss #define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01 371*c3963bc0SZev Weiss static const u16 NCT6779_REG_CRITICAL_PWM[] = { 372*c3963bc0SZev Weiss 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 }; 373*c3963bc0SZev Weiss 374*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 }; 375*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b }; 376*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 377*c3963bc0SZev Weiss 0x18, 0x152 }; 378*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 379*c3963bc0SZev Weiss 0x3a, 0x153 }; 380*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 381*c3963bc0SZev Weiss 0x39, 0x155 }; 382*c3963bc0SZev Weiss 383*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_OFFSET[] = { 384*c3963bc0SZev Weiss 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c }; 385*c3963bc0SZev Weiss 386*c3963bc0SZev Weiss static const char *const nct6779_temp_label[] = { 387*c3963bc0SZev Weiss "", 388*c3963bc0SZev Weiss "SYSTIN", 389*c3963bc0SZev Weiss "CPUTIN", 390*c3963bc0SZev Weiss "AUXTIN0", 391*c3963bc0SZev Weiss "AUXTIN1", 392*c3963bc0SZev Weiss "AUXTIN2", 393*c3963bc0SZev Weiss "AUXTIN3", 394*c3963bc0SZev Weiss "", 395*c3963bc0SZev Weiss "SMBUSMASTER 0", 396*c3963bc0SZev Weiss "SMBUSMASTER 1", 397*c3963bc0SZev Weiss "SMBUSMASTER 2", 398*c3963bc0SZev Weiss "SMBUSMASTER 3", 399*c3963bc0SZev Weiss "SMBUSMASTER 4", 400*c3963bc0SZev Weiss "SMBUSMASTER 5", 401*c3963bc0SZev Weiss "SMBUSMASTER 6", 402*c3963bc0SZev Weiss "SMBUSMASTER 7", 403*c3963bc0SZev Weiss "PECI Agent 0", 404*c3963bc0SZev Weiss "PECI Agent 1", 405*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 406*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 407*c3963bc0SZev Weiss "PCH_CPU_TEMP", 408*c3963bc0SZev Weiss "PCH_MCH_TEMP", 409*c3963bc0SZev Weiss "PCH_DIM0_TEMP", 410*c3963bc0SZev Weiss "PCH_DIM1_TEMP", 411*c3963bc0SZev Weiss "PCH_DIM2_TEMP", 412*c3963bc0SZev Weiss "PCH_DIM3_TEMP", 413*c3963bc0SZev Weiss "BYTE_TEMP", 414*c3963bc0SZev Weiss "", 415*c3963bc0SZev Weiss "", 416*c3963bc0SZev Weiss "", 417*c3963bc0SZev Weiss "", 418*c3963bc0SZev Weiss "Virtual_TEMP" 419*c3963bc0SZev Weiss }; 420*c3963bc0SZev Weiss 421*c3963bc0SZev Weiss #define NCT6779_TEMP_MASK 0x07ffff7e 422*c3963bc0SZev Weiss #define NCT6779_VIRT_TEMP_MASK 0x00000000 423*c3963bc0SZev Weiss #define NCT6791_TEMP_MASK 0x87ffff7e 424*c3963bc0SZev Weiss #define NCT6791_VIRT_TEMP_MASK 0x80000000 425*c3963bc0SZev Weiss 426*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_ALTERNATE[32] 427*c3963bc0SZev Weiss = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0, 428*c3963bc0SZev Weiss 0, 0, 0, 0, 0, 0, 0, 0, 429*c3963bc0SZev Weiss 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407, 430*c3963bc0SZev Weiss 0x408, 0 }; 431*c3963bc0SZev Weiss 432*c3963bc0SZev Weiss static const u16 NCT6779_REG_TEMP_CRIT[32] = { 433*c3963bc0SZev Weiss [15] = 0x709, 434*c3963bc0SZev Weiss [16] = 0x70a, 435*c3963bc0SZev Weiss }; 436*c3963bc0SZev Weiss 437*c3963bc0SZev Weiss /* NCT6791 specific data */ 438*c3963bc0SZev Weiss 439*c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 }; 440*c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a }; 441*c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b }; 442*c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c }; 443*c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d }; 444*c3963bc0SZev Weiss static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e }; 445*c3963bc0SZev Weiss 446*c3963bc0SZev Weiss static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = { 447*c3963bc0SZev Weiss 0x459, 0x45A, 0x45B, 0x568, 0x45D }; 448*c3963bc0SZev Weiss 449*c3963bc0SZev Weiss static const s8 NCT6791_ALARM_BITS[] = { 450*c3963bc0SZev Weiss 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ 451*c3963bc0SZev Weiss 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */ 452*c3963bc0SZev Weiss -1, /* unused */ 453*c3963bc0SZev Weiss 6, 7, 11, 10, 23, 33, /* fan1..fan6 */ 454*c3963bc0SZev Weiss -1, -1, /* unused */ 455*c3963bc0SZev Weiss 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 456*c3963bc0SZev Weiss 12, 9 }; /* intrusion0, intrusion1 */ 457*c3963bc0SZev Weiss 458*c3963bc0SZev Weiss /* NCT6792/NCT6793 specific data */ 459*c3963bc0SZev Weiss 460*c3963bc0SZev Weiss static const u16 NCT6792_REG_TEMP_MON[] = { 461*c3963bc0SZev Weiss 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d }; 462*c3963bc0SZev Weiss static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = { 463*c3963bc0SZev Weiss 0xb2, 0xb3, 0xb4, 0xb5, 0xbf }; 464*c3963bc0SZev Weiss 465*c3963bc0SZev Weiss static const char *const nct6792_temp_label[] = { 466*c3963bc0SZev Weiss "", 467*c3963bc0SZev Weiss "SYSTIN", 468*c3963bc0SZev Weiss "CPUTIN", 469*c3963bc0SZev Weiss "AUXTIN0", 470*c3963bc0SZev Weiss "AUXTIN1", 471*c3963bc0SZev Weiss "AUXTIN2", 472*c3963bc0SZev Weiss "AUXTIN3", 473*c3963bc0SZev Weiss "", 474*c3963bc0SZev Weiss "SMBUSMASTER 0", 475*c3963bc0SZev Weiss "SMBUSMASTER 1", 476*c3963bc0SZev Weiss "SMBUSMASTER 2", 477*c3963bc0SZev Weiss "SMBUSMASTER 3", 478*c3963bc0SZev Weiss "SMBUSMASTER 4", 479*c3963bc0SZev Weiss "SMBUSMASTER 5", 480*c3963bc0SZev Weiss "SMBUSMASTER 6", 481*c3963bc0SZev Weiss "SMBUSMASTER 7", 482*c3963bc0SZev Weiss "PECI Agent 0", 483*c3963bc0SZev Weiss "PECI Agent 1", 484*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 485*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 486*c3963bc0SZev Weiss "PCH_CPU_TEMP", 487*c3963bc0SZev Weiss "PCH_MCH_TEMP", 488*c3963bc0SZev Weiss "PCH_DIM0_TEMP", 489*c3963bc0SZev Weiss "PCH_DIM1_TEMP", 490*c3963bc0SZev Weiss "PCH_DIM2_TEMP", 491*c3963bc0SZev Weiss "PCH_DIM3_TEMP", 492*c3963bc0SZev Weiss "BYTE_TEMP", 493*c3963bc0SZev Weiss "PECI Agent 0 Calibration", 494*c3963bc0SZev Weiss "PECI Agent 1 Calibration", 495*c3963bc0SZev Weiss "", 496*c3963bc0SZev Weiss "", 497*c3963bc0SZev Weiss "Virtual_TEMP" 498*c3963bc0SZev Weiss }; 499*c3963bc0SZev Weiss 500*c3963bc0SZev Weiss #define NCT6792_TEMP_MASK 0x9fffff7e 501*c3963bc0SZev Weiss #define NCT6792_VIRT_TEMP_MASK 0x80000000 502*c3963bc0SZev Weiss 503*c3963bc0SZev Weiss static const char *const nct6793_temp_label[] = { 504*c3963bc0SZev Weiss "", 505*c3963bc0SZev Weiss "SYSTIN", 506*c3963bc0SZev Weiss "CPUTIN", 507*c3963bc0SZev Weiss "AUXTIN0", 508*c3963bc0SZev Weiss "AUXTIN1", 509*c3963bc0SZev Weiss "AUXTIN2", 510*c3963bc0SZev Weiss "AUXTIN3", 511*c3963bc0SZev Weiss "", 512*c3963bc0SZev Weiss "SMBUSMASTER 0", 513*c3963bc0SZev Weiss "SMBUSMASTER 1", 514*c3963bc0SZev Weiss "", 515*c3963bc0SZev Weiss "", 516*c3963bc0SZev Weiss "", 517*c3963bc0SZev Weiss "", 518*c3963bc0SZev Weiss "", 519*c3963bc0SZev Weiss "", 520*c3963bc0SZev Weiss "PECI Agent 0", 521*c3963bc0SZev Weiss "PECI Agent 1", 522*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 523*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 524*c3963bc0SZev Weiss "PCH_CPU_TEMP", 525*c3963bc0SZev Weiss "PCH_MCH_TEMP", 526*c3963bc0SZev Weiss "Agent0 Dimm0 ", 527*c3963bc0SZev Weiss "Agent0 Dimm1", 528*c3963bc0SZev Weiss "Agent1 Dimm0", 529*c3963bc0SZev Weiss "Agent1 Dimm1", 530*c3963bc0SZev Weiss "BYTE_TEMP0", 531*c3963bc0SZev Weiss "BYTE_TEMP1", 532*c3963bc0SZev Weiss "PECI Agent 0 Calibration", 533*c3963bc0SZev Weiss "PECI Agent 1 Calibration", 534*c3963bc0SZev Weiss "", 535*c3963bc0SZev Weiss "Virtual_TEMP" 536*c3963bc0SZev Weiss }; 537*c3963bc0SZev Weiss 538*c3963bc0SZev Weiss #define NCT6793_TEMP_MASK 0xbfff037e 539*c3963bc0SZev Weiss #define NCT6793_VIRT_TEMP_MASK 0x80000000 540*c3963bc0SZev Weiss 541*c3963bc0SZev Weiss static const char *const nct6795_temp_label[] = { 542*c3963bc0SZev Weiss "", 543*c3963bc0SZev Weiss "SYSTIN", 544*c3963bc0SZev Weiss "CPUTIN", 545*c3963bc0SZev Weiss "AUXTIN0", 546*c3963bc0SZev Weiss "AUXTIN1", 547*c3963bc0SZev Weiss "AUXTIN2", 548*c3963bc0SZev Weiss "AUXTIN3", 549*c3963bc0SZev Weiss "", 550*c3963bc0SZev Weiss "SMBUSMASTER 0", 551*c3963bc0SZev Weiss "SMBUSMASTER 1", 552*c3963bc0SZev Weiss "SMBUSMASTER 2", 553*c3963bc0SZev Weiss "SMBUSMASTER 3", 554*c3963bc0SZev Weiss "SMBUSMASTER 4", 555*c3963bc0SZev Weiss "SMBUSMASTER 5", 556*c3963bc0SZev Weiss "SMBUSMASTER 6", 557*c3963bc0SZev Weiss "SMBUSMASTER 7", 558*c3963bc0SZev Weiss "PECI Agent 0", 559*c3963bc0SZev Weiss "PECI Agent 1", 560*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 561*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 562*c3963bc0SZev Weiss "PCH_CPU_TEMP", 563*c3963bc0SZev Weiss "PCH_MCH_TEMP", 564*c3963bc0SZev Weiss "Agent0 Dimm0", 565*c3963bc0SZev Weiss "Agent0 Dimm1", 566*c3963bc0SZev Weiss "Agent1 Dimm0", 567*c3963bc0SZev Weiss "Agent1 Dimm1", 568*c3963bc0SZev Weiss "BYTE_TEMP0", 569*c3963bc0SZev Weiss "BYTE_TEMP1", 570*c3963bc0SZev Weiss "PECI Agent 0 Calibration", 571*c3963bc0SZev Weiss "PECI Agent 1 Calibration", 572*c3963bc0SZev Weiss "", 573*c3963bc0SZev Weiss "Virtual_TEMP" 574*c3963bc0SZev Weiss }; 575*c3963bc0SZev Weiss 576*c3963bc0SZev Weiss #define NCT6795_TEMP_MASK 0xbfffff7e 577*c3963bc0SZev Weiss #define NCT6795_VIRT_TEMP_MASK 0x80000000 578*c3963bc0SZev Weiss 579*c3963bc0SZev Weiss static const char *const nct6796_temp_label[] = { 580*c3963bc0SZev Weiss "", 581*c3963bc0SZev Weiss "SYSTIN", 582*c3963bc0SZev Weiss "CPUTIN", 583*c3963bc0SZev Weiss "AUXTIN0", 584*c3963bc0SZev Weiss "AUXTIN1", 585*c3963bc0SZev Weiss "AUXTIN2", 586*c3963bc0SZev Weiss "AUXTIN3", 587*c3963bc0SZev Weiss "AUXTIN4", 588*c3963bc0SZev Weiss "SMBUSMASTER 0", 589*c3963bc0SZev Weiss "SMBUSMASTER 1", 590*c3963bc0SZev Weiss "Virtual_TEMP", 591*c3963bc0SZev Weiss "Virtual_TEMP", 592*c3963bc0SZev Weiss "", 593*c3963bc0SZev Weiss "", 594*c3963bc0SZev Weiss "", 595*c3963bc0SZev Weiss "", 596*c3963bc0SZev Weiss "PECI Agent 0", 597*c3963bc0SZev Weiss "PECI Agent 1", 598*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 599*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 600*c3963bc0SZev Weiss "PCH_CPU_TEMP", 601*c3963bc0SZev Weiss "PCH_MCH_TEMP", 602*c3963bc0SZev Weiss "Agent0 Dimm0", 603*c3963bc0SZev Weiss "Agent0 Dimm1", 604*c3963bc0SZev Weiss "Agent1 Dimm0", 605*c3963bc0SZev Weiss "Agent1 Dimm1", 606*c3963bc0SZev Weiss "BYTE_TEMP0", 607*c3963bc0SZev Weiss "BYTE_TEMP1", 608*c3963bc0SZev Weiss "PECI Agent 0 Calibration", 609*c3963bc0SZev Weiss "PECI Agent 1 Calibration", 610*c3963bc0SZev Weiss "", 611*c3963bc0SZev Weiss "Virtual_TEMP" 612*c3963bc0SZev Weiss }; 613*c3963bc0SZev Weiss 614*c3963bc0SZev Weiss #define NCT6796_TEMP_MASK 0xbfff0ffe 615*c3963bc0SZev Weiss #define NCT6796_VIRT_TEMP_MASK 0x80000c00 616*c3963bc0SZev Weiss 617*c3963bc0SZev Weiss static const u16 NCT6796_REG_TSI_TEMP[] = { 0x409, 0x40b }; 618*c3963bc0SZev Weiss 619*c3963bc0SZev Weiss static const char *const nct6798_temp_label[] = { 620*c3963bc0SZev Weiss "", 621*c3963bc0SZev Weiss "SYSTIN", 622*c3963bc0SZev Weiss "CPUTIN", 623*c3963bc0SZev Weiss "AUXTIN0", 624*c3963bc0SZev Weiss "AUXTIN1", 625*c3963bc0SZev Weiss "AUXTIN2", 626*c3963bc0SZev Weiss "AUXTIN3", 627*c3963bc0SZev Weiss "AUXTIN4", 628*c3963bc0SZev Weiss "SMBUSMASTER 0", 629*c3963bc0SZev Weiss "SMBUSMASTER 1", 630*c3963bc0SZev Weiss "Virtual_TEMP", 631*c3963bc0SZev Weiss "Virtual_TEMP", 632*c3963bc0SZev Weiss "", 633*c3963bc0SZev Weiss "", 634*c3963bc0SZev Weiss "", 635*c3963bc0SZev Weiss "", 636*c3963bc0SZev Weiss "PECI Agent 0", 637*c3963bc0SZev Weiss "PECI Agent 1", 638*c3963bc0SZev Weiss "PCH_CHIP_CPU_MAX_TEMP", 639*c3963bc0SZev Weiss "PCH_CHIP_TEMP", 640*c3963bc0SZev Weiss "PCH_CPU_TEMP", 641*c3963bc0SZev Weiss "PCH_MCH_TEMP", 642*c3963bc0SZev Weiss "Agent0 Dimm0", 643*c3963bc0SZev Weiss "Agent0 Dimm1", 644*c3963bc0SZev Weiss "Agent1 Dimm0", 645*c3963bc0SZev Weiss "Agent1 Dimm1", 646*c3963bc0SZev Weiss "BYTE_TEMP0", 647*c3963bc0SZev Weiss "BYTE_TEMP1", 648*c3963bc0SZev Weiss "PECI Agent 0 Calibration", /* undocumented */ 649*c3963bc0SZev Weiss "PECI Agent 1 Calibration", /* undocumented */ 650*c3963bc0SZev Weiss "", 651*c3963bc0SZev Weiss "Virtual_TEMP" 652*c3963bc0SZev Weiss }; 653*c3963bc0SZev Weiss 654*c3963bc0SZev Weiss #define NCT6798_TEMP_MASK 0xbfff0ffe 655*c3963bc0SZev Weiss #define NCT6798_VIRT_TEMP_MASK 0x80000c00 656*c3963bc0SZev Weiss 657*c3963bc0SZev Weiss /* NCT6102D/NCT6106D specific data */ 658*c3963bc0SZev Weiss 659*c3963bc0SZev Weiss #define NCT6106_REG_VBAT 0x318 660*c3963bc0SZev Weiss #define NCT6106_REG_DIODE 0x319 661*c3963bc0SZev Weiss #define NCT6106_DIODE_MASK 0x01 662*c3963bc0SZev Weiss 663*c3963bc0SZev Weiss static const u16 NCT6106_REG_IN_MAX[] = { 664*c3963bc0SZev Weiss 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 }; 665*c3963bc0SZev Weiss static const u16 NCT6106_REG_IN_MIN[] = { 666*c3963bc0SZev Weiss 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 }; 667*c3963bc0SZev Weiss static const u16 NCT6106_REG_IN[] = { 668*c3963bc0SZev Weiss 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 }; 669*c3963bc0SZev Weiss 670*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }; 671*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a }; 672*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_HYST[] = { 673*c3963bc0SZev Weiss 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 }; 674*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_OVER[] = { 675*c3963bc0SZev Weiss 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 }; 676*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CRIT_L[] = { 677*c3963bc0SZev Weiss 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 }; 678*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CRIT_H[] = { 679*c3963bc0SZev Weiss 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 }; 680*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 }; 681*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CONFIG[] = { 682*c3963bc0SZev Weiss 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc }; 683*c3963bc0SZev Weiss 684*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 }; 685*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 }; 686*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6 }; 687*c3963bc0SZev Weiss static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 }; 688*c3963bc0SZev Weiss 689*c3963bc0SZev Weiss static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 }; 690*c3963bc0SZev Weiss static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 }; 691*c3963bc0SZev Weiss static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c }; 692*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 }; 693*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_SOURCE[] = { 694*c3963bc0SZev Weiss 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 }; 695*c3963bc0SZev Weiss 696*c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a }; 697*c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = { 698*c3963bc0SZev Weiss 0x11b, 0x12b, 0x13b }; 699*c3963bc0SZev Weiss 700*c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c }; 701*c3963bc0SZev Weiss #define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10 702*c3963bc0SZev Weiss static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d }; 703*c3963bc0SZev Weiss 704*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 }; 705*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 }; 706*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 }; 707*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 }; 708*c3963bc0SZev Weiss static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 }; 709*c3963bc0SZev Weiss static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 }; 710*c3963bc0SZev Weiss 711*c3963bc0SZev Weiss static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 }; 712*c3963bc0SZev Weiss 713*c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 }; 714*c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 }; 715*c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a }; 716*c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b }; 717*c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c }; 718*c3963bc0SZev Weiss static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d }; 719*c3963bc0SZev Weiss 720*c3963bc0SZev Weiss static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 }; 721*c3963bc0SZev Weiss static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 }; 722*c3963bc0SZev Weiss 723*c3963bc0SZev Weiss static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = { 724*c3963bc0SZev Weiss 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d }; 725*c3963bc0SZev Weiss 726*c3963bc0SZev Weiss static const s8 NCT6106_ALARM_BITS[] = { 727*c3963bc0SZev Weiss 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */ 728*c3963bc0SZev Weiss 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */ 729*c3963bc0SZev Weiss -1, /* unused */ 730*c3963bc0SZev Weiss 32, 33, 34, -1, -1, /* fan1..fan5 */ 731*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 732*c3963bc0SZev Weiss 16, 17, 18, 19, 20, 21, /* temp1..temp6 */ 733*c3963bc0SZev Weiss 48, -1 /* intrusion0, intrusion1 */ 734*c3963bc0SZev Weiss }; 735*c3963bc0SZev Weiss 736*c3963bc0SZev Weiss static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = { 737*c3963bc0SZev Weiss 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 }; 738*c3963bc0SZev Weiss 739*c3963bc0SZev Weiss static const s8 NCT6106_BEEP_BITS[] = { 740*c3963bc0SZev Weiss 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */ 741*c3963bc0SZev Weiss 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */ 742*c3963bc0SZev Weiss 32, /* global beep enable */ 743*c3963bc0SZev Weiss 24, 25, 26, 27, 28, /* fan1..fan5 */ 744*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 745*c3963bc0SZev Weiss 16, 17, 18, 19, 20, 21, /* temp1..temp6 */ 746*c3963bc0SZev Weiss 34, -1 /* intrusion0, intrusion1 */ 747*c3963bc0SZev Weiss }; 748*c3963bc0SZev Weiss 749*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = { 750*c3963bc0SZev Weiss [14] = 0x51, 751*c3963bc0SZev Weiss [15] = 0x52, 752*c3963bc0SZev Weiss [16] = 0x54, 753*c3963bc0SZev Weiss }; 754*c3963bc0SZev Weiss 755*c3963bc0SZev Weiss static const u16 NCT6106_REG_TEMP_CRIT[32] = { 756*c3963bc0SZev Weiss [11] = 0x204, 757*c3963bc0SZev Weiss [12] = 0x205, 758*c3963bc0SZev Weiss }; 759*c3963bc0SZev Weiss 760*c3963bc0SZev Weiss static const u16 NCT6106_REG_TSI_TEMP[] = { 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65, 0x67 }; 761*c3963bc0SZev Weiss 762*c3963bc0SZev Weiss /* NCT6112D/NCT6114D/NCT6116D specific data */ 763*c3963bc0SZev Weiss 764*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 }; 765*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 }; 766*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 }; 767*c3963bc0SZev Weiss static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 }; 768*c3963bc0SZev Weiss 769*c3963bc0SZev Weiss static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 }; 770*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 }; 771*c3963bc0SZev Weiss static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 }; 772*c3963bc0SZev Weiss static const u16 NCT6116_REG_TEMP_SOURCE[] = { 773*c3963bc0SZev Weiss 0xb0, 0xb1, 0xb2 }; 774*c3963bc0SZev Weiss 775*c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_TEMP[] = { 776*c3963bc0SZev Weiss 0x11a, 0x12a, 0x13a, 0x19a, 0x1aa }; 777*c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = { 778*c3963bc0SZev Weiss 0x11b, 0x12b, 0x13b, 0x19b, 0x1ab }; 779*c3963bc0SZev Weiss 780*c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = { 781*c3963bc0SZev Weiss 0x11c, 0x12c, 0x13c, 0x19c, 0x1ac }; 782*c3963bc0SZev Weiss static const u16 NCT6116_REG_CRITICAL_PWM[] = { 783*c3963bc0SZev Weiss 0x11d, 0x12d, 0x13d, 0x19d, 0x1ad }; 784*c3963bc0SZev Weiss 785*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = { 786*c3963bc0SZev Weiss 0x114, 0x124, 0x134, 0x194, 0x1a4 }; 787*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = { 788*c3963bc0SZev Weiss 0x115, 0x125, 0x135, 0x195, 0x1a5 }; 789*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = { 790*c3963bc0SZev Weiss 0x116, 0x126, 0x136, 0x196, 0x1a6 }; 791*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_START_OUTPUT[] = { 792*c3963bc0SZev Weiss 0x117, 0x127, 0x137, 0x197, 0x1a7 }; 793*c3963bc0SZev Weiss static const u16 NCT6116_REG_FAN_STOP_TIME[] = { 794*c3963bc0SZev Weiss 0x118, 0x128, 0x138, 0x198, 0x1a8 }; 795*c3963bc0SZev Weiss static const u16 NCT6116_REG_TOLERANCE_H[] = { 796*c3963bc0SZev Weiss 0x112, 0x122, 0x132, 0x192, 0x1a2 }; 797*c3963bc0SZev Weiss 798*c3963bc0SZev Weiss static const u16 NCT6116_REG_TARGET[] = { 799*c3963bc0SZev Weiss 0x111, 0x121, 0x131, 0x191, 0x1a1 }; 800*c3963bc0SZev Weiss 801*c3963bc0SZev Weiss static const u16 NCT6116_REG_AUTO_TEMP[] = { 802*c3963bc0SZev Weiss 0x160, 0x170, 0x180, 0x1d0, 0x1e0 }; 803*c3963bc0SZev Weiss static const u16 NCT6116_REG_AUTO_PWM[] = { 804*c3963bc0SZev Weiss 0x164, 0x174, 0x184, 0x1d4, 0x1e4 }; 805*c3963bc0SZev Weiss 806*c3963bc0SZev Weiss static const s8 NCT6116_ALARM_BITS[] = { 807*c3963bc0SZev Weiss 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */ 808*c3963bc0SZev Weiss 9, -1, -1, -1, -1, -1, -1, /* in8..in9 */ 809*c3963bc0SZev Weiss -1, /* unused */ 810*c3963bc0SZev Weiss 32, 33, 34, 35, 36, /* fan1..fan5 */ 811*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 812*c3963bc0SZev Weiss 16, 17, 18, -1, -1, -1, /* temp1..temp6 */ 813*c3963bc0SZev Weiss 48, -1 /* intrusion0, intrusion1 */ 814*c3963bc0SZev Weiss }; 815*c3963bc0SZev Weiss 816*c3963bc0SZev Weiss static const s8 NCT6116_BEEP_BITS[] = { 817*c3963bc0SZev Weiss 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */ 818*c3963bc0SZev Weiss 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */ 819*c3963bc0SZev Weiss 32, /* global beep enable */ 820*c3963bc0SZev Weiss 24, 25, 26, 27, 28, /* fan1..fan5 */ 821*c3963bc0SZev Weiss -1, -1, -1, /* unused */ 822*c3963bc0SZev Weiss 16, 17, 18, -1, -1, -1, /* temp1..temp6 */ 823*c3963bc0SZev Weiss 34, -1 /* intrusion0, intrusion1 */ 824*c3963bc0SZev Weiss }; 825*c3963bc0SZev Weiss 826*c3963bc0SZev Weiss static const u16 NCT6116_REG_TSI_TEMP[] = { 0x59, 0x5b }; 827*c3963bc0SZev Weiss 828*c3963bc0SZev Weiss static enum pwm_enable reg_to_pwm_enable(int pwm, int mode) 829*c3963bc0SZev Weiss { 830*c3963bc0SZev Weiss if (mode == 0 && pwm == 255) 831*c3963bc0SZev Weiss return off; 832*c3963bc0SZev Weiss return mode + 1; 833*c3963bc0SZev Weiss } 834*c3963bc0SZev Weiss 835*c3963bc0SZev Weiss static int pwm_enable_to_reg(enum pwm_enable mode) 836*c3963bc0SZev Weiss { 837*c3963bc0SZev Weiss if (mode == off) 838*c3963bc0SZev Weiss return 0; 839*c3963bc0SZev Weiss return mode - 1; 840*c3963bc0SZev Weiss } 841*c3963bc0SZev Weiss 842*c3963bc0SZev Weiss /* 843*c3963bc0SZev Weiss * Conversions 844*c3963bc0SZev Weiss */ 845*c3963bc0SZev Weiss 846*c3963bc0SZev Weiss /* 1 is DC mode, output in ms */ 847*c3963bc0SZev Weiss static unsigned int step_time_from_reg(u8 reg, u8 mode) 848*c3963bc0SZev Weiss { 849*c3963bc0SZev Weiss return mode ? 400 * reg : 100 * reg; 850*c3963bc0SZev Weiss } 851*c3963bc0SZev Weiss 852*c3963bc0SZev Weiss static u8 step_time_to_reg(unsigned int msec, u8 mode) 853*c3963bc0SZev Weiss { 854*c3963bc0SZev Weiss return clamp_val((mode ? (msec + 200) / 400 : 855*c3963bc0SZev Weiss (msec + 50) / 100), 1, 255); 856*c3963bc0SZev Weiss } 857*c3963bc0SZev Weiss 858*c3963bc0SZev Weiss static unsigned int fan_from_reg8(u16 reg, unsigned int divreg) 859*c3963bc0SZev Weiss { 860*c3963bc0SZev Weiss if (reg == 0 || reg == 255) 861*c3963bc0SZev Weiss return 0; 862*c3963bc0SZev Weiss return 1350000U / (reg << divreg); 863*c3963bc0SZev Weiss } 864*c3963bc0SZev Weiss 865*c3963bc0SZev Weiss static unsigned int fan_from_reg13(u16 reg, unsigned int divreg) 866*c3963bc0SZev Weiss { 867*c3963bc0SZev Weiss if ((reg & 0xff1f) == 0xff1f) 868*c3963bc0SZev Weiss return 0; 869*c3963bc0SZev Weiss 870*c3963bc0SZev Weiss reg = (reg & 0x1f) | ((reg & 0xff00) >> 3); 871*c3963bc0SZev Weiss 872*c3963bc0SZev Weiss if (reg == 0) 873*c3963bc0SZev Weiss return 0; 874*c3963bc0SZev Weiss 875*c3963bc0SZev Weiss return 1350000U / reg; 876*c3963bc0SZev Weiss } 877*c3963bc0SZev Weiss 878*c3963bc0SZev Weiss static unsigned int fan_from_reg16(u16 reg, unsigned int divreg) 879*c3963bc0SZev Weiss { 880*c3963bc0SZev Weiss if (reg == 0 || reg == 0xffff) 881*c3963bc0SZev Weiss return 0; 882*c3963bc0SZev Weiss 883*c3963bc0SZev Weiss /* 884*c3963bc0SZev Weiss * Even though the registers are 16 bit wide, the fan divisor 885*c3963bc0SZev Weiss * still applies. 886*c3963bc0SZev Weiss */ 887*c3963bc0SZev Weiss return 1350000U / (reg << divreg); 888*c3963bc0SZev Weiss } 889*c3963bc0SZev Weiss 890*c3963bc0SZev Weiss static unsigned int fan_from_reg_rpm(u16 reg, unsigned int divreg) 891*c3963bc0SZev Weiss { 892*c3963bc0SZev Weiss return reg; 893*c3963bc0SZev Weiss } 894*c3963bc0SZev Weiss 895*c3963bc0SZev Weiss static u16 fan_to_reg(u32 fan, unsigned int divreg) 896*c3963bc0SZev Weiss { 897*c3963bc0SZev Weiss if (!fan) 898*c3963bc0SZev Weiss return 0; 899*c3963bc0SZev Weiss 900*c3963bc0SZev Weiss return (1350000U / fan) >> divreg; 901*c3963bc0SZev Weiss } 902*c3963bc0SZev Weiss 903*c3963bc0SZev Weiss static inline unsigned int 904*c3963bc0SZev Weiss div_from_reg(u8 reg) 905*c3963bc0SZev Weiss { 906*c3963bc0SZev Weiss return BIT(reg); 907*c3963bc0SZev Weiss } 908*c3963bc0SZev Weiss 909*c3963bc0SZev Weiss /* 910*c3963bc0SZev Weiss * Some of the voltage inputs have internal scaling, the tables below 911*c3963bc0SZev Weiss * contain 8 (the ADC LSB in mV) * scaling factor * 100 912*c3963bc0SZev Weiss */ 913*c3963bc0SZev Weiss static const u16 scale_in[15] = { 914*c3963bc0SZev Weiss 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800, 915*c3963bc0SZev Weiss 800, 800 916*c3963bc0SZev Weiss }; 917*c3963bc0SZev Weiss 918*c3963bc0SZev Weiss static inline long in_from_reg(u8 reg, u8 nr) 919*c3963bc0SZev Weiss { 920*c3963bc0SZev Weiss return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100); 921*c3963bc0SZev Weiss } 922*c3963bc0SZev Weiss 923*c3963bc0SZev Weiss static inline u8 in_to_reg(u32 val, u8 nr) 924*c3963bc0SZev Weiss { 925*c3963bc0SZev Weiss return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255); 926*c3963bc0SZev Weiss } 927*c3963bc0SZev Weiss 928*c3963bc0SZev Weiss /* TSI temperatures are in 8.3 format */ 929*c3963bc0SZev Weiss static inline unsigned int tsi_temp_from_reg(unsigned int reg) 930*c3963bc0SZev Weiss { 931*c3963bc0SZev Weiss return (reg >> 5) * 125; 932*c3963bc0SZev Weiss } 933*c3963bc0SZev Weiss 934*c3963bc0SZev Weiss /* 935*c3963bc0SZev Weiss * Data structures and manipulation thereof 936*c3963bc0SZev Weiss */ 937*c3963bc0SZev Weiss 938*c3963bc0SZev Weiss struct sensor_device_template { 939*c3963bc0SZev Weiss struct device_attribute dev_attr; 940*c3963bc0SZev Weiss union { 941*c3963bc0SZev Weiss struct { 942*c3963bc0SZev Weiss u8 nr; 943*c3963bc0SZev Weiss u8 index; 944*c3963bc0SZev Weiss } s; 945*c3963bc0SZev Weiss int index; 946*c3963bc0SZev Weiss } u; 947*c3963bc0SZev Weiss bool s2; /* true if both index and nr are used */ 948*c3963bc0SZev Weiss }; 949*c3963bc0SZev Weiss 950*c3963bc0SZev Weiss struct sensor_device_attr_u { 951*c3963bc0SZev Weiss union { 952*c3963bc0SZev Weiss struct sensor_device_attribute a1; 953*c3963bc0SZev Weiss struct sensor_device_attribute_2 a2; 954*c3963bc0SZev Weiss } u; 955*c3963bc0SZev Weiss char name[32]; 956*c3963bc0SZev Weiss }; 957*c3963bc0SZev Weiss 958*c3963bc0SZev Weiss #define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \ 959*c3963bc0SZev Weiss .attr = {.name = _template, .mode = _mode }, \ 960*c3963bc0SZev Weiss .show = _show, \ 961*c3963bc0SZev Weiss .store = _store, \ 962*c3963bc0SZev Weiss } 963*c3963bc0SZev Weiss 964*c3963bc0SZev Weiss #define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \ 965*c3963bc0SZev Weiss { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \ 966*c3963bc0SZev Weiss .u.index = _index, \ 967*c3963bc0SZev Weiss .s2 = false } 968*c3963bc0SZev Weiss 969*c3963bc0SZev Weiss #define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \ 970*c3963bc0SZev Weiss _nr, _index) \ 971*c3963bc0SZev Weiss { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \ 972*c3963bc0SZev Weiss .u.s.index = _index, \ 973*c3963bc0SZev Weiss .u.s.nr = _nr, \ 974*c3963bc0SZev Weiss .s2 = true } 975*c3963bc0SZev Weiss 976*c3963bc0SZev Weiss #define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \ 977*c3963bc0SZev Weiss static struct sensor_device_template sensor_dev_template_##_name \ 978*c3963bc0SZev Weiss = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \ 979*c3963bc0SZev Weiss _index) 980*c3963bc0SZev Weiss 981*c3963bc0SZev Weiss #define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \ 982*c3963bc0SZev Weiss _nr, _index) \ 983*c3963bc0SZev Weiss static struct sensor_device_template sensor_dev_template_##_name \ 984*c3963bc0SZev Weiss = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \ 985*c3963bc0SZev Weiss _nr, _index) 986*c3963bc0SZev Weiss 987*c3963bc0SZev Weiss struct sensor_template_group { 988*c3963bc0SZev Weiss struct sensor_device_template **templates; 989*c3963bc0SZev Weiss umode_t (*is_visible)(struct kobject *, struct attribute *, int); 990*c3963bc0SZev Weiss int base; 991*c3963bc0SZev Weiss }; 992*c3963bc0SZev Weiss 993*c3963bc0SZev Weiss static int nct6775_add_template_attr_group(struct device *dev, struct nct6775_data *data, 994*c3963bc0SZev Weiss const struct sensor_template_group *tg, int repeat) 995*c3963bc0SZev Weiss { 996*c3963bc0SZev Weiss struct attribute_group *group; 997*c3963bc0SZev Weiss struct sensor_device_attr_u *su; 998*c3963bc0SZev Weiss struct sensor_device_attribute *a; 999*c3963bc0SZev Weiss struct sensor_device_attribute_2 *a2; 1000*c3963bc0SZev Weiss struct attribute **attrs; 1001*c3963bc0SZev Weiss struct sensor_device_template **t; 1002*c3963bc0SZev Weiss int i, count; 1003*c3963bc0SZev Weiss 1004*c3963bc0SZev Weiss if (repeat <= 0) 1005*c3963bc0SZev Weiss return -EINVAL; 1006*c3963bc0SZev Weiss 1007*c3963bc0SZev Weiss t = tg->templates; 1008*c3963bc0SZev Weiss for (count = 0; *t; t++, count++) 1009*c3963bc0SZev Weiss ; 1010*c3963bc0SZev Weiss 1011*c3963bc0SZev Weiss if (count == 0) 1012*c3963bc0SZev Weiss return -EINVAL; 1013*c3963bc0SZev Weiss 1014*c3963bc0SZev Weiss group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL); 1015*c3963bc0SZev Weiss if (group == NULL) 1016*c3963bc0SZev Weiss return -ENOMEM; 1017*c3963bc0SZev Weiss 1018*c3963bc0SZev Weiss attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs), 1019*c3963bc0SZev Weiss GFP_KERNEL); 1020*c3963bc0SZev Weiss if (attrs == NULL) 1021*c3963bc0SZev Weiss return -ENOMEM; 1022*c3963bc0SZev Weiss 1023*c3963bc0SZev Weiss su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)), 1024*c3963bc0SZev Weiss GFP_KERNEL); 1025*c3963bc0SZev Weiss if (su == NULL) 1026*c3963bc0SZev Weiss return -ENOMEM; 1027*c3963bc0SZev Weiss 1028*c3963bc0SZev Weiss group->attrs = attrs; 1029*c3963bc0SZev Weiss group->is_visible = tg->is_visible; 1030*c3963bc0SZev Weiss 1031*c3963bc0SZev Weiss for (i = 0; i < repeat; i++) { 1032*c3963bc0SZev Weiss t = tg->templates; 1033*c3963bc0SZev Weiss while (*t != NULL) { 1034*c3963bc0SZev Weiss snprintf(su->name, sizeof(su->name), 1035*c3963bc0SZev Weiss (*t)->dev_attr.attr.name, tg->base + i); 1036*c3963bc0SZev Weiss if ((*t)->s2) { 1037*c3963bc0SZev Weiss a2 = &su->u.a2; 1038*c3963bc0SZev Weiss sysfs_attr_init(&a2->dev_attr.attr); 1039*c3963bc0SZev Weiss a2->dev_attr.attr.name = su->name; 1040*c3963bc0SZev Weiss a2->nr = (*t)->u.s.nr + i; 1041*c3963bc0SZev Weiss a2->index = (*t)->u.s.index; 1042*c3963bc0SZev Weiss a2->dev_attr.attr.mode = 1043*c3963bc0SZev Weiss (*t)->dev_attr.attr.mode; 1044*c3963bc0SZev Weiss a2->dev_attr.show = (*t)->dev_attr.show; 1045*c3963bc0SZev Weiss a2->dev_attr.store = (*t)->dev_attr.store; 1046*c3963bc0SZev Weiss *attrs = &a2->dev_attr.attr; 1047*c3963bc0SZev Weiss } else { 1048*c3963bc0SZev Weiss a = &su->u.a1; 1049*c3963bc0SZev Weiss sysfs_attr_init(&a->dev_attr.attr); 1050*c3963bc0SZev Weiss a->dev_attr.attr.name = su->name; 1051*c3963bc0SZev Weiss a->index = (*t)->u.index + i; 1052*c3963bc0SZev Weiss a->dev_attr.attr.mode = 1053*c3963bc0SZev Weiss (*t)->dev_attr.attr.mode; 1054*c3963bc0SZev Weiss a->dev_attr.show = (*t)->dev_attr.show; 1055*c3963bc0SZev Weiss a->dev_attr.store = (*t)->dev_attr.store; 1056*c3963bc0SZev Weiss *attrs = &a->dev_attr.attr; 1057*c3963bc0SZev Weiss } 1058*c3963bc0SZev Weiss attrs++; 1059*c3963bc0SZev Weiss su++; 1060*c3963bc0SZev Weiss t++; 1061*c3963bc0SZev Weiss } 1062*c3963bc0SZev Weiss } 1063*c3963bc0SZev Weiss 1064*c3963bc0SZev Weiss return nct6775_add_attr_group(data, group); 1065*c3963bc0SZev Weiss } 1066*c3963bc0SZev Weiss 1067*c3963bc0SZev Weiss bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg) 1068*c3963bc0SZev Weiss { 1069*c3963bc0SZev Weiss switch (data->kind) { 1070*c3963bc0SZev Weiss case nct6106: 1071*c3963bc0SZev Weiss return reg == 0x20 || reg == 0x22 || reg == 0x24 || 1072*c3963bc0SZev Weiss (reg >= 0x59 && reg < 0x69 && (reg & 1)) || 1073*c3963bc0SZev Weiss reg == 0xe0 || reg == 0xe2 || reg == 0xe4 || 1074*c3963bc0SZev Weiss reg == 0x111 || reg == 0x121 || reg == 0x131; 1075*c3963bc0SZev Weiss case nct6116: 1076*c3963bc0SZev Weiss return reg == 0x20 || reg == 0x22 || reg == 0x24 || 1077*c3963bc0SZev Weiss reg == 0x26 || reg == 0x28 || reg == 0x59 || reg == 0x5b || 1078*c3963bc0SZev Weiss reg == 0xe0 || reg == 0xe2 || reg == 0xe4 || reg == 0xe6 || 1079*c3963bc0SZev Weiss reg == 0xe8 || reg == 0x111 || reg == 0x121 || reg == 0x131 || 1080*c3963bc0SZev Weiss reg == 0x191 || reg == 0x1a1; 1081*c3963bc0SZev Weiss case nct6775: 1082*c3963bc0SZev Weiss return (((reg & 0xff00) == 0x100 || 1083*c3963bc0SZev Weiss (reg & 0xff00) == 0x200) && 1084*c3963bc0SZev Weiss ((reg & 0x00ff) == 0x50 || 1085*c3963bc0SZev Weiss (reg & 0x00ff) == 0x53 || 1086*c3963bc0SZev Weiss (reg & 0x00ff) == 0x55)) || 1087*c3963bc0SZev Weiss (reg & 0xfff0) == 0x630 || 1088*c3963bc0SZev Weiss reg == 0x640 || reg == 0x642 || 1089*c3963bc0SZev Weiss reg == 0x662 || reg == 0x669 || 1090*c3963bc0SZev Weiss ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) || 1091*c3963bc0SZev Weiss reg == 0x73 || reg == 0x75 || reg == 0x77; 1092*c3963bc0SZev Weiss case nct6776: 1093*c3963bc0SZev Weiss return (((reg & 0xff00) == 0x100 || 1094*c3963bc0SZev Weiss (reg & 0xff00) == 0x200) && 1095*c3963bc0SZev Weiss ((reg & 0x00ff) == 0x50 || 1096*c3963bc0SZev Weiss (reg & 0x00ff) == 0x53 || 1097*c3963bc0SZev Weiss (reg & 0x00ff) == 0x55)) || 1098*c3963bc0SZev Weiss (reg & 0xfff0) == 0x630 || 1099*c3963bc0SZev Weiss reg == 0x402 || 1100*c3963bc0SZev Weiss (reg >= 0x409 && reg < 0x419 && (reg & 1)) || 1101*c3963bc0SZev Weiss reg == 0x640 || reg == 0x642 || 1102*c3963bc0SZev Weiss ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) || 1103*c3963bc0SZev Weiss reg == 0x73 || reg == 0x75 || reg == 0x77; 1104*c3963bc0SZev Weiss case nct6779: 1105*c3963bc0SZev Weiss case nct6791: 1106*c3963bc0SZev Weiss case nct6792: 1107*c3963bc0SZev Weiss case nct6793: 1108*c3963bc0SZev Weiss case nct6795: 1109*c3963bc0SZev Weiss case nct6796: 1110*c3963bc0SZev Weiss case nct6797: 1111*c3963bc0SZev Weiss case nct6798: 1112*c3963bc0SZev Weiss return reg == 0x150 || reg == 0x153 || reg == 0x155 || 1113*c3963bc0SZev Weiss (reg & 0xfff0) == 0x4c0 || 1114*c3963bc0SZev Weiss reg == 0x402 || 1115*c3963bc0SZev Weiss (reg >= 0x409 && reg < 0x419 && (reg & 1)) || 1116*c3963bc0SZev Weiss reg == 0x63a || reg == 0x63c || reg == 0x63e || 1117*c3963bc0SZev Weiss reg == 0x640 || reg == 0x642 || reg == 0x64a || 1118*c3963bc0SZev Weiss reg == 0x64c || 1119*c3963bc0SZev Weiss reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 || 1120*c3963bc0SZev Weiss reg == 0x7b || reg == 0x7d; 1121*c3963bc0SZev Weiss } 1122*c3963bc0SZev Weiss return false; 1123*c3963bc0SZev Weiss } 1124*c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_reg_is_word_sized); 1125*c3963bc0SZev Weiss 1126*c3963bc0SZev Weiss /* We left-align 8-bit temperature values to make the code simpler */ 1127*c3963bc0SZev Weiss static int nct6775_read_temp(struct nct6775_data *data, u16 reg, u16 *val) 1128*c3963bc0SZev Weiss { 1129*c3963bc0SZev Weiss int err; 1130*c3963bc0SZev Weiss 1131*c3963bc0SZev Weiss err = nct6775_read_value(data, reg, val); 1132*c3963bc0SZev Weiss if (err) 1133*c3963bc0SZev Weiss return err; 1134*c3963bc0SZev Weiss 1135*c3963bc0SZev Weiss if (!nct6775_reg_is_word_sized(data, reg)) 1136*c3963bc0SZev Weiss *val <<= 8; 1137*c3963bc0SZev Weiss 1138*c3963bc0SZev Weiss return 0; 1139*c3963bc0SZev Weiss } 1140*c3963bc0SZev Weiss 1141*c3963bc0SZev Weiss /* This function assumes that the caller holds data->update_lock */ 1142*c3963bc0SZev Weiss static int nct6775_write_fan_div(struct nct6775_data *data, int nr) 1143*c3963bc0SZev Weiss { 1144*c3963bc0SZev Weiss u16 reg; 1145*c3963bc0SZev Weiss int err; 1146*c3963bc0SZev Weiss u16 fandiv_reg = nr < 2 ? NCT6775_REG_FANDIV1 : NCT6775_REG_FANDIV2; 1147*c3963bc0SZev Weiss unsigned int oddshift = (nr & 1) * 4; /* masks shift by four if nr is odd */ 1148*c3963bc0SZev Weiss 1149*c3963bc0SZev Weiss err = nct6775_read_value(data, fandiv_reg, ®); 1150*c3963bc0SZev Weiss if (err) 1151*c3963bc0SZev Weiss return err; 1152*c3963bc0SZev Weiss reg &= 0x70 >> oddshift; 1153*c3963bc0SZev Weiss reg |= data->fan_div[nr] & (0x7 << oddshift); 1154*c3963bc0SZev Weiss return nct6775_write_value(data, fandiv_reg, reg); 1155*c3963bc0SZev Weiss } 1156*c3963bc0SZev Weiss 1157*c3963bc0SZev Weiss static int nct6775_write_fan_div_common(struct nct6775_data *data, int nr) 1158*c3963bc0SZev Weiss { 1159*c3963bc0SZev Weiss if (data->kind == nct6775) 1160*c3963bc0SZev Weiss return nct6775_write_fan_div(data, nr); 1161*c3963bc0SZev Weiss return 0; 1162*c3963bc0SZev Weiss } 1163*c3963bc0SZev Weiss 1164*c3963bc0SZev Weiss static int nct6775_update_fan_div(struct nct6775_data *data) 1165*c3963bc0SZev Weiss { 1166*c3963bc0SZev Weiss int err; 1167*c3963bc0SZev Weiss u16 i; 1168*c3963bc0SZev Weiss 1169*c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_FANDIV1, &i); 1170*c3963bc0SZev Weiss if (err) 1171*c3963bc0SZev Weiss return err; 1172*c3963bc0SZev Weiss data->fan_div[0] = i & 0x7; 1173*c3963bc0SZev Weiss data->fan_div[1] = (i & 0x70) >> 4; 1174*c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_FANDIV2, &i); 1175*c3963bc0SZev Weiss if (err) 1176*c3963bc0SZev Weiss return err; 1177*c3963bc0SZev Weiss data->fan_div[2] = i & 0x7; 1178*c3963bc0SZev Weiss if (data->has_fan & BIT(3)) 1179*c3963bc0SZev Weiss data->fan_div[3] = (i & 0x70) >> 4; 1180*c3963bc0SZev Weiss 1181*c3963bc0SZev Weiss return 0; 1182*c3963bc0SZev Weiss } 1183*c3963bc0SZev Weiss 1184*c3963bc0SZev Weiss static int nct6775_update_fan_div_common(struct nct6775_data *data) 1185*c3963bc0SZev Weiss { 1186*c3963bc0SZev Weiss if (data->kind == nct6775) 1187*c3963bc0SZev Weiss return nct6775_update_fan_div(data); 1188*c3963bc0SZev Weiss return 0; 1189*c3963bc0SZev Weiss } 1190*c3963bc0SZev Weiss 1191*c3963bc0SZev Weiss static int nct6775_init_fan_div(struct nct6775_data *data) 1192*c3963bc0SZev Weiss { 1193*c3963bc0SZev Weiss int i, err; 1194*c3963bc0SZev Weiss 1195*c3963bc0SZev Weiss err = nct6775_update_fan_div_common(data); 1196*c3963bc0SZev Weiss if (err) 1197*c3963bc0SZev Weiss return err; 1198*c3963bc0SZev Weiss 1199*c3963bc0SZev Weiss /* 1200*c3963bc0SZev Weiss * For all fans, start with highest divider value if the divider 1201*c3963bc0SZev Weiss * register is not initialized. This ensures that we get a 1202*c3963bc0SZev Weiss * reading from the fan count register, even if it is not optimal. 1203*c3963bc0SZev Weiss * We'll compute a better divider later on. 1204*c3963bc0SZev Weiss */ 1205*c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) { 1206*c3963bc0SZev Weiss if (!(data->has_fan & BIT(i))) 1207*c3963bc0SZev Weiss continue; 1208*c3963bc0SZev Weiss if (data->fan_div[i] == 0) { 1209*c3963bc0SZev Weiss data->fan_div[i] = 7; 1210*c3963bc0SZev Weiss err = nct6775_write_fan_div_common(data, i); 1211*c3963bc0SZev Weiss if (err) 1212*c3963bc0SZev Weiss return err; 1213*c3963bc0SZev Weiss } 1214*c3963bc0SZev Weiss } 1215*c3963bc0SZev Weiss 1216*c3963bc0SZev Weiss return 0; 1217*c3963bc0SZev Weiss } 1218*c3963bc0SZev Weiss 1219*c3963bc0SZev Weiss static int nct6775_init_fan_common(struct device *dev, 1220*c3963bc0SZev Weiss struct nct6775_data *data) 1221*c3963bc0SZev Weiss { 1222*c3963bc0SZev Weiss int i, err; 1223*c3963bc0SZev Weiss u16 reg; 1224*c3963bc0SZev Weiss 1225*c3963bc0SZev Weiss if (data->has_fan_div) { 1226*c3963bc0SZev Weiss err = nct6775_init_fan_div(data); 1227*c3963bc0SZev Weiss if (err) 1228*c3963bc0SZev Weiss return err; 1229*c3963bc0SZev Weiss } 1230*c3963bc0SZev Weiss 1231*c3963bc0SZev Weiss /* 1232*c3963bc0SZev Weiss * If fan_min is not set (0), set it to 0xff to disable it. This 1233*c3963bc0SZev Weiss * prevents the unnecessary warning when fanX_min is reported as 0. 1234*c3963bc0SZev Weiss */ 1235*c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { 1236*c3963bc0SZev Weiss if (data->has_fan_min & BIT(i)) { 1237*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_MIN[i], ®); 1238*c3963bc0SZev Weiss if (err) 1239*c3963bc0SZev Weiss return err; 1240*c3963bc0SZev Weiss if (!reg) { 1241*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MIN[i], 1242*c3963bc0SZev Weiss data->has_fan_div ? 0xff : 0xff1f); 1243*c3963bc0SZev Weiss if (err) 1244*c3963bc0SZev Weiss return err; 1245*c3963bc0SZev Weiss } 1246*c3963bc0SZev Weiss } 1247*c3963bc0SZev Weiss } 1248*c3963bc0SZev Weiss 1249*c3963bc0SZev Weiss return 0; 1250*c3963bc0SZev Weiss } 1251*c3963bc0SZev Weiss 1252*c3963bc0SZev Weiss static int nct6775_select_fan_div(struct device *dev, 1253*c3963bc0SZev Weiss struct nct6775_data *data, int nr, u16 reg) 1254*c3963bc0SZev Weiss { 1255*c3963bc0SZev Weiss int err; 1256*c3963bc0SZev Weiss u8 fan_div = data->fan_div[nr]; 1257*c3963bc0SZev Weiss u16 fan_min; 1258*c3963bc0SZev Weiss 1259*c3963bc0SZev Weiss if (!data->has_fan_div) 1260*c3963bc0SZev Weiss return 0; 1261*c3963bc0SZev Weiss 1262*c3963bc0SZev Weiss /* 1263*c3963bc0SZev Weiss * If we failed to measure the fan speed, or the reported value is not 1264*c3963bc0SZev Weiss * in the optimal range, and the clock divider can be modified, 1265*c3963bc0SZev Weiss * let's try that for next time. 1266*c3963bc0SZev Weiss */ 1267*c3963bc0SZev Weiss if (reg == 0x00 && fan_div < 0x07) 1268*c3963bc0SZev Weiss fan_div++; 1269*c3963bc0SZev Weiss else if (reg != 0x00 && reg < 0x30 && fan_div > 0) 1270*c3963bc0SZev Weiss fan_div--; 1271*c3963bc0SZev Weiss 1272*c3963bc0SZev Weiss if (fan_div != data->fan_div[nr]) { 1273*c3963bc0SZev Weiss dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n", 1274*c3963bc0SZev Weiss nr + 1, div_from_reg(data->fan_div[nr]), 1275*c3963bc0SZev Weiss div_from_reg(fan_div)); 1276*c3963bc0SZev Weiss 1277*c3963bc0SZev Weiss /* Preserve min limit if possible */ 1278*c3963bc0SZev Weiss if (data->has_fan_min & BIT(nr)) { 1279*c3963bc0SZev Weiss fan_min = data->fan_min[nr]; 1280*c3963bc0SZev Weiss if (fan_div > data->fan_div[nr]) { 1281*c3963bc0SZev Weiss if (fan_min != 255 && fan_min > 1) 1282*c3963bc0SZev Weiss fan_min >>= 1; 1283*c3963bc0SZev Weiss } else { 1284*c3963bc0SZev Weiss if (fan_min != 255) { 1285*c3963bc0SZev Weiss fan_min <<= 1; 1286*c3963bc0SZev Weiss if (fan_min > 254) 1287*c3963bc0SZev Weiss fan_min = 254; 1288*c3963bc0SZev Weiss } 1289*c3963bc0SZev Weiss } 1290*c3963bc0SZev Weiss if (fan_min != data->fan_min[nr]) { 1291*c3963bc0SZev Weiss data->fan_min[nr] = fan_min; 1292*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MIN[nr], fan_min); 1293*c3963bc0SZev Weiss if (err) 1294*c3963bc0SZev Weiss return err; 1295*c3963bc0SZev Weiss } 1296*c3963bc0SZev Weiss } 1297*c3963bc0SZev Weiss data->fan_div[nr] = fan_div; 1298*c3963bc0SZev Weiss err = nct6775_write_fan_div_common(data, nr); 1299*c3963bc0SZev Weiss if (err) 1300*c3963bc0SZev Weiss return err; 1301*c3963bc0SZev Weiss } 1302*c3963bc0SZev Weiss 1303*c3963bc0SZev Weiss return 0; 1304*c3963bc0SZev Weiss } 1305*c3963bc0SZev Weiss 1306*c3963bc0SZev Weiss static int nct6775_update_pwm(struct device *dev) 1307*c3963bc0SZev Weiss { 1308*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1309*c3963bc0SZev Weiss int i, j, err; 1310*c3963bc0SZev Weiss u16 fanmodecfg, reg; 1311*c3963bc0SZev Weiss bool duty_is_dc; 1312*c3963bc0SZev Weiss 1313*c3963bc0SZev Weiss for (i = 0; i < data->pwm_num; i++) { 1314*c3963bc0SZev Weiss if (!(data->has_pwm & BIT(i))) 1315*c3963bc0SZev Weiss continue; 1316*c3963bc0SZev Weiss 1317*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_PWM_MODE[i], ®); 1318*c3963bc0SZev Weiss if (err) 1319*c3963bc0SZev Weiss return err; 1320*c3963bc0SZev Weiss duty_is_dc = data->REG_PWM_MODE[i] && (reg & data->PWM_MODE_MASK[i]); 1321*c3963bc0SZev Weiss data->pwm_mode[i] = !duty_is_dc; 1322*c3963bc0SZev Weiss 1323*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_MODE[i], &fanmodecfg); 1324*c3963bc0SZev Weiss if (err) 1325*c3963bc0SZev Weiss return err; 1326*c3963bc0SZev Weiss for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) { 1327*c3963bc0SZev Weiss if (data->REG_PWM[j] && data->REG_PWM[j][i]) { 1328*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_PWM[j][i], ®); 1329*c3963bc0SZev Weiss if (err) 1330*c3963bc0SZev Weiss return err; 1331*c3963bc0SZev Weiss data->pwm[j][i] = reg; 1332*c3963bc0SZev Weiss } 1333*c3963bc0SZev Weiss } 1334*c3963bc0SZev Weiss 1335*c3963bc0SZev Weiss data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i], 1336*c3963bc0SZev Weiss (fanmodecfg >> 4) & 7); 1337*c3963bc0SZev Weiss 1338*c3963bc0SZev Weiss if (!data->temp_tolerance[0][i] || 1339*c3963bc0SZev Weiss data->pwm_enable[i] != speed_cruise) 1340*c3963bc0SZev Weiss data->temp_tolerance[0][i] = fanmodecfg & 0x0f; 1341*c3963bc0SZev Weiss if (!data->target_speed_tolerance[i] || 1342*c3963bc0SZev Weiss data->pwm_enable[i] == speed_cruise) { 1343*c3963bc0SZev Weiss u8 t = fanmodecfg & 0x0f; 1344*c3963bc0SZev Weiss 1345*c3963bc0SZev Weiss if (data->REG_TOLERANCE_H) { 1346*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TOLERANCE_H[i], ®); 1347*c3963bc0SZev Weiss if (err) 1348*c3963bc0SZev Weiss return err; 1349*c3963bc0SZev Weiss t |= (reg & 0x70) >> 1; 1350*c3963bc0SZev Weiss } 1351*c3963bc0SZev Weiss data->target_speed_tolerance[i] = t; 1352*c3963bc0SZev Weiss } 1353*c3963bc0SZev Weiss 1354*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_CRITICAL_TEMP_TOLERANCE[i], ®); 1355*c3963bc0SZev Weiss if (err) 1356*c3963bc0SZev Weiss return err; 1357*c3963bc0SZev Weiss data->temp_tolerance[1][i] = reg; 1358*c3963bc0SZev Weiss 1359*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SEL[i], ®); 1360*c3963bc0SZev Weiss if (err) 1361*c3963bc0SZev Weiss return err; 1362*c3963bc0SZev Weiss data->pwm_temp_sel[i] = reg & 0x1f; 1363*c3963bc0SZev Weiss /* If fan can stop, report floor as 0 */ 1364*c3963bc0SZev Weiss if (reg & 0x80) 1365*c3963bc0SZev Weiss data->pwm[2][i] = 0; 1366*c3963bc0SZev Weiss 1367*c3963bc0SZev Weiss if (!data->REG_WEIGHT_TEMP_SEL[i]) 1368*c3963bc0SZev Weiss continue; 1369*c3963bc0SZev Weiss 1370*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i], ®); 1371*c3963bc0SZev Weiss if (err) 1372*c3963bc0SZev Weiss return err; 1373*c3963bc0SZev Weiss data->pwm_weight_temp_sel[i] = reg & 0x1f; 1374*c3963bc0SZev Weiss /* If weight is disabled, report weight source as 0 */ 1375*c3963bc0SZev Weiss if (!(reg & 0x80)) 1376*c3963bc0SZev Weiss data->pwm_weight_temp_sel[i] = 0; 1377*c3963bc0SZev Weiss 1378*c3963bc0SZev Weiss /* Weight temp data */ 1379*c3963bc0SZev Weiss for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) { 1380*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_WEIGHT_TEMP[j][i], ®); 1381*c3963bc0SZev Weiss if (err) 1382*c3963bc0SZev Weiss return err; 1383*c3963bc0SZev Weiss data->weight_temp[j][i] = reg; 1384*c3963bc0SZev Weiss } 1385*c3963bc0SZev Weiss } 1386*c3963bc0SZev Weiss 1387*c3963bc0SZev Weiss return 0; 1388*c3963bc0SZev Weiss } 1389*c3963bc0SZev Weiss 1390*c3963bc0SZev Weiss static int nct6775_update_pwm_limits(struct device *dev) 1391*c3963bc0SZev Weiss { 1392*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1393*c3963bc0SZev Weiss int i, j, err; 1394*c3963bc0SZev Weiss u16 reg, reg_t; 1395*c3963bc0SZev Weiss 1396*c3963bc0SZev Weiss for (i = 0; i < data->pwm_num; i++) { 1397*c3963bc0SZev Weiss if (!(data->has_pwm & BIT(i))) 1398*c3963bc0SZev Weiss continue; 1399*c3963bc0SZev Weiss 1400*c3963bc0SZev Weiss for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) { 1401*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_TIME[j][i], ®); 1402*c3963bc0SZev Weiss if (err) 1403*c3963bc0SZev Weiss return err; 1404*c3963bc0SZev Weiss data->fan_time[j][i] = reg; 1405*c3963bc0SZev Weiss } 1406*c3963bc0SZev Weiss 1407*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TARGET[i], ®_t); 1408*c3963bc0SZev Weiss if (err) 1409*c3963bc0SZev Weiss return err; 1410*c3963bc0SZev Weiss 1411*c3963bc0SZev Weiss /* Update only in matching mode or if never updated */ 1412*c3963bc0SZev Weiss if (!data->target_temp[i] || 1413*c3963bc0SZev Weiss data->pwm_enable[i] == thermal_cruise) 1414*c3963bc0SZev Weiss data->target_temp[i] = reg_t & data->target_temp_mask; 1415*c3963bc0SZev Weiss if (!data->target_speed[i] || 1416*c3963bc0SZev Weiss data->pwm_enable[i] == speed_cruise) { 1417*c3963bc0SZev Weiss if (data->REG_TOLERANCE_H) { 1418*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TOLERANCE_H[i], ®); 1419*c3963bc0SZev Weiss if (err) 1420*c3963bc0SZev Weiss return err; 1421*c3963bc0SZev Weiss reg_t |= (reg & 0x0f) << 8; 1422*c3963bc0SZev Weiss } 1423*c3963bc0SZev Weiss data->target_speed[i] = reg_t; 1424*c3963bc0SZev Weiss } 1425*c3963bc0SZev Weiss 1426*c3963bc0SZev Weiss for (j = 0; j < data->auto_pwm_num; j++) { 1427*c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_AUTO_PWM(data, i, j), ®); 1428*c3963bc0SZev Weiss if (err) 1429*c3963bc0SZev Weiss return err; 1430*c3963bc0SZev Weiss data->auto_pwm[i][j] = reg; 1431*c3963bc0SZev Weiss 1432*c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_AUTO_TEMP(data, i, j), ®); 1433*c3963bc0SZev Weiss if (err) 1434*c3963bc0SZev Weiss return err; 1435*c3963bc0SZev Weiss data->auto_temp[i][j] = reg; 1436*c3963bc0SZev Weiss } 1437*c3963bc0SZev Weiss 1438*c3963bc0SZev Weiss /* critical auto_pwm temperature data */ 1439*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_CRITICAL_TEMP[i], ®); 1440*c3963bc0SZev Weiss if (err) 1441*c3963bc0SZev Weiss return err; 1442*c3963bc0SZev Weiss data->auto_temp[i][data->auto_pwm_num] = reg; 1443*c3963bc0SZev Weiss 1444*c3963bc0SZev Weiss switch (data->kind) { 1445*c3963bc0SZev Weiss case nct6775: 1446*c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_CRITICAL_ENAB[i], ®); 1447*c3963bc0SZev Weiss if (err) 1448*c3963bc0SZev Weiss return err; 1449*c3963bc0SZev Weiss data->auto_pwm[i][data->auto_pwm_num] = 1450*c3963bc0SZev Weiss (reg & 0x02) ? 0xff : 0x00; 1451*c3963bc0SZev Weiss break; 1452*c3963bc0SZev Weiss case nct6776: 1453*c3963bc0SZev Weiss data->auto_pwm[i][data->auto_pwm_num] = 0xff; 1454*c3963bc0SZev Weiss break; 1455*c3963bc0SZev Weiss case nct6106: 1456*c3963bc0SZev Weiss case nct6116: 1457*c3963bc0SZev Weiss case nct6779: 1458*c3963bc0SZev Weiss case nct6791: 1459*c3963bc0SZev Weiss case nct6792: 1460*c3963bc0SZev Weiss case nct6793: 1461*c3963bc0SZev Weiss case nct6795: 1462*c3963bc0SZev Weiss case nct6796: 1463*c3963bc0SZev Weiss case nct6797: 1464*c3963bc0SZev Weiss case nct6798: 1465*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i], ®); 1466*c3963bc0SZev Weiss if (err) 1467*c3963bc0SZev Weiss return err; 1468*c3963bc0SZev Weiss if (reg & data->CRITICAL_PWM_ENABLE_MASK) { 1469*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_CRITICAL_PWM[i], ®); 1470*c3963bc0SZev Weiss if (err) 1471*c3963bc0SZev Weiss return err; 1472*c3963bc0SZev Weiss } else { 1473*c3963bc0SZev Weiss reg = 0xff; 1474*c3963bc0SZev Weiss } 1475*c3963bc0SZev Weiss data->auto_pwm[i][data->auto_pwm_num] = reg; 1476*c3963bc0SZev Weiss break; 1477*c3963bc0SZev Weiss } 1478*c3963bc0SZev Weiss } 1479*c3963bc0SZev Weiss 1480*c3963bc0SZev Weiss return 0; 1481*c3963bc0SZev Weiss } 1482*c3963bc0SZev Weiss 1483*c3963bc0SZev Weiss static struct nct6775_data *nct6775_update_device(struct device *dev) 1484*c3963bc0SZev Weiss { 1485*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1486*c3963bc0SZev Weiss int i, j, err = 0; 1487*c3963bc0SZev Weiss u16 reg; 1488*c3963bc0SZev Weiss 1489*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 1490*c3963bc0SZev Weiss 1491*c3963bc0SZev Weiss if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 1492*c3963bc0SZev Weiss || !data->valid) { 1493*c3963bc0SZev Weiss /* Fan clock dividers */ 1494*c3963bc0SZev Weiss err = nct6775_update_fan_div_common(data); 1495*c3963bc0SZev Weiss if (err) 1496*c3963bc0SZev Weiss goto out; 1497*c3963bc0SZev Weiss 1498*c3963bc0SZev Weiss /* Measured voltages and limits */ 1499*c3963bc0SZev Weiss for (i = 0; i < data->in_num; i++) { 1500*c3963bc0SZev Weiss if (!(data->have_in & BIT(i))) 1501*c3963bc0SZev Weiss continue; 1502*c3963bc0SZev Weiss 1503*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_VIN[i], ®); 1504*c3963bc0SZev Weiss if (err) 1505*c3963bc0SZev Weiss goto out; 1506*c3963bc0SZev Weiss data->in[i][0] = reg; 1507*c3963bc0SZev Weiss 1508*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_IN_MINMAX[0][i], ®); 1509*c3963bc0SZev Weiss if (err) 1510*c3963bc0SZev Weiss goto out; 1511*c3963bc0SZev Weiss data->in[i][1] = reg; 1512*c3963bc0SZev Weiss 1513*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_IN_MINMAX[1][i], ®); 1514*c3963bc0SZev Weiss if (err) 1515*c3963bc0SZev Weiss goto out; 1516*c3963bc0SZev Weiss data->in[i][2] = reg; 1517*c3963bc0SZev Weiss } 1518*c3963bc0SZev Weiss 1519*c3963bc0SZev Weiss /* Measured fan speeds and limits */ 1520*c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(data->rpm); i++) { 1521*c3963bc0SZev Weiss if (!(data->has_fan & BIT(i))) 1522*c3963bc0SZev Weiss continue; 1523*c3963bc0SZev Weiss 1524*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN[i], ®); 1525*c3963bc0SZev Weiss if (err) 1526*c3963bc0SZev Weiss goto out; 1527*c3963bc0SZev Weiss data->rpm[i] = data->fan_from_reg(reg, 1528*c3963bc0SZev Weiss data->fan_div[i]); 1529*c3963bc0SZev Weiss 1530*c3963bc0SZev Weiss if (data->has_fan_min & BIT(i)) { 1531*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_MIN[i], ®); 1532*c3963bc0SZev Weiss if (err) 1533*c3963bc0SZev Weiss goto out; 1534*c3963bc0SZev Weiss data->fan_min[i] = reg; 1535*c3963bc0SZev Weiss } 1536*c3963bc0SZev Weiss 1537*c3963bc0SZev Weiss if (data->REG_FAN_PULSES[i]) { 1538*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_PULSES[i], ®); 1539*c3963bc0SZev Weiss if (err) 1540*c3963bc0SZev Weiss goto out; 1541*c3963bc0SZev Weiss data->fan_pulses[i] = (reg >> data->FAN_PULSE_SHIFT[i]) & 0x03; 1542*c3963bc0SZev Weiss } 1543*c3963bc0SZev Weiss 1544*c3963bc0SZev Weiss err = nct6775_select_fan_div(dev, data, i, reg); 1545*c3963bc0SZev Weiss if (err) 1546*c3963bc0SZev Weiss goto out; 1547*c3963bc0SZev Weiss } 1548*c3963bc0SZev Weiss 1549*c3963bc0SZev Weiss err = nct6775_update_pwm(dev); 1550*c3963bc0SZev Weiss if (err) 1551*c3963bc0SZev Weiss goto out; 1552*c3963bc0SZev Weiss 1553*c3963bc0SZev Weiss err = nct6775_update_pwm_limits(dev); 1554*c3963bc0SZev Weiss if (err) 1555*c3963bc0SZev Weiss goto out; 1556*c3963bc0SZev Weiss 1557*c3963bc0SZev Weiss /* Measured temperatures and limits */ 1558*c3963bc0SZev Weiss for (i = 0; i < NUM_TEMP; i++) { 1559*c3963bc0SZev Weiss if (!(data->have_temp & BIT(i))) 1560*c3963bc0SZev Weiss continue; 1561*c3963bc0SZev Weiss for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) { 1562*c3963bc0SZev Weiss if (data->reg_temp[j][i]) { 1563*c3963bc0SZev Weiss err = nct6775_read_temp(data, data->reg_temp[j][i], ®); 1564*c3963bc0SZev Weiss if (err) 1565*c3963bc0SZev Weiss goto out; 1566*c3963bc0SZev Weiss data->temp[j][i] = reg; 1567*c3963bc0SZev Weiss } 1568*c3963bc0SZev Weiss } 1569*c3963bc0SZev Weiss if (i >= NUM_TEMP_FIXED || 1570*c3963bc0SZev Weiss !(data->have_temp_fixed & BIT(i))) 1571*c3963bc0SZev Weiss continue; 1572*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_OFFSET[i], ®); 1573*c3963bc0SZev Weiss if (err) 1574*c3963bc0SZev Weiss goto out; 1575*c3963bc0SZev Weiss data->temp_offset[i] = reg; 1576*c3963bc0SZev Weiss } 1577*c3963bc0SZev Weiss 1578*c3963bc0SZev Weiss for (i = 0; i < NUM_TSI_TEMP; i++) { 1579*c3963bc0SZev Weiss if (!(data->have_tsi_temp & BIT(i))) 1580*c3963bc0SZev Weiss continue; 1581*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TSI_TEMP[i], ®); 1582*c3963bc0SZev Weiss if (err) 1583*c3963bc0SZev Weiss goto out; 1584*c3963bc0SZev Weiss data->tsi_temp[i] = reg; 1585*c3963bc0SZev Weiss } 1586*c3963bc0SZev Weiss 1587*c3963bc0SZev Weiss data->alarms = 0; 1588*c3963bc0SZev Weiss for (i = 0; i < NUM_REG_ALARM; i++) { 1589*c3963bc0SZev Weiss u16 alarm; 1590*c3963bc0SZev Weiss 1591*c3963bc0SZev Weiss if (!data->REG_ALARM[i]) 1592*c3963bc0SZev Weiss continue; 1593*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_ALARM[i], &alarm); 1594*c3963bc0SZev Weiss if (err) 1595*c3963bc0SZev Weiss goto out; 1596*c3963bc0SZev Weiss data->alarms |= ((u64)alarm) << (i << 3); 1597*c3963bc0SZev Weiss } 1598*c3963bc0SZev Weiss 1599*c3963bc0SZev Weiss data->beeps = 0; 1600*c3963bc0SZev Weiss for (i = 0; i < NUM_REG_BEEP; i++) { 1601*c3963bc0SZev Weiss u16 beep; 1602*c3963bc0SZev Weiss 1603*c3963bc0SZev Weiss if (!data->REG_BEEP[i]) 1604*c3963bc0SZev Weiss continue; 1605*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_BEEP[i], &beep); 1606*c3963bc0SZev Weiss if (err) 1607*c3963bc0SZev Weiss goto out; 1608*c3963bc0SZev Weiss data->beeps |= ((u64)beep) << (i << 3); 1609*c3963bc0SZev Weiss } 1610*c3963bc0SZev Weiss 1611*c3963bc0SZev Weiss data->last_updated = jiffies; 1612*c3963bc0SZev Weiss data->valid = true; 1613*c3963bc0SZev Weiss } 1614*c3963bc0SZev Weiss out: 1615*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 1616*c3963bc0SZev Weiss return err ? ERR_PTR(err) : data; 1617*c3963bc0SZev Weiss } 1618*c3963bc0SZev Weiss 1619*c3963bc0SZev Weiss /* 1620*c3963bc0SZev Weiss * Sysfs callback functions 1621*c3963bc0SZev Weiss */ 1622*c3963bc0SZev Weiss static ssize_t 1623*c3963bc0SZev Weiss show_in_reg(struct device *dev, struct device_attribute *attr, char *buf) 1624*c3963bc0SZev Weiss { 1625*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1626*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 1627*c3963bc0SZev Weiss int index = sattr->index; 1628*c3963bc0SZev Weiss int nr = sattr->nr; 1629*c3963bc0SZev Weiss 1630*c3963bc0SZev Weiss if (IS_ERR(data)) 1631*c3963bc0SZev Weiss return PTR_ERR(data); 1632*c3963bc0SZev Weiss 1633*c3963bc0SZev Weiss return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr)); 1634*c3963bc0SZev Weiss } 1635*c3963bc0SZev Weiss 1636*c3963bc0SZev Weiss static ssize_t 1637*c3963bc0SZev Weiss store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf, 1638*c3963bc0SZev Weiss size_t count) 1639*c3963bc0SZev Weiss { 1640*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1641*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 1642*c3963bc0SZev Weiss int index = sattr->index; 1643*c3963bc0SZev Weiss int nr = sattr->nr; 1644*c3963bc0SZev Weiss unsigned long val; 1645*c3963bc0SZev Weiss int err; 1646*c3963bc0SZev Weiss 1647*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 1648*c3963bc0SZev Weiss if (err < 0) 1649*c3963bc0SZev Weiss return err; 1650*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 1651*c3963bc0SZev Weiss data->in[nr][index] = in_to_reg(val, nr); 1652*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr], data->in[nr][index]); 1653*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 1654*c3963bc0SZev Weiss return err ? : count; 1655*c3963bc0SZev Weiss } 1656*c3963bc0SZev Weiss 1657*c3963bc0SZev Weiss ssize_t 1658*c3963bc0SZev Weiss nct6775_show_alarm(struct device *dev, struct device_attribute *attr, char *buf) 1659*c3963bc0SZev Weiss { 1660*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1661*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1662*c3963bc0SZev Weiss int nr; 1663*c3963bc0SZev Weiss 1664*c3963bc0SZev Weiss if (IS_ERR(data)) 1665*c3963bc0SZev Weiss return PTR_ERR(data); 1666*c3963bc0SZev Weiss 1667*c3963bc0SZev Weiss nr = data->ALARM_BITS[sattr->index]; 1668*c3963bc0SZev Weiss return sprintf(buf, "%u\n", 1669*c3963bc0SZev Weiss (unsigned int)((data->alarms >> nr) & 0x01)); 1670*c3963bc0SZev Weiss } 1671*c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_show_alarm); 1672*c3963bc0SZev Weiss 1673*c3963bc0SZev Weiss static int find_temp_source(struct nct6775_data *data, int index, int count) 1674*c3963bc0SZev Weiss { 1675*c3963bc0SZev Weiss int source = data->temp_src[index]; 1676*c3963bc0SZev Weiss int nr, err; 1677*c3963bc0SZev Weiss 1678*c3963bc0SZev Weiss for (nr = 0; nr < count; nr++) { 1679*c3963bc0SZev Weiss u16 src; 1680*c3963bc0SZev Weiss 1681*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SOURCE[nr], &src); 1682*c3963bc0SZev Weiss if (err) 1683*c3963bc0SZev Weiss return err; 1684*c3963bc0SZev Weiss if ((src & 0x1f) == source) 1685*c3963bc0SZev Weiss return nr; 1686*c3963bc0SZev Weiss } 1687*c3963bc0SZev Weiss return -ENODEV; 1688*c3963bc0SZev Weiss } 1689*c3963bc0SZev Weiss 1690*c3963bc0SZev Weiss static ssize_t 1691*c3963bc0SZev Weiss show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf) 1692*c3963bc0SZev Weiss { 1693*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1694*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1695*c3963bc0SZev Weiss unsigned int alarm = 0; 1696*c3963bc0SZev Weiss int nr; 1697*c3963bc0SZev Weiss 1698*c3963bc0SZev Weiss if (IS_ERR(data)) 1699*c3963bc0SZev Weiss return PTR_ERR(data); 1700*c3963bc0SZev Weiss 1701*c3963bc0SZev Weiss /* 1702*c3963bc0SZev Weiss * For temperatures, there is no fixed mapping from registers to alarm 1703*c3963bc0SZev Weiss * bits. Alarm bits are determined by the temperature source mapping. 1704*c3963bc0SZev Weiss */ 1705*c3963bc0SZev Weiss nr = find_temp_source(data, sattr->index, data->num_temp_alarms); 1706*c3963bc0SZev Weiss if (nr >= 0) { 1707*c3963bc0SZev Weiss int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE]; 1708*c3963bc0SZev Weiss 1709*c3963bc0SZev Weiss alarm = (data->alarms >> bit) & 0x01; 1710*c3963bc0SZev Weiss } 1711*c3963bc0SZev Weiss return sprintf(buf, "%u\n", alarm); 1712*c3963bc0SZev Weiss } 1713*c3963bc0SZev Weiss 1714*c3963bc0SZev Weiss ssize_t 1715*c3963bc0SZev Weiss nct6775_show_beep(struct device *dev, struct device_attribute *attr, char *buf) 1716*c3963bc0SZev Weiss { 1717*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1718*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1719*c3963bc0SZev Weiss int nr; 1720*c3963bc0SZev Weiss 1721*c3963bc0SZev Weiss if (IS_ERR(data)) 1722*c3963bc0SZev Weiss return PTR_ERR(data); 1723*c3963bc0SZev Weiss 1724*c3963bc0SZev Weiss nr = data->BEEP_BITS[sattr->index]; 1725*c3963bc0SZev Weiss 1726*c3963bc0SZev Weiss return sprintf(buf, "%u\n", 1727*c3963bc0SZev Weiss (unsigned int)((data->beeps >> nr) & 0x01)); 1728*c3963bc0SZev Weiss } 1729*c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_show_beep); 1730*c3963bc0SZev Weiss 1731*c3963bc0SZev Weiss ssize_t 1732*c3963bc0SZev Weiss nct6775_store_beep(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 1733*c3963bc0SZev Weiss { 1734*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 1735*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1736*c3963bc0SZev Weiss int nr = data->BEEP_BITS[sattr->index]; 1737*c3963bc0SZev Weiss int regindex = nr >> 3; 1738*c3963bc0SZev Weiss unsigned long val; 1739*c3963bc0SZev Weiss int err; 1740*c3963bc0SZev Weiss 1741*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 1742*c3963bc0SZev Weiss if (err < 0) 1743*c3963bc0SZev Weiss return err; 1744*c3963bc0SZev Weiss if (val > 1) 1745*c3963bc0SZev Weiss return -EINVAL; 1746*c3963bc0SZev Weiss 1747*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 1748*c3963bc0SZev Weiss if (val) 1749*c3963bc0SZev Weiss data->beeps |= (1ULL << nr); 1750*c3963bc0SZev Weiss else 1751*c3963bc0SZev Weiss data->beeps &= ~(1ULL << nr); 1752*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_BEEP[regindex], 1753*c3963bc0SZev Weiss (data->beeps >> (regindex << 3)) & 0xff); 1754*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 1755*c3963bc0SZev Weiss return err ? : count; 1756*c3963bc0SZev Weiss } 1757*c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_store_beep); 1758*c3963bc0SZev Weiss 1759*c3963bc0SZev Weiss static ssize_t 1760*c3963bc0SZev Weiss show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf) 1761*c3963bc0SZev Weiss { 1762*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1763*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1764*c3963bc0SZev Weiss unsigned int beep = 0; 1765*c3963bc0SZev Weiss int nr; 1766*c3963bc0SZev Weiss 1767*c3963bc0SZev Weiss if (IS_ERR(data)) 1768*c3963bc0SZev Weiss return PTR_ERR(data); 1769*c3963bc0SZev Weiss 1770*c3963bc0SZev Weiss /* 1771*c3963bc0SZev Weiss * For temperatures, there is no fixed mapping from registers to beep 1772*c3963bc0SZev Weiss * enable bits. Beep enable bits are determined by the temperature 1773*c3963bc0SZev Weiss * source mapping. 1774*c3963bc0SZev Weiss */ 1775*c3963bc0SZev Weiss nr = find_temp_source(data, sattr->index, data->num_temp_beeps); 1776*c3963bc0SZev Weiss if (nr >= 0) { 1777*c3963bc0SZev Weiss int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE]; 1778*c3963bc0SZev Weiss 1779*c3963bc0SZev Weiss beep = (data->beeps >> bit) & 0x01; 1780*c3963bc0SZev Weiss } 1781*c3963bc0SZev Weiss return sprintf(buf, "%u\n", beep); 1782*c3963bc0SZev Weiss } 1783*c3963bc0SZev Weiss 1784*c3963bc0SZev Weiss static ssize_t 1785*c3963bc0SZev Weiss store_temp_beep(struct device *dev, struct device_attribute *attr, 1786*c3963bc0SZev Weiss const char *buf, size_t count) 1787*c3963bc0SZev Weiss { 1788*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 1789*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1790*c3963bc0SZev Weiss int nr, bit, regindex; 1791*c3963bc0SZev Weiss unsigned long val; 1792*c3963bc0SZev Weiss int err; 1793*c3963bc0SZev Weiss 1794*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 1795*c3963bc0SZev Weiss if (err < 0) 1796*c3963bc0SZev Weiss return err; 1797*c3963bc0SZev Weiss if (val > 1) 1798*c3963bc0SZev Weiss return -EINVAL; 1799*c3963bc0SZev Weiss 1800*c3963bc0SZev Weiss nr = find_temp_source(data, sattr->index, data->num_temp_beeps); 1801*c3963bc0SZev Weiss if (nr < 0) 1802*c3963bc0SZev Weiss return nr; 1803*c3963bc0SZev Weiss 1804*c3963bc0SZev Weiss bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE]; 1805*c3963bc0SZev Weiss regindex = bit >> 3; 1806*c3963bc0SZev Weiss 1807*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 1808*c3963bc0SZev Weiss if (val) 1809*c3963bc0SZev Weiss data->beeps |= (1ULL << bit); 1810*c3963bc0SZev Weiss else 1811*c3963bc0SZev Weiss data->beeps &= ~(1ULL << bit); 1812*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_BEEP[regindex], 1813*c3963bc0SZev Weiss (data->beeps >> (regindex << 3)) & 0xff); 1814*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 1815*c3963bc0SZev Weiss 1816*c3963bc0SZev Weiss return err ? : count; 1817*c3963bc0SZev Weiss } 1818*c3963bc0SZev Weiss 1819*c3963bc0SZev Weiss static umode_t nct6775_in_is_visible(struct kobject *kobj, 1820*c3963bc0SZev Weiss struct attribute *attr, int index) 1821*c3963bc0SZev Weiss { 1822*c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 1823*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1824*c3963bc0SZev Weiss int in = index / 5; /* voltage index */ 1825*c3963bc0SZev Weiss 1826*c3963bc0SZev Weiss if (!(data->have_in & BIT(in))) 1827*c3963bc0SZev Weiss return 0; 1828*c3963bc0SZev Weiss 1829*c3963bc0SZev Weiss return nct6775_attr_mode(data, attr); 1830*c3963bc0SZev Weiss } 1831*c3963bc0SZev Weiss 1832*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(in_input, "in%d_input", 0444, show_in_reg, NULL, 0, 0); 1833*c3963bc0SZev Weiss SENSOR_TEMPLATE(in_alarm, "in%d_alarm", 0444, nct6775_show_alarm, NULL, 0); 1834*c3963bc0SZev Weiss SENSOR_TEMPLATE(in_beep, "in%d_beep", 0644, nct6775_show_beep, nct6775_store_beep, 0); 1835*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(in_min, "in%d_min", 0644, show_in_reg, store_in_reg, 0, 1); 1836*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(in_max, "in%d_max", 0644, show_in_reg, store_in_reg, 0, 2); 1837*c3963bc0SZev Weiss 1838*c3963bc0SZev Weiss /* 1839*c3963bc0SZev Weiss * nct6775_in_is_visible uses the index into the following array 1840*c3963bc0SZev Weiss * to determine if attributes should be created or not. 1841*c3963bc0SZev Weiss * Any change in order or content must be matched. 1842*c3963bc0SZev Weiss */ 1843*c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_in_template[] = { 1844*c3963bc0SZev Weiss &sensor_dev_template_in_input, 1845*c3963bc0SZev Weiss &sensor_dev_template_in_alarm, 1846*c3963bc0SZev Weiss &sensor_dev_template_in_beep, 1847*c3963bc0SZev Weiss &sensor_dev_template_in_min, 1848*c3963bc0SZev Weiss &sensor_dev_template_in_max, 1849*c3963bc0SZev Weiss NULL 1850*c3963bc0SZev Weiss }; 1851*c3963bc0SZev Weiss 1852*c3963bc0SZev Weiss static const struct sensor_template_group nct6775_in_template_group = { 1853*c3963bc0SZev Weiss .templates = nct6775_attributes_in_template, 1854*c3963bc0SZev Weiss .is_visible = nct6775_in_is_visible, 1855*c3963bc0SZev Weiss }; 1856*c3963bc0SZev Weiss 1857*c3963bc0SZev Weiss static ssize_t 1858*c3963bc0SZev Weiss show_fan(struct device *dev, struct device_attribute *attr, char *buf) 1859*c3963bc0SZev Weiss { 1860*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1861*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1862*c3963bc0SZev Weiss int nr = sattr->index; 1863*c3963bc0SZev Weiss 1864*c3963bc0SZev Weiss if (IS_ERR(data)) 1865*c3963bc0SZev Weiss return PTR_ERR(data); 1866*c3963bc0SZev Weiss 1867*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->rpm[nr]); 1868*c3963bc0SZev Weiss } 1869*c3963bc0SZev Weiss 1870*c3963bc0SZev Weiss static ssize_t 1871*c3963bc0SZev Weiss show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) 1872*c3963bc0SZev Weiss { 1873*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1874*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1875*c3963bc0SZev Weiss int nr = sattr->index; 1876*c3963bc0SZev Weiss 1877*c3963bc0SZev Weiss if (IS_ERR(data)) 1878*c3963bc0SZev Weiss return PTR_ERR(data); 1879*c3963bc0SZev Weiss 1880*c3963bc0SZev Weiss return sprintf(buf, "%d\n", 1881*c3963bc0SZev Weiss data->fan_from_reg_min(data->fan_min[nr], 1882*c3963bc0SZev Weiss data->fan_div[nr])); 1883*c3963bc0SZev Weiss } 1884*c3963bc0SZev Weiss 1885*c3963bc0SZev Weiss static ssize_t 1886*c3963bc0SZev Weiss show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) 1887*c3963bc0SZev Weiss { 1888*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1889*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1890*c3963bc0SZev Weiss int nr = sattr->index; 1891*c3963bc0SZev Weiss 1892*c3963bc0SZev Weiss if (IS_ERR(data)) 1893*c3963bc0SZev Weiss return PTR_ERR(data); 1894*c3963bc0SZev Weiss 1895*c3963bc0SZev Weiss return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr])); 1896*c3963bc0SZev Weiss } 1897*c3963bc0SZev Weiss 1898*c3963bc0SZev Weiss static ssize_t 1899*c3963bc0SZev Weiss store_fan_min(struct device *dev, struct device_attribute *attr, 1900*c3963bc0SZev Weiss const char *buf, size_t count) 1901*c3963bc0SZev Weiss { 1902*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 1903*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1904*c3963bc0SZev Weiss int nr = sattr->index; 1905*c3963bc0SZev Weiss unsigned long val; 1906*c3963bc0SZev Weiss unsigned int reg; 1907*c3963bc0SZev Weiss u8 new_div; 1908*c3963bc0SZev Weiss int err; 1909*c3963bc0SZev Weiss 1910*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 1911*c3963bc0SZev Weiss if (err < 0) 1912*c3963bc0SZev Weiss return err; 1913*c3963bc0SZev Weiss 1914*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 1915*c3963bc0SZev Weiss if (!data->has_fan_div) { 1916*c3963bc0SZev Weiss /* NCT6776F or NCT6779D; we know this is a 13 bit register */ 1917*c3963bc0SZev Weiss if (!val) { 1918*c3963bc0SZev Weiss val = 0xff1f; 1919*c3963bc0SZev Weiss } else { 1920*c3963bc0SZev Weiss if (val > 1350000U) 1921*c3963bc0SZev Weiss val = 135000U; 1922*c3963bc0SZev Weiss val = 1350000U / val; 1923*c3963bc0SZev Weiss val = (val & 0x1f) | ((val << 3) & 0xff00); 1924*c3963bc0SZev Weiss } 1925*c3963bc0SZev Weiss data->fan_min[nr] = val; 1926*c3963bc0SZev Weiss goto write_min; /* Leave fan divider alone */ 1927*c3963bc0SZev Weiss } 1928*c3963bc0SZev Weiss if (!val) { 1929*c3963bc0SZev Weiss /* No min limit, alarm disabled */ 1930*c3963bc0SZev Weiss data->fan_min[nr] = 255; 1931*c3963bc0SZev Weiss new_div = data->fan_div[nr]; /* No change */ 1932*c3963bc0SZev Weiss dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); 1933*c3963bc0SZev Weiss goto write_div; 1934*c3963bc0SZev Weiss } 1935*c3963bc0SZev Weiss reg = 1350000U / val; 1936*c3963bc0SZev Weiss if (reg >= 128 * 255) { 1937*c3963bc0SZev Weiss /* 1938*c3963bc0SZev Weiss * Speed below this value cannot possibly be represented, 1939*c3963bc0SZev Weiss * even with the highest divider (128) 1940*c3963bc0SZev Weiss */ 1941*c3963bc0SZev Weiss data->fan_min[nr] = 254; 1942*c3963bc0SZev Weiss new_div = 7; /* 128 == BIT(7) */ 1943*c3963bc0SZev Weiss dev_warn(dev, 1944*c3963bc0SZev Weiss "fan%u low limit %lu below minimum %u, set to minimum\n", 1945*c3963bc0SZev Weiss nr + 1, val, data->fan_from_reg_min(254, 7)); 1946*c3963bc0SZev Weiss } else if (!reg) { 1947*c3963bc0SZev Weiss /* 1948*c3963bc0SZev Weiss * Speed above this value cannot possibly be represented, 1949*c3963bc0SZev Weiss * even with the lowest divider (1) 1950*c3963bc0SZev Weiss */ 1951*c3963bc0SZev Weiss data->fan_min[nr] = 1; 1952*c3963bc0SZev Weiss new_div = 0; /* 1 == BIT(0) */ 1953*c3963bc0SZev Weiss dev_warn(dev, 1954*c3963bc0SZev Weiss "fan%u low limit %lu above maximum %u, set to maximum\n", 1955*c3963bc0SZev Weiss nr + 1, val, data->fan_from_reg_min(1, 0)); 1956*c3963bc0SZev Weiss } else { 1957*c3963bc0SZev Weiss /* 1958*c3963bc0SZev Weiss * Automatically pick the best divider, i.e. the one such 1959*c3963bc0SZev Weiss * that the min limit will correspond to a register value 1960*c3963bc0SZev Weiss * in the 96..192 range 1961*c3963bc0SZev Weiss */ 1962*c3963bc0SZev Weiss new_div = 0; 1963*c3963bc0SZev Weiss while (reg > 192 && new_div < 7) { 1964*c3963bc0SZev Weiss reg >>= 1; 1965*c3963bc0SZev Weiss new_div++; 1966*c3963bc0SZev Weiss } 1967*c3963bc0SZev Weiss data->fan_min[nr] = reg; 1968*c3963bc0SZev Weiss } 1969*c3963bc0SZev Weiss 1970*c3963bc0SZev Weiss write_div: 1971*c3963bc0SZev Weiss /* 1972*c3963bc0SZev Weiss * Write both the fan clock divider (if it changed) and the new 1973*c3963bc0SZev Weiss * fan min (unconditionally) 1974*c3963bc0SZev Weiss */ 1975*c3963bc0SZev Weiss if (new_div != data->fan_div[nr]) { 1976*c3963bc0SZev Weiss dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", 1977*c3963bc0SZev Weiss nr + 1, div_from_reg(data->fan_div[nr]), 1978*c3963bc0SZev Weiss div_from_reg(new_div)); 1979*c3963bc0SZev Weiss data->fan_div[nr] = new_div; 1980*c3963bc0SZev Weiss err = nct6775_write_fan_div_common(data, nr); 1981*c3963bc0SZev Weiss if (err) 1982*c3963bc0SZev Weiss goto write_min; 1983*c3963bc0SZev Weiss /* Give the chip time to sample a new speed value */ 1984*c3963bc0SZev Weiss data->last_updated = jiffies; 1985*c3963bc0SZev Weiss } 1986*c3963bc0SZev Weiss 1987*c3963bc0SZev Weiss write_min: 1988*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]); 1989*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 1990*c3963bc0SZev Weiss 1991*c3963bc0SZev Weiss return err ? : count; 1992*c3963bc0SZev Weiss } 1993*c3963bc0SZev Weiss 1994*c3963bc0SZev Weiss static ssize_t 1995*c3963bc0SZev Weiss show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf) 1996*c3963bc0SZev Weiss { 1997*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 1998*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 1999*c3963bc0SZev Weiss int p; 2000*c3963bc0SZev Weiss 2001*c3963bc0SZev Weiss if (IS_ERR(data)) 2002*c3963bc0SZev Weiss return PTR_ERR(data); 2003*c3963bc0SZev Weiss 2004*c3963bc0SZev Weiss p = data->fan_pulses[sattr->index]; 2005*c3963bc0SZev Weiss return sprintf(buf, "%d\n", p ? : 4); 2006*c3963bc0SZev Weiss } 2007*c3963bc0SZev Weiss 2008*c3963bc0SZev Weiss static ssize_t 2009*c3963bc0SZev Weiss store_fan_pulses(struct device *dev, struct device_attribute *attr, 2010*c3963bc0SZev Weiss const char *buf, size_t count) 2011*c3963bc0SZev Weiss { 2012*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2013*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2014*c3963bc0SZev Weiss int nr = sattr->index; 2015*c3963bc0SZev Weiss unsigned long val; 2016*c3963bc0SZev Weiss int err; 2017*c3963bc0SZev Weiss u16 reg; 2018*c3963bc0SZev Weiss 2019*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2020*c3963bc0SZev Weiss if (err < 0) 2021*c3963bc0SZev Weiss return err; 2022*c3963bc0SZev Weiss 2023*c3963bc0SZev Weiss if (val > 4) 2024*c3963bc0SZev Weiss return -EINVAL; 2025*c3963bc0SZev Weiss 2026*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2027*c3963bc0SZev Weiss data->fan_pulses[nr] = val & 3; 2028*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_PULSES[nr], ®); 2029*c3963bc0SZev Weiss if (err) 2030*c3963bc0SZev Weiss goto out; 2031*c3963bc0SZev Weiss reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]); 2032*c3963bc0SZev Weiss reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr]; 2033*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg); 2034*c3963bc0SZev Weiss out: 2035*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2036*c3963bc0SZev Weiss 2037*c3963bc0SZev Weiss return err ? : count; 2038*c3963bc0SZev Weiss } 2039*c3963bc0SZev Weiss 2040*c3963bc0SZev Weiss static umode_t nct6775_fan_is_visible(struct kobject *kobj, 2041*c3963bc0SZev Weiss struct attribute *attr, int index) 2042*c3963bc0SZev Weiss { 2043*c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 2044*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2045*c3963bc0SZev Weiss int fan = index / 6; /* fan index */ 2046*c3963bc0SZev Weiss int nr = index % 6; /* attribute index */ 2047*c3963bc0SZev Weiss 2048*c3963bc0SZev Weiss if (!(data->has_fan & BIT(fan))) 2049*c3963bc0SZev Weiss return 0; 2050*c3963bc0SZev Weiss 2051*c3963bc0SZev Weiss if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1) 2052*c3963bc0SZev Weiss return 0; 2053*c3963bc0SZev Weiss if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1) 2054*c3963bc0SZev Weiss return 0; 2055*c3963bc0SZev Weiss if (nr == 3 && !data->REG_FAN_PULSES[fan]) 2056*c3963bc0SZev Weiss return 0; 2057*c3963bc0SZev Weiss if (nr == 4 && !(data->has_fan_min & BIT(fan))) 2058*c3963bc0SZev Weiss return 0; 2059*c3963bc0SZev Weiss if (nr == 5 && data->kind != nct6775) 2060*c3963bc0SZev Weiss return 0; 2061*c3963bc0SZev Weiss 2062*c3963bc0SZev Weiss return nct6775_attr_mode(data, attr); 2063*c3963bc0SZev Weiss } 2064*c3963bc0SZev Weiss 2065*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_input, "fan%d_input", 0444, show_fan, NULL, 0); 2066*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", 0444, nct6775_show_alarm, NULL, FAN_ALARM_BASE); 2067*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_beep, "fan%d_beep", 0644, nct6775_show_beep, 2068*c3963bc0SZev Weiss nct6775_store_beep, FAN_ALARM_BASE); 2069*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", 0644, show_fan_pulses, store_fan_pulses, 0); 2070*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_min, "fan%d_min", 0644, show_fan_min, store_fan_min, 0); 2071*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_div, "fan%d_div", 0444, show_fan_div, NULL, 0); 2072*c3963bc0SZev Weiss 2073*c3963bc0SZev Weiss /* 2074*c3963bc0SZev Weiss * nct6775_fan_is_visible uses the index into the following array 2075*c3963bc0SZev Weiss * to determine if attributes should be created or not. 2076*c3963bc0SZev Weiss * Any change in order or content must be matched. 2077*c3963bc0SZev Weiss */ 2078*c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_fan_template[] = { 2079*c3963bc0SZev Weiss &sensor_dev_template_fan_input, 2080*c3963bc0SZev Weiss &sensor_dev_template_fan_alarm, /* 1 */ 2081*c3963bc0SZev Weiss &sensor_dev_template_fan_beep, /* 2 */ 2082*c3963bc0SZev Weiss &sensor_dev_template_fan_pulses, 2083*c3963bc0SZev Weiss &sensor_dev_template_fan_min, /* 4 */ 2084*c3963bc0SZev Weiss &sensor_dev_template_fan_div, /* 5 */ 2085*c3963bc0SZev Weiss NULL 2086*c3963bc0SZev Weiss }; 2087*c3963bc0SZev Weiss 2088*c3963bc0SZev Weiss static const struct sensor_template_group nct6775_fan_template_group = { 2089*c3963bc0SZev Weiss .templates = nct6775_attributes_fan_template, 2090*c3963bc0SZev Weiss .is_visible = nct6775_fan_is_visible, 2091*c3963bc0SZev Weiss .base = 1, 2092*c3963bc0SZev Weiss }; 2093*c3963bc0SZev Weiss 2094*c3963bc0SZev Weiss static ssize_t 2095*c3963bc0SZev Weiss show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) 2096*c3963bc0SZev Weiss { 2097*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2098*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2099*c3963bc0SZev Weiss int nr = sattr->index; 2100*c3963bc0SZev Weiss 2101*c3963bc0SZev Weiss if (IS_ERR(data)) 2102*c3963bc0SZev Weiss return PTR_ERR(data); 2103*c3963bc0SZev Weiss 2104*c3963bc0SZev Weiss return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); 2105*c3963bc0SZev Weiss } 2106*c3963bc0SZev Weiss 2107*c3963bc0SZev Weiss static ssize_t 2108*c3963bc0SZev Weiss show_temp(struct device *dev, struct device_attribute *attr, char *buf) 2109*c3963bc0SZev Weiss { 2110*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2111*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2112*c3963bc0SZev Weiss int nr = sattr->nr; 2113*c3963bc0SZev Weiss int index = sattr->index; 2114*c3963bc0SZev Weiss 2115*c3963bc0SZev Weiss if (IS_ERR(data)) 2116*c3963bc0SZev Weiss return PTR_ERR(data); 2117*c3963bc0SZev Weiss 2118*c3963bc0SZev Weiss return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr])); 2119*c3963bc0SZev Weiss } 2120*c3963bc0SZev Weiss 2121*c3963bc0SZev Weiss static ssize_t 2122*c3963bc0SZev Weiss store_temp(struct device *dev, struct device_attribute *attr, const char *buf, 2123*c3963bc0SZev Weiss size_t count) 2124*c3963bc0SZev Weiss { 2125*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2126*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2127*c3963bc0SZev Weiss int nr = sattr->nr; 2128*c3963bc0SZev Weiss int index = sattr->index; 2129*c3963bc0SZev Weiss int err; 2130*c3963bc0SZev Weiss long val; 2131*c3963bc0SZev Weiss 2132*c3963bc0SZev Weiss err = kstrtol(buf, 10, &val); 2133*c3963bc0SZev Weiss if (err < 0) 2134*c3963bc0SZev Weiss return err; 2135*c3963bc0SZev Weiss 2136*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2137*c3963bc0SZev Weiss data->temp[index][nr] = LM75_TEMP_TO_REG(val); 2138*c3963bc0SZev Weiss err = nct6775_write_temp(data, data->reg_temp[index][nr], data->temp[index][nr]); 2139*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2140*c3963bc0SZev Weiss return err ? : count; 2141*c3963bc0SZev Weiss } 2142*c3963bc0SZev Weiss 2143*c3963bc0SZev Weiss static ssize_t 2144*c3963bc0SZev Weiss show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) 2145*c3963bc0SZev Weiss { 2146*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2147*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2148*c3963bc0SZev Weiss 2149*c3963bc0SZev Weiss if (IS_ERR(data)) 2150*c3963bc0SZev Weiss return PTR_ERR(data); 2151*c3963bc0SZev Weiss 2152*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000); 2153*c3963bc0SZev Weiss } 2154*c3963bc0SZev Weiss 2155*c3963bc0SZev Weiss static ssize_t 2156*c3963bc0SZev Weiss store_temp_offset(struct device *dev, struct device_attribute *attr, 2157*c3963bc0SZev Weiss const char *buf, size_t count) 2158*c3963bc0SZev Weiss { 2159*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2160*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2161*c3963bc0SZev Weiss int nr = sattr->index; 2162*c3963bc0SZev Weiss long val; 2163*c3963bc0SZev Weiss int err; 2164*c3963bc0SZev Weiss 2165*c3963bc0SZev Weiss err = kstrtol(buf, 10, &val); 2166*c3963bc0SZev Weiss if (err < 0) 2167*c3963bc0SZev Weiss return err; 2168*c3963bc0SZev Weiss 2169*c3963bc0SZev Weiss val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); 2170*c3963bc0SZev Weiss 2171*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2172*c3963bc0SZev Weiss data->temp_offset[nr] = val; 2173*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val); 2174*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2175*c3963bc0SZev Weiss 2176*c3963bc0SZev Weiss return err ? : count; 2177*c3963bc0SZev Weiss } 2178*c3963bc0SZev Weiss 2179*c3963bc0SZev Weiss static ssize_t 2180*c3963bc0SZev Weiss show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) 2181*c3963bc0SZev Weiss { 2182*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2183*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2184*c3963bc0SZev Weiss int nr = sattr->index; 2185*c3963bc0SZev Weiss 2186*c3963bc0SZev Weiss if (IS_ERR(data)) 2187*c3963bc0SZev Weiss return PTR_ERR(data); 2188*c3963bc0SZev Weiss 2189*c3963bc0SZev Weiss return sprintf(buf, "%d\n", (int)data->temp_type[nr]); 2190*c3963bc0SZev Weiss } 2191*c3963bc0SZev Weiss 2192*c3963bc0SZev Weiss static ssize_t 2193*c3963bc0SZev Weiss store_temp_type(struct device *dev, struct device_attribute *attr, 2194*c3963bc0SZev Weiss const char *buf, size_t count) 2195*c3963bc0SZev Weiss { 2196*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2197*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2198*c3963bc0SZev Weiss int nr = sattr->index; 2199*c3963bc0SZev Weiss unsigned long val; 2200*c3963bc0SZev Weiss int err; 2201*c3963bc0SZev Weiss u8 vbit, dbit; 2202*c3963bc0SZev Weiss u16 vbat, diode; 2203*c3963bc0SZev Weiss 2204*c3963bc0SZev Weiss if (IS_ERR(data)) 2205*c3963bc0SZev Weiss return PTR_ERR(data); 2206*c3963bc0SZev Weiss 2207*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2208*c3963bc0SZev Weiss if (err < 0) 2209*c3963bc0SZev Weiss return err; 2210*c3963bc0SZev Weiss 2211*c3963bc0SZev Weiss if (val != 1 && val != 3 && val != 4) 2212*c3963bc0SZev Weiss return -EINVAL; 2213*c3963bc0SZev Weiss 2214*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2215*c3963bc0SZev Weiss 2216*c3963bc0SZev Weiss data->temp_type[nr] = val; 2217*c3963bc0SZev Weiss vbit = 0x02 << nr; 2218*c3963bc0SZev Weiss dbit = data->DIODE_MASK << nr; 2219*c3963bc0SZev Weiss 2220*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_VBAT, &vbat); 2221*c3963bc0SZev Weiss if (err) 2222*c3963bc0SZev Weiss goto out; 2223*c3963bc0SZev Weiss vbat &= ~vbit; 2224*c3963bc0SZev Weiss 2225*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_DIODE, &diode); 2226*c3963bc0SZev Weiss if (err) 2227*c3963bc0SZev Weiss goto out; 2228*c3963bc0SZev Weiss diode &= ~dbit; 2229*c3963bc0SZev Weiss 2230*c3963bc0SZev Weiss switch (val) { 2231*c3963bc0SZev Weiss case 1: /* CPU diode (diode, current mode) */ 2232*c3963bc0SZev Weiss vbat |= vbit; 2233*c3963bc0SZev Weiss diode |= dbit; 2234*c3963bc0SZev Weiss break; 2235*c3963bc0SZev Weiss case 3: /* diode, voltage mode */ 2236*c3963bc0SZev Weiss vbat |= dbit; 2237*c3963bc0SZev Weiss break; 2238*c3963bc0SZev Weiss case 4: /* thermistor */ 2239*c3963bc0SZev Weiss break; 2240*c3963bc0SZev Weiss } 2241*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_VBAT, vbat); 2242*c3963bc0SZev Weiss if (err) 2243*c3963bc0SZev Weiss goto out; 2244*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_DIODE, diode); 2245*c3963bc0SZev Weiss out: 2246*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2247*c3963bc0SZev Weiss return err ? : count; 2248*c3963bc0SZev Weiss } 2249*c3963bc0SZev Weiss 2250*c3963bc0SZev Weiss static umode_t nct6775_temp_is_visible(struct kobject *kobj, 2251*c3963bc0SZev Weiss struct attribute *attr, int index) 2252*c3963bc0SZev Weiss { 2253*c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 2254*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2255*c3963bc0SZev Weiss int temp = index / 10; /* temp index */ 2256*c3963bc0SZev Weiss int nr = index % 10; /* attribute index */ 2257*c3963bc0SZev Weiss 2258*c3963bc0SZev Weiss if (!(data->have_temp & BIT(temp))) 2259*c3963bc0SZev Weiss return 0; 2260*c3963bc0SZev Weiss 2261*c3963bc0SZev Weiss if (nr == 1 && !data->temp_label) 2262*c3963bc0SZev Weiss return 0; 2263*c3963bc0SZev Weiss 2264*c3963bc0SZev Weiss if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0) 2265*c3963bc0SZev Weiss return 0; /* alarm */ 2266*c3963bc0SZev Weiss 2267*c3963bc0SZev Weiss if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0) 2268*c3963bc0SZev Weiss return 0; /* beep */ 2269*c3963bc0SZev Weiss 2270*c3963bc0SZev Weiss if (nr == 4 && !data->reg_temp[1][temp]) /* max */ 2271*c3963bc0SZev Weiss return 0; 2272*c3963bc0SZev Weiss 2273*c3963bc0SZev Weiss if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */ 2274*c3963bc0SZev Weiss return 0; 2275*c3963bc0SZev Weiss 2276*c3963bc0SZev Weiss if (nr == 6 && !data->reg_temp[3][temp]) /* crit */ 2277*c3963bc0SZev Weiss return 0; 2278*c3963bc0SZev Weiss 2279*c3963bc0SZev Weiss if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */ 2280*c3963bc0SZev Weiss return 0; 2281*c3963bc0SZev Weiss 2282*c3963bc0SZev Weiss /* offset and type only apply to fixed sensors */ 2283*c3963bc0SZev Weiss if (nr > 7 && !(data->have_temp_fixed & BIT(temp))) 2284*c3963bc0SZev Weiss return 0; 2285*c3963bc0SZev Weiss 2286*c3963bc0SZev Weiss return nct6775_attr_mode(data, attr); 2287*c3963bc0SZev Weiss } 2288*c3963bc0SZev Weiss 2289*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_input, "temp%d_input", 0444, show_temp, NULL, 0, 0); 2290*c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_label, "temp%d_label", 0444, show_temp_label, NULL, 0); 2291*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_max, "temp%d_max", 0644, show_temp, store_temp, 0, 1); 2292*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", 0644, show_temp, store_temp, 0, 2); 2293*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", 0644, show_temp, store_temp, 0, 3); 2294*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", 0644, show_temp, store_temp, 0, 4); 2295*c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_offset, "temp%d_offset", 0644, show_temp_offset, store_temp_offset, 0); 2296*c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_type, "temp%d_type", 0644, show_temp_type, store_temp_type, 0); 2297*c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", 0444, show_temp_alarm, NULL, 0); 2298*c3963bc0SZev Weiss SENSOR_TEMPLATE(temp_beep, "temp%d_beep", 0644, show_temp_beep, store_temp_beep, 0); 2299*c3963bc0SZev Weiss 2300*c3963bc0SZev Weiss /* 2301*c3963bc0SZev Weiss * nct6775_temp_is_visible uses the index into the following array 2302*c3963bc0SZev Weiss * to determine if attributes should be created or not. 2303*c3963bc0SZev Weiss * Any change in order or content must be matched. 2304*c3963bc0SZev Weiss */ 2305*c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_temp_template[] = { 2306*c3963bc0SZev Weiss &sensor_dev_template_temp_input, 2307*c3963bc0SZev Weiss &sensor_dev_template_temp_label, 2308*c3963bc0SZev Weiss &sensor_dev_template_temp_alarm, /* 2 */ 2309*c3963bc0SZev Weiss &sensor_dev_template_temp_beep, /* 3 */ 2310*c3963bc0SZev Weiss &sensor_dev_template_temp_max, /* 4 */ 2311*c3963bc0SZev Weiss &sensor_dev_template_temp_max_hyst, /* 5 */ 2312*c3963bc0SZev Weiss &sensor_dev_template_temp_crit, /* 6 */ 2313*c3963bc0SZev Weiss &sensor_dev_template_temp_lcrit, /* 7 */ 2314*c3963bc0SZev Weiss &sensor_dev_template_temp_offset, /* 8 */ 2315*c3963bc0SZev Weiss &sensor_dev_template_temp_type, /* 9 */ 2316*c3963bc0SZev Weiss NULL 2317*c3963bc0SZev Weiss }; 2318*c3963bc0SZev Weiss 2319*c3963bc0SZev Weiss static const struct sensor_template_group nct6775_temp_template_group = { 2320*c3963bc0SZev Weiss .templates = nct6775_attributes_temp_template, 2321*c3963bc0SZev Weiss .is_visible = nct6775_temp_is_visible, 2322*c3963bc0SZev Weiss .base = 1, 2323*c3963bc0SZev Weiss }; 2324*c3963bc0SZev Weiss 2325*c3963bc0SZev Weiss static ssize_t show_tsi_temp(struct device *dev, struct device_attribute *attr, char *buf) 2326*c3963bc0SZev Weiss { 2327*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2328*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2329*c3963bc0SZev Weiss 2330*c3963bc0SZev Weiss if (IS_ERR(data)) 2331*c3963bc0SZev Weiss return PTR_ERR(data); 2332*c3963bc0SZev Weiss 2333*c3963bc0SZev Weiss return sysfs_emit(buf, "%u\n", tsi_temp_from_reg(data->tsi_temp[sattr->index])); 2334*c3963bc0SZev Weiss } 2335*c3963bc0SZev Weiss 2336*c3963bc0SZev Weiss static ssize_t show_tsi_temp_label(struct device *dev, struct device_attribute *attr, char *buf) 2337*c3963bc0SZev Weiss { 2338*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2339*c3963bc0SZev Weiss 2340*c3963bc0SZev Weiss return sysfs_emit(buf, "TSI%d_TEMP\n", sattr->index); 2341*c3963bc0SZev Weiss } 2342*c3963bc0SZev Weiss 2343*c3963bc0SZev Weiss SENSOR_TEMPLATE(tsi_temp_input, "temp%d_input", 0444, show_tsi_temp, NULL, 0); 2344*c3963bc0SZev Weiss SENSOR_TEMPLATE(tsi_temp_label, "temp%d_label", 0444, show_tsi_temp_label, NULL, 0); 2345*c3963bc0SZev Weiss 2346*c3963bc0SZev Weiss static umode_t nct6775_tsi_temp_is_visible(struct kobject *kobj, struct attribute *attr, 2347*c3963bc0SZev Weiss int index) 2348*c3963bc0SZev Weiss { 2349*c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 2350*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2351*c3963bc0SZev Weiss int temp = index / 2; 2352*c3963bc0SZev Weiss 2353*c3963bc0SZev Weiss return (data->have_tsi_temp & BIT(temp)) ? nct6775_attr_mode(data, attr) : 0; 2354*c3963bc0SZev Weiss } 2355*c3963bc0SZev Weiss 2356*c3963bc0SZev Weiss /* 2357*c3963bc0SZev Weiss * The index calculation in nct6775_tsi_temp_is_visible() must be kept in 2358*c3963bc0SZev Weiss * sync with the size of this array. 2359*c3963bc0SZev Weiss */ 2360*c3963bc0SZev Weiss static struct sensor_device_template *nct6775_tsi_temp_template[] = { 2361*c3963bc0SZev Weiss &sensor_dev_template_tsi_temp_input, 2362*c3963bc0SZev Weiss &sensor_dev_template_tsi_temp_label, 2363*c3963bc0SZev Weiss NULL 2364*c3963bc0SZev Weiss }; 2365*c3963bc0SZev Weiss 2366*c3963bc0SZev Weiss static ssize_t 2367*c3963bc0SZev Weiss show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) 2368*c3963bc0SZev Weiss { 2369*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2370*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2371*c3963bc0SZev Weiss 2372*c3963bc0SZev Weiss if (IS_ERR(data)) 2373*c3963bc0SZev Weiss return PTR_ERR(data); 2374*c3963bc0SZev Weiss 2375*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]); 2376*c3963bc0SZev Weiss } 2377*c3963bc0SZev Weiss 2378*c3963bc0SZev Weiss static ssize_t 2379*c3963bc0SZev Weiss store_pwm_mode(struct device *dev, struct device_attribute *attr, 2380*c3963bc0SZev Weiss const char *buf, size_t count) 2381*c3963bc0SZev Weiss { 2382*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2383*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2384*c3963bc0SZev Weiss int nr = sattr->index; 2385*c3963bc0SZev Weiss unsigned long val; 2386*c3963bc0SZev Weiss int err; 2387*c3963bc0SZev Weiss u16 reg; 2388*c3963bc0SZev Weiss 2389*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2390*c3963bc0SZev Weiss if (err < 0) 2391*c3963bc0SZev Weiss return err; 2392*c3963bc0SZev Weiss 2393*c3963bc0SZev Weiss if (val > 1) 2394*c3963bc0SZev Weiss return -EINVAL; 2395*c3963bc0SZev Weiss 2396*c3963bc0SZev Weiss /* Setting DC mode (0) is not supported for all chips/channels */ 2397*c3963bc0SZev Weiss if (data->REG_PWM_MODE[nr] == 0) { 2398*c3963bc0SZev Weiss if (!val) 2399*c3963bc0SZev Weiss return -EINVAL; 2400*c3963bc0SZev Weiss return count; 2401*c3963bc0SZev Weiss } 2402*c3963bc0SZev Weiss 2403*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2404*c3963bc0SZev Weiss data->pwm_mode[nr] = val; 2405*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_PWM_MODE[nr], ®); 2406*c3963bc0SZev Weiss if (err) 2407*c3963bc0SZev Weiss goto out; 2408*c3963bc0SZev Weiss reg &= ~data->PWM_MODE_MASK[nr]; 2409*c3963bc0SZev Weiss if (!val) 2410*c3963bc0SZev Weiss reg |= data->PWM_MODE_MASK[nr]; 2411*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); 2412*c3963bc0SZev Weiss out: 2413*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2414*c3963bc0SZev Weiss return err ? : count; 2415*c3963bc0SZev Weiss } 2416*c3963bc0SZev Weiss 2417*c3963bc0SZev Weiss static ssize_t 2418*c3963bc0SZev Weiss show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 2419*c3963bc0SZev Weiss { 2420*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2421*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2422*c3963bc0SZev Weiss int nr = sattr->nr; 2423*c3963bc0SZev Weiss int index = sattr->index; 2424*c3963bc0SZev Weiss int err; 2425*c3963bc0SZev Weiss u16 pwm; 2426*c3963bc0SZev Weiss 2427*c3963bc0SZev Weiss if (IS_ERR(data)) 2428*c3963bc0SZev Weiss return PTR_ERR(data); 2429*c3963bc0SZev Weiss 2430*c3963bc0SZev Weiss /* 2431*c3963bc0SZev Weiss * For automatic fan control modes, show current pwm readings. 2432*c3963bc0SZev Weiss * Otherwise, show the configured value. 2433*c3963bc0SZev Weiss */ 2434*c3963bc0SZev Weiss if (index == 0 && data->pwm_enable[nr] > manual) { 2435*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_PWM_READ[nr], &pwm); 2436*c3963bc0SZev Weiss if (err) 2437*c3963bc0SZev Weiss return err; 2438*c3963bc0SZev Weiss } else { 2439*c3963bc0SZev Weiss pwm = data->pwm[index][nr]; 2440*c3963bc0SZev Weiss } 2441*c3963bc0SZev Weiss 2442*c3963bc0SZev Weiss return sprintf(buf, "%d\n", pwm); 2443*c3963bc0SZev Weiss } 2444*c3963bc0SZev Weiss 2445*c3963bc0SZev Weiss static ssize_t 2446*c3963bc0SZev Weiss store_pwm(struct device *dev, struct device_attribute *attr, const char *buf, 2447*c3963bc0SZev Weiss size_t count) 2448*c3963bc0SZev Weiss { 2449*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2450*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2451*c3963bc0SZev Weiss int nr = sattr->nr; 2452*c3963bc0SZev Weiss int index = sattr->index; 2453*c3963bc0SZev Weiss unsigned long val; 2454*c3963bc0SZev Weiss int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 }; 2455*c3963bc0SZev Weiss int maxval[7] 2456*c3963bc0SZev Weiss = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 }; 2457*c3963bc0SZev Weiss int err; 2458*c3963bc0SZev Weiss u16 reg; 2459*c3963bc0SZev Weiss 2460*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2461*c3963bc0SZev Weiss if (err < 0) 2462*c3963bc0SZev Weiss return err; 2463*c3963bc0SZev Weiss val = clamp_val(val, minval[index], maxval[index]); 2464*c3963bc0SZev Weiss 2465*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2466*c3963bc0SZev Weiss data->pwm[index][nr] = val; 2467*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_PWM[index][nr], val); 2468*c3963bc0SZev Weiss if (err) 2469*c3963bc0SZev Weiss goto out; 2470*c3963bc0SZev Weiss if (index == 2) { /* floor: disable if val == 0 */ 2471*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SEL[nr], ®); 2472*c3963bc0SZev Weiss if (err) 2473*c3963bc0SZev Weiss goto out; 2474*c3963bc0SZev Weiss reg &= 0x7f; 2475*c3963bc0SZev Weiss if (val) 2476*c3963bc0SZev Weiss reg |= 0x80; 2477*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg); 2478*c3963bc0SZev Weiss } 2479*c3963bc0SZev Weiss out: 2480*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2481*c3963bc0SZev Weiss return err ? : count; 2482*c3963bc0SZev Weiss } 2483*c3963bc0SZev Weiss 2484*c3963bc0SZev Weiss /* Returns 0 if OK, -EINVAL otherwise */ 2485*c3963bc0SZev Weiss static int check_trip_points(struct nct6775_data *data, int nr) 2486*c3963bc0SZev Weiss { 2487*c3963bc0SZev Weiss int i; 2488*c3963bc0SZev Weiss 2489*c3963bc0SZev Weiss for (i = 0; i < data->auto_pwm_num - 1; i++) { 2490*c3963bc0SZev Weiss if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1]) 2491*c3963bc0SZev Weiss return -EINVAL; 2492*c3963bc0SZev Weiss } 2493*c3963bc0SZev Weiss for (i = 0; i < data->auto_pwm_num - 1; i++) { 2494*c3963bc0SZev Weiss if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1]) 2495*c3963bc0SZev Weiss return -EINVAL; 2496*c3963bc0SZev Weiss } 2497*c3963bc0SZev Weiss /* validate critical temperature and pwm if enabled (pwm > 0) */ 2498*c3963bc0SZev Weiss if (data->auto_pwm[nr][data->auto_pwm_num]) { 2499*c3963bc0SZev Weiss if (data->auto_temp[nr][data->auto_pwm_num - 1] > 2500*c3963bc0SZev Weiss data->auto_temp[nr][data->auto_pwm_num] || 2501*c3963bc0SZev Weiss data->auto_pwm[nr][data->auto_pwm_num - 1] > 2502*c3963bc0SZev Weiss data->auto_pwm[nr][data->auto_pwm_num]) 2503*c3963bc0SZev Weiss return -EINVAL; 2504*c3963bc0SZev Weiss } 2505*c3963bc0SZev Weiss return 0; 2506*c3963bc0SZev Weiss } 2507*c3963bc0SZev Weiss 2508*c3963bc0SZev Weiss static int pwm_update_registers(struct nct6775_data *data, int nr) 2509*c3963bc0SZev Weiss { 2510*c3963bc0SZev Weiss u16 reg; 2511*c3963bc0SZev Weiss int err; 2512*c3963bc0SZev Weiss 2513*c3963bc0SZev Weiss switch (data->pwm_enable[nr]) { 2514*c3963bc0SZev Weiss case off: 2515*c3963bc0SZev Weiss case manual: 2516*c3963bc0SZev Weiss break; 2517*c3963bc0SZev Weiss case speed_cruise: 2518*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_MODE[nr], ®); 2519*c3963bc0SZev Weiss if (err) 2520*c3963bc0SZev Weiss return err; 2521*c3963bc0SZev Weiss reg = (reg & ~data->tolerance_mask) | 2522*c3963bc0SZev Weiss (data->target_speed_tolerance[nr] & data->tolerance_mask); 2523*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg); 2524*c3963bc0SZev Weiss if (err) 2525*c3963bc0SZev Weiss return err; 2526*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TARGET[nr], 2527*c3963bc0SZev Weiss data->target_speed[nr] & 0xff); 2528*c3963bc0SZev Weiss if (err) 2529*c3963bc0SZev Weiss return err; 2530*c3963bc0SZev Weiss if (data->REG_TOLERANCE_H) { 2531*c3963bc0SZev Weiss reg = (data->target_speed[nr] >> 8) & 0x0f; 2532*c3963bc0SZev Weiss reg |= (data->target_speed_tolerance[nr] & 0x38) << 1; 2533*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TOLERANCE_H[nr], reg); 2534*c3963bc0SZev Weiss if (err) 2535*c3963bc0SZev Weiss return err; 2536*c3963bc0SZev Weiss } 2537*c3963bc0SZev Weiss break; 2538*c3963bc0SZev Weiss case thermal_cruise: 2539*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TARGET[nr], data->target_temp[nr]); 2540*c3963bc0SZev Weiss if (err) 2541*c3963bc0SZev Weiss return err; 2542*c3963bc0SZev Weiss fallthrough; 2543*c3963bc0SZev Weiss default: 2544*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_MODE[nr], ®); 2545*c3963bc0SZev Weiss if (err) 2546*c3963bc0SZev Weiss return err; 2547*c3963bc0SZev Weiss reg = (reg & ~data->tolerance_mask) | 2548*c3963bc0SZev Weiss data->temp_tolerance[0][nr]; 2549*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg); 2550*c3963bc0SZev Weiss if (err) 2551*c3963bc0SZev Weiss return err; 2552*c3963bc0SZev Weiss break; 2553*c3963bc0SZev Weiss } 2554*c3963bc0SZev Weiss 2555*c3963bc0SZev Weiss return 0; 2556*c3963bc0SZev Weiss } 2557*c3963bc0SZev Weiss 2558*c3963bc0SZev Weiss static ssize_t 2559*c3963bc0SZev Weiss show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 2560*c3963bc0SZev Weiss { 2561*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2562*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2563*c3963bc0SZev Weiss 2564*c3963bc0SZev Weiss if (IS_ERR(data)) 2565*c3963bc0SZev Weiss return PTR_ERR(data); 2566*c3963bc0SZev Weiss 2567*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]); 2568*c3963bc0SZev Weiss } 2569*c3963bc0SZev Weiss 2570*c3963bc0SZev Weiss static ssize_t 2571*c3963bc0SZev Weiss store_pwm_enable(struct device *dev, struct device_attribute *attr, 2572*c3963bc0SZev Weiss const char *buf, size_t count) 2573*c3963bc0SZev Weiss { 2574*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2575*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2576*c3963bc0SZev Weiss int nr = sattr->index; 2577*c3963bc0SZev Weiss unsigned long val; 2578*c3963bc0SZev Weiss int err; 2579*c3963bc0SZev Weiss u16 reg; 2580*c3963bc0SZev Weiss 2581*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2582*c3963bc0SZev Weiss if (err < 0) 2583*c3963bc0SZev Weiss return err; 2584*c3963bc0SZev Weiss 2585*c3963bc0SZev Weiss if (val > sf4) 2586*c3963bc0SZev Weiss return -EINVAL; 2587*c3963bc0SZev Weiss 2588*c3963bc0SZev Weiss if (val == sf3 && data->kind != nct6775) 2589*c3963bc0SZev Weiss return -EINVAL; 2590*c3963bc0SZev Weiss 2591*c3963bc0SZev Weiss if (val == sf4 && check_trip_points(data, nr)) { 2592*c3963bc0SZev Weiss dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n"); 2593*c3963bc0SZev Weiss dev_err(dev, "Adjust trip points and try again\n"); 2594*c3963bc0SZev Weiss return -EINVAL; 2595*c3963bc0SZev Weiss } 2596*c3963bc0SZev Weiss 2597*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2598*c3963bc0SZev Weiss data->pwm_enable[nr] = val; 2599*c3963bc0SZev Weiss if (val == off) { 2600*c3963bc0SZev Weiss /* 2601*c3963bc0SZev Weiss * turn off pwm control: select manual mode, set pwm to maximum 2602*c3963bc0SZev Weiss */ 2603*c3963bc0SZev Weiss data->pwm[0][nr] = 255; 2604*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_PWM[0][nr], 255); 2605*c3963bc0SZev Weiss if (err) 2606*c3963bc0SZev Weiss goto out; 2607*c3963bc0SZev Weiss } 2608*c3963bc0SZev Weiss err = pwm_update_registers(data, nr); 2609*c3963bc0SZev Weiss if (err) 2610*c3963bc0SZev Weiss goto out; 2611*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_FAN_MODE[nr], ®); 2612*c3963bc0SZev Weiss if (err) 2613*c3963bc0SZev Weiss goto out; 2614*c3963bc0SZev Weiss reg &= 0x0f; 2615*c3963bc0SZev Weiss reg |= pwm_enable_to_reg(val) << 4; 2616*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg); 2617*c3963bc0SZev Weiss out: 2618*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2619*c3963bc0SZev Weiss return err ? : count; 2620*c3963bc0SZev Weiss } 2621*c3963bc0SZev Weiss 2622*c3963bc0SZev Weiss static ssize_t 2623*c3963bc0SZev Weiss show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src) 2624*c3963bc0SZev Weiss { 2625*c3963bc0SZev Weiss int i, sel = 0; 2626*c3963bc0SZev Weiss 2627*c3963bc0SZev Weiss for (i = 0; i < NUM_TEMP; i++) { 2628*c3963bc0SZev Weiss if (!(data->have_temp & BIT(i))) 2629*c3963bc0SZev Weiss continue; 2630*c3963bc0SZev Weiss if (src == data->temp_src[i]) { 2631*c3963bc0SZev Weiss sel = i + 1; 2632*c3963bc0SZev Weiss break; 2633*c3963bc0SZev Weiss } 2634*c3963bc0SZev Weiss } 2635*c3963bc0SZev Weiss 2636*c3963bc0SZev Weiss return sprintf(buf, "%d\n", sel); 2637*c3963bc0SZev Weiss } 2638*c3963bc0SZev Weiss 2639*c3963bc0SZev Weiss static ssize_t 2640*c3963bc0SZev Weiss show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf) 2641*c3963bc0SZev Weiss { 2642*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2643*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2644*c3963bc0SZev Weiss int index = sattr->index; 2645*c3963bc0SZev Weiss 2646*c3963bc0SZev Weiss if (IS_ERR(data)) 2647*c3963bc0SZev Weiss return PTR_ERR(data); 2648*c3963bc0SZev Weiss 2649*c3963bc0SZev Weiss return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]); 2650*c3963bc0SZev Weiss } 2651*c3963bc0SZev Weiss 2652*c3963bc0SZev Weiss static ssize_t 2653*c3963bc0SZev Weiss store_pwm_temp_sel(struct device *dev, struct device_attribute *attr, 2654*c3963bc0SZev Weiss const char *buf, size_t count) 2655*c3963bc0SZev Weiss { 2656*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2657*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2658*c3963bc0SZev Weiss int nr = sattr->index; 2659*c3963bc0SZev Weiss unsigned long val; 2660*c3963bc0SZev Weiss int err, src; 2661*c3963bc0SZev Weiss u16 reg; 2662*c3963bc0SZev Weiss 2663*c3963bc0SZev Weiss if (IS_ERR(data)) 2664*c3963bc0SZev Weiss return PTR_ERR(data); 2665*c3963bc0SZev Weiss 2666*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2667*c3963bc0SZev Weiss if (err < 0) 2668*c3963bc0SZev Weiss return err; 2669*c3963bc0SZev Weiss if (val == 0 || val > NUM_TEMP) 2670*c3963bc0SZev Weiss return -EINVAL; 2671*c3963bc0SZev Weiss if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1]) 2672*c3963bc0SZev Weiss return -EINVAL; 2673*c3963bc0SZev Weiss 2674*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2675*c3963bc0SZev Weiss src = data->temp_src[val - 1]; 2676*c3963bc0SZev Weiss data->pwm_temp_sel[nr] = src; 2677*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SEL[nr], ®); 2678*c3963bc0SZev Weiss if (err) 2679*c3963bc0SZev Weiss goto out; 2680*c3963bc0SZev Weiss reg &= 0xe0; 2681*c3963bc0SZev Weiss reg |= src; 2682*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg); 2683*c3963bc0SZev Weiss out: 2684*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2685*c3963bc0SZev Weiss 2686*c3963bc0SZev Weiss return err ? : count; 2687*c3963bc0SZev Weiss } 2688*c3963bc0SZev Weiss 2689*c3963bc0SZev Weiss static ssize_t 2690*c3963bc0SZev Weiss show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, 2691*c3963bc0SZev Weiss char *buf) 2692*c3963bc0SZev Weiss { 2693*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2694*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2695*c3963bc0SZev Weiss int index = sattr->index; 2696*c3963bc0SZev Weiss 2697*c3963bc0SZev Weiss if (IS_ERR(data)) 2698*c3963bc0SZev Weiss return PTR_ERR(data); 2699*c3963bc0SZev Weiss 2700*c3963bc0SZev Weiss return show_pwm_temp_sel_common(data, buf, 2701*c3963bc0SZev Weiss data->pwm_weight_temp_sel[index]); 2702*c3963bc0SZev Weiss } 2703*c3963bc0SZev Weiss 2704*c3963bc0SZev Weiss static ssize_t 2705*c3963bc0SZev Weiss store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, 2706*c3963bc0SZev Weiss const char *buf, size_t count) 2707*c3963bc0SZev Weiss { 2708*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2709*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2710*c3963bc0SZev Weiss int nr = sattr->index; 2711*c3963bc0SZev Weiss unsigned long val; 2712*c3963bc0SZev Weiss int err, src; 2713*c3963bc0SZev Weiss u16 reg; 2714*c3963bc0SZev Weiss 2715*c3963bc0SZev Weiss if (IS_ERR(data)) 2716*c3963bc0SZev Weiss return PTR_ERR(data); 2717*c3963bc0SZev Weiss 2718*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2719*c3963bc0SZev Weiss if (err < 0) 2720*c3963bc0SZev Weiss return err; 2721*c3963bc0SZev Weiss if (val > NUM_TEMP) 2722*c3963bc0SZev Weiss return -EINVAL; 2723*c3963bc0SZev Weiss val = array_index_nospec(val, NUM_TEMP + 1); 2724*c3963bc0SZev Weiss if (val && (!(data->have_temp & BIT(val - 1)) || 2725*c3963bc0SZev Weiss !data->temp_src[val - 1])) 2726*c3963bc0SZev Weiss return -EINVAL; 2727*c3963bc0SZev Weiss 2728*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2729*c3963bc0SZev Weiss if (val) { 2730*c3963bc0SZev Weiss src = data->temp_src[val - 1]; 2731*c3963bc0SZev Weiss data->pwm_weight_temp_sel[nr] = src; 2732*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr], ®); 2733*c3963bc0SZev Weiss if (err) 2734*c3963bc0SZev Weiss goto out; 2735*c3963bc0SZev Weiss reg &= 0xe0; 2736*c3963bc0SZev Weiss reg |= (src | 0x80); 2737*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg); 2738*c3963bc0SZev Weiss } else { 2739*c3963bc0SZev Weiss data->pwm_weight_temp_sel[nr] = 0; 2740*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr], ®); 2741*c3963bc0SZev Weiss if (err) 2742*c3963bc0SZev Weiss goto out; 2743*c3963bc0SZev Weiss reg &= 0x7f; 2744*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg); 2745*c3963bc0SZev Weiss } 2746*c3963bc0SZev Weiss out: 2747*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2748*c3963bc0SZev Weiss 2749*c3963bc0SZev Weiss return err ? : count; 2750*c3963bc0SZev Weiss } 2751*c3963bc0SZev Weiss 2752*c3963bc0SZev Weiss static ssize_t 2753*c3963bc0SZev Weiss show_target_temp(struct device *dev, struct device_attribute *attr, char *buf) 2754*c3963bc0SZev Weiss { 2755*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2756*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2757*c3963bc0SZev Weiss 2758*c3963bc0SZev Weiss if (IS_ERR(data)) 2759*c3963bc0SZev Weiss return PTR_ERR(data); 2760*c3963bc0SZev Weiss 2761*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000); 2762*c3963bc0SZev Weiss } 2763*c3963bc0SZev Weiss 2764*c3963bc0SZev Weiss static ssize_t 2765*c3963bc0SZev Weiss store_target_temp(struct device *dev, struct device_attribute *attr, 2766*c3963bc0SZev Weiss const char *buf, size_t count) 2767*c3963bc0SZev Weiss { 2768*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2769*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2770*c3963bc0SZev Weiss int nr = sattr->index; 2771*c3963bc0SZev Weiss unsigned long val; 2772*c3963bc0SZev Weiss int err; 2773*c3963bc0SZev Weiss 2774*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2775*c3963bc0SZev Weiss if (err < 0) 2776*c3963bc0SZev Weiss return err; 2777*c3963bc0SZev Weiss 2778*c3963bc0SZev Weiss val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 2779*c3963bc0SZev Weiss data->target_temp_mask); 2780*c3963bc0SZev Weiss 2781*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2782*c3963bc0SZev Weiss data->target_temp[nr] = val; 2783*c3963bc0SZev Weiss err = pwm_update_registers(data, nr); 2784*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2785*c3963bc0SZev Weiss return err ? : count; 2786*c3963bc0SZev Weiss } 2787*c3963bc0SZev Weiss 2788*c3963bc0SZev Weiss static ssize_t 2789*c3963bc0SZev Weiss show_target_speed(struct device *dev, struct device_attribute *attr, char *buf) 2790*c3963bc0SZev Weiss { 2791*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2792*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2793*c3963bc0SZev Weiss int nr = sattr->index; 2794*c3963bc0SZev Weiss 2795*c3963bc0SZev Weiss if (IS_ERR(data)) 2796*c3963bc0SZev Weiss return PTR_ERR(data); 2797*c3963bc0SZev Weiss 2798*c3963bc0SZev Weiss return sprintf(buf, "%d\n", 2799*c3963bc0SZev Weiss fan_from_reg16(data->target_speed[nr], 2800*c3963bc0SZev Weiss data->fan_div[nr])); 2801*c3963bc0SZev Weiss } 2802*c3963bc0SZev Weiss 2803*c3963bc0SZev Weiss static ssize_t 2804*c3963bc0SZev Weiss store_target_speed(struct device *dev, struct device_attribute *attr, 2805*c3963bc0SZev Weiss const char *buf, size_t count) 2806*c3963bc0SZev Weiss { 2807*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2808*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2809*c3963bc0SZev Weiss int nr = sattr->index; 2810*c3963bc0SZev Weiss unsigned long val; 2811*c3963bc0SZev Weiss int err; 2812*c3963bc0SZev Weiss u16 speed; 2813*c3963bc0SZev Weiss 2814*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2815*c3963bc0SZev Weiss if (err < 0) 2816*c3963bc0SZev Weiss return err; 2817*c3963bc0SZev Weiss 2818*c3963bc0SZev Weiss val = clamp_val(val, 0, 1350000U); 2819*c3963bc0SZev Weiss speed = fan_to_reg(val, data->fan_div[nr]); 2820*c3963bc0SZev Weiss 2821*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2822*c3963bc0SZev Weiss data->target_speed[nr] = speed; 2823*c3963bc0SZev Weiss err = pwm_update_registers(data, nr); 2824*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2825*c3963bc0SZev Weiss return err ? : count; 2826*c3963bc0SZev Weiss } 2827*c3963bc0SZev Weiss 2828*c3963bc0SZev Weiss static ssize_t 2829*c3963bc0SZev Weiss show_temp_tolerance(struct device *dev, struct device_attribute *attr, 2830*c3963bc0SZev Weiss char *buf) 2831*c3963bc0SZev Weiss { 2832*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2833*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2834*c3963bc0SZev Weiss int nr = sattr->nr; 2835*c3963bc0SZev Weiss int index = sattr->index; 2836*c3963bc0SZev Weiss 2837*c3963bc0SZev Weiss if (IS_ERR(data)) 2838*c3963bc0SZev Weiss return PTR_ERR(data); 2839*c3963bc0SZev Weiss 2840*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000); 2841*c3963bc0SZev Weiss } 2842*c3963bc0SZev Weiss 2843*c3963bc0SZev Weiss static ssize_t 2844*c3963bc0SZev Weiss store_temp_tolerance(struct device *dev, struct device_attribute *attr, 2845*c3963bc0SZev Weiss const char *buf, size_t count) 2846*c3963bc0SZev Weiss { 2847*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2848*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2849*c3963bc0SZev Weiss int nr = sattr->nr; 2850*c3963bc0SZev Weiss int index = sattr->index; 2851*c3963bc0SZev Weiss unsigned long val; 2852*c3963bc0SZev Weiss int err; 2853*c3963bc0SZev Weiss 2854*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2855*c3963bc0SZev Weiss if (err < 0) 2856*c3963bc0SZev Weiss return err; 2857*c3963bc0SZev Weiss 2858*c3963bc0SZev Weiss /* Limit tolerance as needed */ 2859*c3963bc0SZev Weiss val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask); 2860*c3963bc0SZev Weiss 2861*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2862*c3963bc0SZev Weiss data->temp_tolerance[index][nr] = val; 2863*c3963bc0SZev Weiss if (index) 2864*c3963bc0SZev Weiss err = pwm_update_registers(data, nr); 2865*c3963bc0SZev Weiss else 2866*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_CRITICAL_TEMP_TOLERANCE[nr], val); 2867*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2868*c3963bc0SZev Weiss return err ? : count; 2869*c3963bc0SZev Weiss } 2870*c3963bc0SZev Weiss 2871*c3963bc0SZev Weiss /* 2872*c3963bc0SZev Weiss * Fan speed tolerance is a tricky beast, since the associated register is 2873*c3963bc0SZev Weiss * a tick counter, but the value is reported and configured as rpm. 2874*c3963bc0SZev Weiss * Compute resulting low and high rpm values and report the difference. 2875*c3963bc0SZev Weiss * A fan speed tolerance only makes sense if a fan target speed has been 2876*c3963bc0SZev Weiss * configured, so only display values other than 0 if that is the case. 2877*c3963bc0SZev Weiss */ 2878*c3963bc0SZev Weiss static ssize_t 2879*c3963bc0SZev Weiss show_speed_tolerance(struct device *dev, struct device_attribute *attr, 2880*c3963bc0SZev Weiss char *buf) 2881*c3963bc0SZev Weiss { 2882*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2883*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2884*c3963bc0SZev Weiss int nr = sattr->index; 2885*c3963bc0SZev Weiss int target, tolerance = 0; 2886*c3963bc0SZev Weiss 2887*c3963bc0SZev Weiss if (IS_ERR(data)) 2888*c3963bc0SZev Weiss return PTR_ERR(data); 2889*c3963bc0SZev Weiss 2890*c3963bc0SZev Weiss target = data->target_speed[nr]; 2891*c3963bc0SZev Weiss 2892*c3963bc0SZev Weiss if (target) { 2893*c3963bc0SZev Weiss int low = target - data->target_speed_tolerance[nr]; 2894*c3963bc0SZev Weiss int high = target + data->target_speed_tolerance[nr]; 2895*c3963bc0SZev Weiss 2896*c3963bc0SZev Weiss if (low <= 0) 2897*c3963bc0SZev Weiss low = 1; 2898*c3963bc0SZev Weiss if (high > 0xffff) 2899*c3963bc0SZev Weiss high = 0xffff; 2900*c3963bc0SZev Weiss if (high < low) 2901*c3963bc0SZev Weiss high = low; 2902*c3963bc0SZev Weiss 2903*c3963bc0SZev Weiss tolerance = (fan_from_reg16(low, data->fan_div[nr]) 2904*c3963bc0SZev Weiss - fan_from_reg16(high, data->fan_div[nr])) / 2; 2905*c3963bc0SZev Weiss } 2906*c3963bc0SZev Weiss 2907*c3963bc0SZev Weiss return sprintf(buf, "%d\n", tolerance); 2908*c3963bc0SZev Weiss } 2909*c3963bc0SZev Weiss 2910*c3963bc0SZev Weiss static ssize_t 2911*c3963bc0SZev Weiss store_speed_tolerance(struct device *dev, struct device_attribute *attr, 2912*c3963bc0SZev Weiss const char *buf, size_t count) 2913*c3963bc0SZev Weiss { 2914*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2915*c3963bc0SZev Weiss struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 2916*c3963bc0SZev Weiss int nr = sattr->index; 2917*c3963bc0SZev Weiss unsigned long val; 2918*c3963bc0SZev Weiss int err; 2919*c3963bc0SZev Weiss int low, high; 2920*c3963bc0SZev Weiss 2921*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2922*c3963bc0SZev Weiss if (err < 0) 2923*c3963bc0SZev Weiss return err; 2924*c3963bc0SZev Weiss 2925*c3963bc0SZev Weiss high = fan_from_reg16(data->target_speed[nr], data->fan_div[nr]) + val; 2926*c3963bc0SZev Weiss low = fan_from_reg16(data->target_speed[nr], data->fan_div[nr]) - val; 2927*c3963bc0SZev Weiss if (low <= 0) 2928*c3963bc0SZev Weiss low = 1; 2929*c3963bc0SZev Weiss if (high < low) 2930*c3963bc0SZev Weiss high = low; 2931*c3963bc0SZev Weiss 2932*c3963bc0SZev Weiss val = (fan_to_reg(low, data->fan_div[nr]) - 2933*c3963bc0SZev Weiss fan_to_reg(high, data->fan_div[nr])) / 2; 2934*c3963bc0SZev Weiss 2935*c3963bc0SZev Weiss /* Limit tolerance as needed */ 2936*c3963bc0SZev Weiss val = clamp_val(val, 0, data->speed_tolerance_limit); 2937*c3963bc0SZev Weiss 2938*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2939*c3963bc0SZev Weiss data->target_speed_tolerance[nr] = val; 2940*c3963bc0SZev Weiss err = pwm_update_registers(data, nr); 2941*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2942*c3963bc0SZev Weiss return err ? : count; 2943*c3963bc0SZev Weiss } 2944*c3963bc0SZev Weiss 2945*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm, "pwm%d", 0644, show_pwm, store_pwm, 0, 0); 2946*c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", 0644, show_pwm_mode, store_pwm_mode, 0); 2947*c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", 0644, show_pwm_enable, store_pwm_enable, 0); 2948*c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", 0644, show_pwm_temp_sel, store_pwm_temp_sel, 0); 2949*c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", 0644, show_target_temp, store_target_temp, 0); 2950*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_target, "fan%d_target", 0644, show_target_speed, store_target_speed, 0); 2951*c3963bc0SZev Weiss SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", 0644, show_speed_tolerance, 2952*c3963bc0SZev Weiss store_speed_tolerance, 0); 2953*c3963bc0SZev Weiss 2954*c3963bc0SZev Weiss /* Smart Fan registers */ 2955*c3963bc0SZev Weiss 2956*c3963bc0SZev Weiss static ssize_t 2957*c3963bc0SZev Weiss show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf) 2958*c3963bc0SZev Weiss { 2959*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 2960*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2961*c3963bc0SZev Weiss int nr = sattr->nr; 2962*c3963bc0SZev Weiss int index = sattr->index; 2963*c3963bc0SZev Weiss 2964*c3963bc0SZev Weiss if (IS_ERR(data)) 2965*c3963bc0SZev Weiss return PTR_ERR(data); 2966*c3963bc0SZev Weiss 2967*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000); 2968*c3963bc0SZev Weiss } 2969*c3963bc0SZev Weiss 2970*c3963bc0SZev Weiss static ssize_t 2971*c3963bc0SZev Weiss store_weight_temp(struct device *dev, struct device_attribute *attr, 2972*c3963bc0SZev Weiss const char *buf, size_t count) 2973*c3963bc0SZev Weiss { 2974*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 2975*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 2976*c3963bc0SZev Weiss int nr = sattr->nr; 2977*c3963bc0SZev Weiss int index = sattr->index; 2978*c3963bc0SZev Weiss unsigned long val; 2979*c3963bc0SZev Weiss int err; 2980*c3963bc0SZev Weiss 2981*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 2982*c3963bc0SZev Weiss if (err < 0) 2983*c3963bc0SZev Weiss return err; 2984*c3963bc0SZev Weiss 2985*c3963bc0SZev Weiss val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255); 2986*c3963bc0SZev Weiss 2987*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 2988*c3963bc0SZev Weiss data->weight_temp[index][nr] = val; 2989*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val); 2990*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 2991*c3963bc0SZev Weiss return err ? : count; 2992*c3963bc0SZev Weiss } 2993*c3963bc0SZev Weiss 2994*c3963bc0SZev Weiss SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", 0644, 2995*c3963bc0SZev Weiss show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0); 2996*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step", 2997*c3963bc0SZev Weiss 0644, show_weight_temp, store_weight_temp, 0, 0); 2998*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol", 2999*c3963bc0SZev Weiss 0644, show_weight_temp, store_weight_temp, 0, 1); 3000*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base", 3001*c3963bc0SZev Weiss 0644, show_weight_temp, store_weight_temp, 0, 2); 3002*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step", 0644, show_pwm, store_pwm, 0, 5); 3003*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base", 0644, show_pwm, store_pwm, 0, 6); 3004*c3963bc0SZev Weiss 3005*c3963bc0SZev Weiss static ssize_t 3006*c3963bc0SZev Weiss show_fan_time(struct device *dev, struct device_attribute *attr, char *buf) 3007*c3963bc0SZev Weiss { 3008*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 3009*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 3010*c3963bc0SZev Weiss int nr = sattr->nr; 3011*c3963bc0SZev Weiss int index = sattr->index; 3012*c3963bc0SZev Weiss 3013*c3963bc0SZev Weiss if (IS_ERR(data)) 3014*c3963bc0SZev Weiss return PTR_ERR(data); 3015*c3963bc0SZev Weiss 3016*c3963bc0SZev Weiss return sprintf(buf, "%d\n", 3017*c3963bc0SZev Weiss step_time_from_reg(data->fan_time[index][nr], 3018*c3963bc0SZev Weiss data->pwm_mode[nr])); 3019*c3963bc0SZev Weiss } 3020*c3963bc0SZev Weiss 3021*c3963bc0SZev Weiss static ssize_t 3022*c3963bc0SZev Weiss store_fan_time(struct device *dev, struct device_attribute *attr, 3023*c3963bc0SZev Weiss const char *buf, size_t count) 3024*c3963bc0SZev Weiss { 3025*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 3026*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 3027*c3963bc0SZev Weiss int nr = sattr->nr; 3028*c3963bc0SZev Weiss int index = sattr->index; 3029*c3963bc0SZev Weiss unsigned long val; 3030*c3963bc0SZev Weiss int err; 3031*c3963bc0SZev Weiss 3032*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 3033*c3963bc0SZev Weiss if (err < 0) 3034*c3963bc0SZev Weiss return err; 3035*c3963bc0SZev Weiss 3036*c3963bc0SZev Weiss val = step_time_to_reg(val, data->pwm_mode[nr]); 3037*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 3038*c3963bc0SZev Weiss data->fan_time[index][nr] = val; 3039*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val); 3040*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 3041*c3963bc0SZev Weiss return err ? : count; 3042*c3963bc0SZev Weiss } 3043*c3963bc0SZev Weiss 3044*c3963bc0SZev Weiss static ssize_t 3045*c3963bc0SZev Weiss show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf) 3046*c3963bc0SZev Weiss { 3047*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 3048*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 3049*c3963bc0SZev Weiss 3050*c3963bc0SZev Weiss if (IS_ERR(data)) 3051*c3963bc0SZev Weiss return PTR_ERR(data); 3052*c3963bc0SZev Weiss 3053*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]); 3054*c3963bc0SZev Weiss } 3055*c3963bc0SZev Weiss 3056*c3963bc0SZev Weiss static ssize_t 3057*c3963bc0SZev Weiss store_auto_pwm(struct device *dev, struct device_attribute *attr, 3058*c3963bc0SZev Weiss const char *buf, size_t count) 3059*c3963bc0SZev Weiss { 3060*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 3061*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 3062*c3963bc0SZev Weiss int nr = sattr->nr; 3063*c3963bc0SZev Weiss int point = sattr->index; 3064*c3963bc0SZev Weiss unsigned long val; 3065*c3963bc0SZev Weiss int err; 3066*c3963bc0SZev Weiss u16 reg; 3067*c3963bc0SZev Weiss 3068*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 3069*c3963bc0SZev Weiss if (err < 0) 3070*c3963bc0SZev Weiss return err; 3071*c3963bc0SZev Weiss if (val > 255) 3072*c3963bc0SZev Weiss return -EINVAL; 3073*c3963bc0SZev Weiss 3074*c3963bc0SZev Weiss if (point == data->auto_pwm_num) { 3075*c3963bc0SZev Weiss if (data->kind != nct6775 && !val) 3076*c3963bc0SZev Weiss return -EINVAL; 3077*c3963bc0SZev Weiss if (data->kind != nct6779 && val) 3078*c3963bc0SZev Weiss val = 0xff; 3079*c3963bc0SZev Weiss } 3080*c3963bc0SZev Weiss 3081*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 3082*c3963bc0SZev Weiss data->auto_pwm[nr][point] = val; 3083*c3963bc0SZev Weiss if (point < data->auto_pwm_num) { 3084*c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_AUTO_PWM(data, nr, point), 3085*c3963bc0SZev Weiss data->auto_pwm[nr][point]); 3086*c3963bc0SZev Weiss } else { 3087*c3963bc0SZev Weiss switch (data->kind) { 3088*c3963bc0SZev Weiss case nct6775: 3089*c3963bc0SZev Weiss /* disable if needed (pwm == 0) */ 3090*c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_CRITICAL_ENAB[nr], ®); 3091*c3963bc0SZev Weiss if (err) 3092*c3963bc0SZev Weiss break; 3093*c3963bc0SZev Weiss if (val) 3094*c3963bc0SZev Weiss reg |= 0x02; 3095*c3963bc0SZev Weiss else 3096*c3963bc0SZev Weiss reg &= ~0x02; 3097*c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr], reg); 3098*c3963bc0SZev Weiss break; 3099*c3963bc0SZev Weiss case nct6776: 3100*c3963bc0SZev Weiss break; /* always enabled, nothing to do */ 3101*c3963bc0SZev Weiss case nct6106: 3102*c3963bc0SZev Weiss case nct6116: 3103*c3963bc0SZev Weiss case nct6779: 3104*c3963bc0SZev Weiss case nct6791: 3105*c3963bc0SZev Weiss case nct6792: 3106*c3963bc0SZev Weiss case nct6793: 3107*c3963bc0SZev Weiss case nct6795: 3108*c3963bc0SZev Weiss case nct6796: 3109*c3963bc0SZev Weiss case nct6797: 3110*c3963bc0SZev Weiss case nct6798: 3111*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); 3112*c3963bc0SZev Weiss if (err) 3113*c3963bc0SZev Weiss break; 3114*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[nr], ®); 3115*c3963bc0SZev Weiss if (err) 3116*c3963bc0SZev Weiss break; 3117*c3963bc0SZev Weiss if (val == 255) 3118*c3963bc0SZev Weiss reg &= ~data->CRITICAL_PWM_ENABLE_MASK; 3119*c3963bc0SZev Weiss else 3120*c3963bc0SZev Weiss reg |= data->CRITICAL_PWM_ENABLE_MASK; 3121*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_CRITICAL_PWM_ENABLE[nr], reg); 3122*c3963bc0SZev Weiss break; 3123*c3963bc0SZev Weiss } 3124*c3963bc0SZev Weiss } 3125*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 3126*c3963bc0SZev Weiss return err ? : count; 3127*c3963bc0SZev Weiss } 3128*c3963bc0SZev Weiss 3129*c3963bc0SZev Weiss static ssize_t 3130*c3963bc0SZev Weiss show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf) 3131*c3963bc0SZev Weiss { 3132*c3963bc0SZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 3133*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 3134*c3963bc0SZev Weiss int nr = sattr->nr; 3135*c3963bc0SZev Weiss int point = sattr->index; 3136*c3963bc0SZev Weiss 3137*c3963bc0SZev Weiss if (IS_ERR(data)) 3138*c3963bc0SZev Weiss return PTR_ERR(data); 3139*c3963bc0SZev Weiss 3140*c3963bc0SZev Weiss /* 3141*c3963bc0SZev Weiss * We don't know for sure if the temperature is signed or unsigned. 3142*c3963bc0SZev Weiss * Assume it is unsigned. 3143*c3963bc0SZev Weiss */ 3144*c3963bc0SZev Weiss return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000); 3145*c3963bc0SZev Weiss } 3146*c3963bc0SZev Weiss 3147*c3963bc0SZev Weiss static ssize_t 3148*c3963bc0SZev Weiss store_auto_temp(struct device *dev, struct device_attribute *attr, 3149*c3963bc0SZev Weiss const char *buf, size_t count) 3150*c3963bc0SZev Weiss { 3151*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 3152*c3963bc0SZev Weiss struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 3153*c3963bc0SZev Weiss int nr = sattr->nr; 3154*c3963bc0SZev Weiss int point = sattr->index; 3155*c3963bc0SZev Weiss unsigned long val; 3156*c3963bc0SZev Weiss int err; 3157*c3963bc0SZev Weiss 3158*c3963bc0SZev Weiss err = kstrtoul(buf, 10, &val); 3159*c3963bc0SZev Weiss if (err) 3160*c3963bc0SZev Weiss return err; 3161*c3963bc0SZev Weiss if (val > 255000) 3162*c3963bc0SZev Weiss return -EINVAL; 3163*c3963bc0SZev Weiss 3164*c3963bc0SZev Weiss mutex_lock(&data->update_lock); 3165*c3963bc0SZev Weiss data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000); 3166*c3963bc0SZev Weiss if (point < data->auto_pwm_num) { 3167*c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_AUTO_TEMP(data, nr, point), 3168*c3963bc0SZev Weiss data->auto_temp[nr][point]); 3169*c3963bc0SZev Weiss } else { 3170*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr], 3171*c3963bc0SZev Weiss data->auto_temp[nr][point]); 3172*c3963bc0SZev Weiss } 3173*c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 3174*c3963bc0SZev Weiss return err ? : count; 3175*c3963bc0SZev Weiss } 3176*c3963bc0SZev Weiss 3177*c3963bc0SZev Weiss static umode_t nct6775_pwm_is_visible(struct kobject *kobj, 3178*c3963bc0SZev Weiss struct attribute *attr, int index) 3179*c3963bc0SZev Weiss { 3180*c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 3181*c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 3182*c3963bc0SZev Weiss int pwm = index / 36; /* pwm index */ 3183*c3963bc0SZev Weiss int nr = index % 36; /* attribute index */ 3184*c3963bc0SZev Weiss 3185*c3963bc0SZev Weiss if (!(data->has_pwm & BIT(pwm))) 3186*c3963bc0SZev Weiss return 0; 3187*c3963bc0SZev Weiss 3188*c3963bc0SZev Weiss if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */ 3189*c3963bc0SZev Weiss if (!data->REG_WEIGHT_TEMP_SEL[pwm]) 3190*c3963bc0SZev Weiss return 0; 3191*c3963bc0SZev Weiss if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */ 3192*c3963bc0SZev Weiss return 0; 3193*c3963bc0SZev Weiss if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */ 3194*c3963bc0SZev Weiss return 0; 3195*c3963bc0SZev Weiss if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */ 3196*c3963bc0SZev Weiss return 0; 3197*c3963bc0SZev Weiss 3198*c3963bc0SZev Weiss if (nr >= 22 && nr <= 35) { /* auto point */ 3199*c3963bc0SZev Weiss int api = (nr - 22) / 2; /* auto point index */ 3200*c3963bc0SZev Weiss 3201*c3963bc0SZev Weiss if (api > data->auto_pwm_num) 3202*c3963bc0SZev Weiss return 0; 3203*c3963bc0SZev Weiss } 3204*c3963bc0SZev Weiss return nct6775_attr_mode(data, attr); 3205*c3963bc0SZev Weiss } 3206*c3963bc0SZev Weiss 3207*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", 0644, show_fan_time, store_fan_time, 0, 0); 3208*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", 0644, 3209*c3963bc0SZev Weiss show_fan_time, store_fan_time, 0, 1); 3210*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", 0644, 3211*c3963bc0SZev Weiss show_fan_time, store_fan_time, 0, 2); 3212*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", 0644, show_pwm, store_pwm, 0, 1); 3213*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", 0644, show_pwm, store_pwm, 0, 2); 3214*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", 0644, 3215*c3963bc0SZev Weiss show_temp_tolerance, store_temp_tolerance, 0, 0); 3216*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance", 3217*c3963bc0SZev Weiss 0644, show_temp_tolerance, store_temp_tolerance, 0, 1); 3218*c3963bc0SZev Weiss 3219*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", 0644, show_pwm, store_pwm, 0, 3); 3220*c3963bc0SZev Weiss 3221*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", 0644, show_pwm, store_pwm, 0, 4); 3222*c3963bc0SZev Weiss 3223*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm", 3224*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 0); 3225*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp", 3226*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 0); 3227*c3963bc0SZev Weiss 3228*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm", 3229*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 1); 3230*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp", 3231*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 1); 3232*c3963bc0SZev Weiss 3233*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm", 3234*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 2); 3235*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp", 3236*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 2); 3237*c3963bc0SZev Weiss 3238*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm", 3239*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 3); 3240*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp", 3241*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 3); 3242*c3963bc0SZev Weiss 3243*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm", 3244*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 4); 3245*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp", 3246*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 4); 3247*c3963bc0SZev Weiss 3248*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm", 3249*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 5); 3250*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp", 3251*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 5); 3252*c3963bc0SZev Weiss 3253*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm", 3254*c3963bc0SZev Weiss 0644, show_auto_pwm, store_auto_pwm, 0, 6); 3255*c3963bc0SZev Weiss SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp", 3256*c3963bc0SZev Weiss 0644, show_auto_temp, store_auto_temp, 0, 6); 3257*c3963bc0SZev Weiss 3258*c3963bc0SZev Weiss /* 3259*c3963bc0SZev Weiss * nct6775_pwm_is_visible uses the index into the following array 3260*c3963bc0SZev Weiss * to determine if attributes should be created or not. 3261*c3963bc0SZev Weiss * Any change in order or content must be matched. 3262*c3963bc0SZev Weiss */ 3263*c3963bc0SZev Weiss static struct sensor_device_template *nct6775_attributes_pwm_template[] = { 3264*c3963bc0SZev Weiss &sensor_dev_template_pwm, 3265*c3963bc0SZev Weiss &sensor_dev_template_pwm_mode, 3266*c3963bc0SZev Weiss &sensor_dev_template_pwm_enable, 3267*c3963bc0SZev Weiss &sensor_dev_template_pwm_temp_sel, 3268*c3963bc0SZev Weiss &sensor_dev_template_pwm_temp_tolerance, 3269*c3963bc0SZev Weiss &sensor_dev_template_pwm_crit_temp_tolerance, 3270*c3963bc0SZev Weiss &sensor_dev_template_pwm_target_temp, 3271*c3963bc0SZev Weiss &sensor_dev_template_fan_target, 3272*c3963bc0SZev Weiss &sensor_dev_template_fan_tolerance, 3273*c3963bc0SZev Weiss &sensor_dev_template_pwm_stop_time, 3274*c3963bc0SZev Weiss &sensor_dev_template_pwm_step_up_time, 3275*c3963bc0SZev Weiss &sensor_dev_template_pwm_step_down_time, 3276*c3963bc0SZev Weiss &sensor_dev_template_pwm_start, 3277*c3963bc0SZev Weiss &sensor_dev_template_pwm_floor, 3278*c3963bc0SZev Weiss &sensor_dev_template_pwm_weight_temp_sel, /* 14 */ 3279*c3963bc0SZev Weiss &sensor_dev_template_pwm_weight_temp_step, 3280*c3963bc0SZev Weiss &sensor_dev_template_pwm_weight_temp_step_tol, 3281*c3963bc0SZev Weiss &sensor_dev_template_pwm_weight_temp_step_base, 3282*c3963bc0SZev Weiss &sensor_dev_template_pwm_weight_duty_step, /* 18 */ 3283*c3963bc0SZev Weiss &sensor_dev_template_pwm_max, /* 19 */ 3284*c3963bc0SZev Weiss &sensor_dev_template_pwm_step, /* 20 */ 3285*c3963bc0SZev Weiss &sensor_dev_template_pwm_weight_duty_base, /* 21 */ 3286*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */ 3287*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point1_temp, 3288*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point2_pwm, 3289*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point2_temp, 3290*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point3_pwm, 3291*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point3_temp, 3292*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point4_pwm, 3293*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point4_temp, 3294*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point5_pwm, 3295*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point5_temp, 3296*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point6_pwm, 3297*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point6_temp, 3298*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point7_pwm, 3299*c3963bc0SZev Weiss &sensor_dev_template_pwm_auto_point7_temp, /* 35 */ 3300*c3963bc0SZev Weiss 3301*c3963bc0SZev Weiss NULL 3302*c3963bc0SZev Weiss }; 3303*c3963bc0SZev Weiss 3304*c3963bc0SZev Weiss static const struct sensor_template_group nct6775_pwm_template_group = { 3305*c3963bc0SZev Weiss .templates = nct6775_attributes_pwm_template, 3306*c3963bc0SZev Weiss .is_visible = nct6775_pwm_is_visible, 3307*c3963bc0SZev Weiss .base = 1, 3308*c3963bc0SZev Weiss }; 3309*c3963bc0SZev Weiss 3310*c3963bc0SZev Weiss static inline int nct6775_init_device(struct nct6775_data *data) 3311*c3963bc0SZev Weiss { 3312*c3963bc0SZev Weiss int i, err; 3313*c3963bc0SZev Weiss u16 tmp, diode; 3314*c3963bc0SZev Weiss 3315*c3963bc0SZev Weiss /* Start monitoring if needed */ 3316*c3963bc0SZev Weiss if (data->REG_CONFIG) { 3317*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_CONFIG, &tmp); 3318*c3963bc0SZev Weiss if (err) 3319*c3963bc0SZev Weiss return err; 3320*c3963bc0SZev Weiss if (!(tmp & 0x01)) { 3321*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01); 3322*c3963bc0SZev Weiss if (err) 3323*c3963bc0SZev Weiss return err; 3324*c3963bc0SZev Weiss } 3325*c3963bc0SZev Weiss } 3326*c3963bc0SZev Weiss 3327*c3963bc0SZev Weiss /* Enable temperature sensors if needed */ 3328*c3963bc0SZev Weiss for (i = 0; i < NUM_TEMP; i++) { 3329*c3963bc0SZev Weiss if (!(data->have_temp & BIT(i))) 3330*c3963bc0SZev Weiss continue; 3331*c3963bc0SZev Weiss if (!data->reg_temp_config[i]) 3332*c3963bc0SZev Weiss continue; 3333*c3963bc0SZev Weiss err = nct6775_read_value(data, data->reg_temp_config[i], &tmp); 3334*c3963bc0SZev Weiss if (err) 3335*c3963bc0SZev Weiss return err; 3336*c3963bc0SZev Weiss if (tmp & 0x01) { 3337*c3963bc0SZev Weiss err = nct6775_write_value(data, data->reg_temp_config[i], tmp & 0xfe); 3338*c3963bc0SZev Weiss if (err) 3339*c3963bc0SZev Weiss return err; 3340*c3963bc0SZev Weiss } 3341*c3963bc0SZev Weiss } 3342*c3963bc0SZev Weiss 3343*c3963bc0SZev Weiss /* Enable VBAT monitoring if needed */ 3344*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_VBAT, &tmp); 3345*c3963bc0SZev Weiss if (err) 3346*c3963bc0SZev Weiss return err; 3347*c3963bc0SZev Weiss if (!(tmp & 0x01)) { 3348*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_VBAT, tmp | 0x01); 3349*c3963bc0SZev Weiss if (err) 3350*c3963bc0SZev Weiss return err; 3351*c3963bc0SZev Weiss } 3352*c3963bc0SZev Weiss 3353*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_DIODE, &diode); 3354*c3963bc0SZev Weiss if (err) 3355*c3963bc0SZev Weiss return err; 3356*c3963bc0SZev Weiss 3357*c3963bc0SZev Weiss for (i = 0; i < data->temp_fixed_num; i++) { 3358*c3963bc0SZev Weiss if (!(data->have_temp_fixed & BIT(i))) 3359*c3963bc0SZev Weiss continue; 3360*c3963bc0SZev Weiss if ((tmp & (data->DIODE_MASK << i))) /* diode */ 3361*c3963bc0SZev Weiss data->temp_type[i] 3362*c3963bc0SZev Weiss = 3 - ((diode >> i) & data->DIODE_MASK); 3363*c3963bc0SZev Weiss else /* thermistor */ 3364*c3963bc0SZev Weiss data->temp_type[i] = 4; 3365*c3963bc0SZev Weiss } 3366*c3963bc0SZev Weiss 3367*c3963bc0SZev Weiss return 0; 3368*c3963bc0SZev Weiss } 3369*c3963bc0SZev Weiss 3370*c3963bc0SZev Weiss static int add_temp_sensors(struct nct6775_data *data, const u16 *regp, 3371*c3963bc0SZev Weiss int *available, int *mask) 3372*c3963bc0SZev Weiss { 3373*c3963bc0SZev Weiss int i, err; 3374*c3963bc0SZev Weiss u16 src; 3375*c3963bc0SZev Weiss 3376*c3963bc0SZev Weiss for (i = 0; i < data->pwm_num && *available; i++) { 3377*c3963bc0SZev Weiss int index; 3378*c3963bc0SZev Weiss 3379*c3963bc0SZev Weiss if (!regp[i]) 3380*c3963bc0SZev Weiss continue; 3381*c3963bc0SZev Weiss err = nct6775_read_value(data, regp[i], &src); 3382*c3963bc0SZev Weiss if (err) 3383*c3963bc0SZev Weiss return err; 3384*c3963bc0SZev Weiss src &= 0x1f; 3385*c3963bc0SZev Weiss if (!src || (*mask & BIT(src))) 3386*c3963bc0SZev Weiss continue; 3387*c3963bc0SZev Weiss if (!(data->temp_mask & BIT(src))) 3388*c3963bc0SZev Weiss continue; 3389*c3963bc0SZev Weiss 3390*c3963bc0SZev Weiss index = __ffs(*available); 3391*c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src); 3392*c3963bc0SZev Weiss if (err) 3393*c3963bc0SZev Weiss return err; 3394*c3963bc0SZev Weiss *available &= ~BIT(index); 3395*c3963bc0SZev Weiss *mask |= BIT(src); 3396*c3963bc0SZev Weiss } 3397*c3963bc0SZev Weiss 3398*c3963bc0SZev Weiss return 0; 3399*c3963bc0SZev Weiss } 3400*c3963bc0SZev Weiss 3401*c3963bc0SZev Weiss int nct6775_probe(struct device *dev, struct nct6775_data *data, 3402*c3963bc0SZev Weiss const struct regmap_config *regmapcfg) 3403*c3963bc0SZev Weiss { 3404*c3963bc0SZev Weiss int i, s, err = 0; 3405*c3963bc0SZev Weiss int mask, available; 3406*c3963bc0SZev Weiss u16 src; 3407*c3963bc0SZev Weiss const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config; 3408*c3963bc0SZev Weiss const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit; 3409*c3963bc0SZev Weiss const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL; 3410*c3963bc0SZev Weiss int num_reg_temp, num_reg_temp_mon, num_reg_tsi_temp; 3411*c3963bc0SZev Weiss struct device *hwmon_dev; 3412*c3963bc0SZev Weiss struct sensor_template_group tsi_temp_tg; 3413*c3963bc0SZev Weiss 3414*c3963bc0SZev Weiss data->regmap = devm_regmap_init(dev, NULL, data, regmapcfg); 3415*c3963bc0SZev Weiss if (IS_ERR(data->regmap)) 3416*c3963bc0SZev Weiss return PTR_ERR(data->regmap); 3417*c3963bc0SZev Weiss 3418*c3963bc0SZev Weiss mutex_init(&data->update_lock); 3419*c3963bc0SZev Weiss data->name = nct6775_device_names[data->kind]; 3420*c3963bc0SZev Weiss data->bank = 0xff; /* Force initial bank selection */ 3421*c3963bc0SZev Weiss 3422*c3963bc0SZev Weiss switch (data->kind) { 3423*c3963bc0SZev Weiss case nct6106: 3424*c3963bc0SZev Weiss data->in_num = 9; 3425*c3963bc0SZev Weiss data->pwm_num = 3; 3426*c3963bc0SZev Weiss data->auto_pwm_num = 4; 3427*c3963bc0SZev Weiss data->temp_fixed_num = 3; 3428*c3963bc0SZev Weiss data->num_temp_alarms = 6; 3429*c3963bc0SZev Weiss data->num_temp_beeps = 6; 3430*c3963bc0SZev Weiss 3431*c3963bc0SZev Weiss data->fan_from_reg = fan_from_reg13; 3432*c3963bc0SZev Weiss data->fan_from_reg_min = fan_from_reg13; 3433*c3963bc0SZev Weiss 3434*c3963bc0SZev Weiss data->temp_label = nct6776_temp_label; 3435*c3963bc0SZev Weiss data->temp_mask = NCT6776_TEMP_MASK; 3436*c3963bc0SZev Weiss data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK; 3437*c3963bc0SZev Weiss 3438*c3963bc0SZev Weiss data->REG_VBAT = NCT6106_REG_VBAT; 3439*c3963bc0SZev Weiss data->REG_DIODE = NCT6106_REG_DIODE; 3440*c3963bc0SZev Weiss data->DIODE_MASK = NCT6106_DIODE_MASK; 3441*c3963bc0SZev Weiss data->REG_VIN = NCT6106_REG_IN; 3442*c3963bc0SZev Weiss data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN; 3443*c3963bc0SZev Weiss data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX; 3444*c3963bc0SZev Weiss data->REG_TARGET = NCT6106_REG_TARGET; 3445*c3963bc0SZev Weiss data->REG_FAN = NCT6106_REG_FAN; 3446*c3963bc0SZev Weiss data->REG_FAN_MODE = NCT6106_REG_FAN_MODE; 3447*c3963bc0SZev Weiss data->REG_FAN_MIN = NCT6106_REG_FAN_MIN; 3448*c3963bc0SZev Weiss data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES; 3449*c3963bc0SZev Weiss data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT; 3450*c3963bc0SZev Weiss data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME; 3451*c3963bc0SZev Weiss data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME; 3452*c3963bc0SZev Weiss data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME; 3453*c3963bc0SZev Weiss data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H; 3454*c3963bc0SZev Weiss data->REG_PWM[0] = NCT6116_REG_PWM; 3455*c3963bc0SZev Weiss data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT; 3456*c3963bc0SZev Weiss data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT; 3457*c3963bc0SZev Weiss data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP; 3458*c3963bc0SZev Weiss data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE; 3459*c3963bc0SZev Weiss data->REG_PWM_READ = NCT6106_REG_PWM_READ; 3460*c3963bc0SZev Weiss data->REG_PWM_MODE = NCT6106_REG_PWM_MODE; 3461*c3963bc0SZev Weiss data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK; 3462*c3963bc0SZev Weiss data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP; 3463*c3963bc0SZev Weiss data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM; 3464*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP; 3465*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP_TOLERANCE 3466*c3963bc0SZev Weiss = NCT6106_REG_CRITICAL_TEMP_TOLERANCE; 3467*c3963bc0SZev Weiss data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE; 3468*c3963bc0SZev Weiss data->CRITICAL_PWM_ENABLE_MASK 3469*c3963bc0SZev Weiss = NCT6106_CRITICAL_PWM_ENABLE_MASK; 3470*c3963bc0SZev Weiss data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM; 3471*c3963bc0SZev Weiss data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET; 3472*c3963bc0SZev Weiss data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE; 3473*c3963bc0SZev Weiss data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL; 3474*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL; 3475*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP; 3476*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL; 3477*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE; 3478*c3963bc0SZev Weiss data->REG_ALARM = NCT6106_REG_ALARM; 3479*c3963bc0SZev Weiss data->ALARM_BITS = NCT6106_ALARM_BITS; 3480*c3963bc0SZev Weiss data->REG_BEEP = NCT6106_REG_BEEP; 3481*c3963bc0SZev Weiss data->BEEP_BITS = NCT6106_BEEP_BITS; 3482*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6106_REG_TSI_TEMP; 3483*c3963bc0SZev Weiss 3484*c3963bc0SZev Weiss reg_temp = NCT6106_REG_TEMP; 3485*c3963bc0SZev Weiss reg_temp_mon = NCT6106_REG_TEMP_MON; 3486*c3963bc0SZev Weiss num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP); 3487*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON); 3488*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6106_REG_TSI_TEMP); 3489*c3963bc0SZev Weiss reg_temp_over = NCT6106_REG_TEMP_OVER; 3490*c3963bc0SZev Weiss reg_temp_hyst = NCT6106_REG_TEMP_HYST; 3491*c3963bc0SZev Weiss reg_temp_config = NCT6106_REG_TEMP_CONFIG; 3492*c3963bc0SZev Weiss reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE; 3493*c3963bc0SZev Weiss reg_temp_crit = NCT6106_REG_TEMP_CRIT; 3494*c3963bc0SZev Weiss reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L; 3495*c3963bc0SZev Weiss reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H; 3496*c3963bc0SZev Weiss 3497*c3963bc0SZev Weiss break; 3498*c3963bc0SZev Weiss case nct6116: 3499*c3963bc0SZev Weiss data->in_num = 9; 3500*c3963bc0SZev Weiss data->pwm_num = 3; 3501*c3963bc0SZev Weiss data->auto_pwm_num = 4; 3502*c3963bc0SZev Weiss data->temp_fixed_num = 3; 3503*c3963bc0SZev Weiss data->num_temp_alarms = 3; 3504*c3963bc0SZev Weiss data->num_temp_beeps = 3; 3505*c3963bc0SZev Weiss 3506*c3963bc0SZev Weiss data->fan_from_reg = fan_from_reg13; 3507*c3963bc0SZev Weiss data->fan_from_reg_min = fan_from_reg13; 3508*c3963bc0SZev Weiss 3509*c3963bc0SZev Weiss data->temp_label = nct6776_temp_label; 3510*c3963bc0SZev Weiss data->temp_mask = NCT6776_TEMP_MASK; 3511*c3963bc0SZev Weiss data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK; 3512*c3963bc0SZev Weiss 3513*c3963bc0SZev Weiss data->REG_VBAT = NCT6106_REG_VBAT; 3514*c3963bc0SZev Weiss data->REG_DIODE = NCT6106_REG_DIODE; 3515*c3963bc0SZev Weiss data->DIODE_MASK = NCT6106_DIODE_MASK; 3516*c3963bc0SZev Weiss data->REG_VIN = NCT6106_REG_IN; 3517*c3963bc0SZev Weiss data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN; 3518*c3963bc0SZev Weiss data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX; 3519*c3963bc0SZev Weiss data->REG_TARGET = NCT6116_REG_TARGET; 3520*c3963bc0SZev Weiss data->REG_FAN = NCT6116_REG_FAN; 3521*c3963bc0SZev Weiss data->REG_FAN_MODE = NCT6116_REG_FAN_MODE; 3522*c3963bc0SZev Weiss data->REG_FAN_MIN = NCT6116_REG_FAN_MIN; 3523*c3963bc0SZev Weiss data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES; 3524*c3963bc0SZev Weiss data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT; 3525*c3963bc0SZev Weiss data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME; 3526*c3963bc0SZev Weiss data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME; 3527*c3963bc0SZev Weiss data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME; 3528*c3963bc0SZev Weiss data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H; 3529*c3963bc0SZev Weiss data->REG_PWM[0] = NCT6116_REG_PWM; 3530*c3963bc0SZev Weiss data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT; 3531*c3963bc0SZev Weiss data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT; 3532*c3963bc0SZev Weiss data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP; 3533*c3963bc0SZev Weiss data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE; 3534*c3963bc0SZev Weiss data->REG_PWM_READ = NCT6106_REG_PWM_READ; 3535*c3963bc0SZev Weiss data->REG_PWM_MODE = NCT6106_REG_PWM_MODE; 3536*c3963bc0SZev Weiss data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK; 3537*c3963bc0SZev Weiss data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP; 3538*c3963bc0SZev Weiss data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM; 3539*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP; 3540*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP_TOLERANCE 3541*c3963bc0SZev Weiss = NCT6116_REG_CRITICAL_TEMP_TOLERANCE; 3542*c3963bc0SZev Weiss data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE; 3543*c3963bc0SZev Weiss data->CRITICAL_PWM_ENABLE_MASK 3544*c3963bc0SZev Weiss = NCT6106_CRITICAL_PWM_ENABLE_MASK; 3545*c3963bc0SZev Weiss data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM; 3546*c3963bc0SZev Weiss data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET; 3547*c3963bc0SZev Weiss data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE; 3548*c3963bc0SZev Weiss data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL; 3549*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL; 3550*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP; 3551*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL; 3552*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE; 3553*c3963bc0SZev Weiss data->REG_ALARM = NCT6106_REG_ALARM; 3554*c3963bc0SZev Weiss data->ALARM_BITS = NCT6116_ALARM_BITS; 3555*c3963bc0SZev Weiss data->REG_BEEP = NCT6106_REG_BEEP; 3556*c3963bc0SZev Weiss data->BEEP_BITS = NCT6116_BEEP_BITS; 3557*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6116_REG_TSI_TEMP; 3558*c3963bc0SZev Weiss 3559*c3963bc0SZev Weiss reg_temp = NCT6106_REG_TEMP; 3560*c3963bc0SZev Weiss reg_temp_mon = NCT6106_REG_TEMP_MON; 3561*c3963bc0SZev Weiss num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP); 3562*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON); 3563*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6116_REG_TSI_TEMP); 3564*c3963bc0SZev Weiss reg_temp_over = NCT6106_REG_TEMP_OVER; 3565*c3963bc0SZev Weiss reg_temp_hyst = NCT6106_REG_TEMP_HYST; 3566*c3963bc0SZev Weiss reg_temp_config = NCT6106_REG_TEMP_CONFIG; 3567*c3963bc0SZev Weiss reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE; 3568*c3963bc0SZev Weiss reg_temp_crit = NCT6106_REG_TEMP_CRIT; 3569*c3963bc0SZev Weiss reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L; 3570*c3963bc0SZev Weiss reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H; 3571*c3963bc0SZev Weiss 3572*c3963bc0SZev Weiss break; 3573*c3963bc0SZev Weiss case nct6775: 3574*c3963bc0SZev Weiss data->in_num = 9; 3575*c3963bc0SZev Weiss data->pwm_num = 3; 3576*c3963bc0SZev Weiss data->auto_pwm_num = 6; 3577*c3963bc0SZev Weiss data->has_fan_div = true; 3578*c3963bc0SZev Weiss data->temp_fixed_num = 3; 3579*c3963bc0SZev Weiss data->num_temp_alarms = 3; 3580*c3963bc0SZev Weiss data->num_temp_beeps = 3; 3581*c3963bc0SZev Weiss 3582*c3963bc0SZev Weiss data->ALARM_BITS = NCT6775_ALARM_BITS; 3583*c3963bc0SZev Weiss data->BEEP_BITS = NCT6775_BEEP_BITS; 3584*c3963bc0SZev Weiss 3585*c3963bc0SZev Weiss data->fan_from_reg = fan_from_reg16; 3586*c3963bc0SZev Weiss data->fan_from_reg_min = fan_from_reg8; 3587*c3963bc0SZev Weiss data->target_temp_mask = 0x7f; 3588*c3963bc0SZev Weiss data->tolerance_mask = 0x0f; 3589*c3963bc0SZev Weiss data->speed_tolerance_limit = 15; 3590*c3963bc0SZev Weiss 3591*c3963bc0SZev Weiss data->temp_label = nct6775_temp_label; 3592*c3963bc0SZev Weiss data->temp_mask = NCT6775_TEMP_MASK; 3593*c3963bc0SZev Weiss data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK; 3594*c3963bc0SZev Weiss 3595*c3963bc0SZev Weiss data->REG_CONFIG = NCT6775_REG_CONFIG; 3596*c3963bc0SZev Weiss data->REG_VBAT = NCT6775_REG_VBAT; 3597*c3963bc0SZev Weiss data->REG_DIODE = NCT6775_REG_DIODE; 3598*c3963bc0SZev Weiss data->DIODE_MASK = NCT6775_DIODE_MASK; 3599*c3963bc0SZev Weiss data->REG_VIN = NCT6775_REG_IN; 3600*c3963bc0SZev Weiss data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; 3601*c3963bc0SZev Weiss data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; 3602*c3963bc0SZev Weiss data->REG_TARGET = NCT6775_REG_TARGET; 3603*c3963bc0SZev Weiss data->REG_FAN = NCT6775_REG_FAN; 3604*c3963bc0SZev Weiss data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; 3605*c3963bc0SZev Weiss data->REG_FAN_MIN = NCT6775_REG_FAN_MIN; 3606*c3963bc0SZev Weiss data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES; 3607*c3963bc0SZev Weiss data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT; 3608*c3963bc0SZev Weiss data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME; 3609*c3963bc0SZev Weiss data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME; 3610*c3963bc0SZev Weiss data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME; 3611*c3963bc0SZev Weiss data->REG_PWM[0] = NCT6775_REG_PWM; 3612*c3963bc0SZev Weiss data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT; 3613*c3963bc0SZev Weiss data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT; 3614*c3963bc0SZev Weiss data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT; 3615*c3963bc0SZev Weiss data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT; 3616*c3963bc0SZev Weiss data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP; 3617*c3963bc0SZev Weiss data->REG_PWM_READ = NCT6775_REG_PWM_READ; 3618*c3963bc0SZev Weiss data->REG_PWM_MODE = NCT6775_REG_PWM_MODE; 3619*c3963bc0SZev Weiss data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK; 3620*c3963bc0SZev Weiss data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP; 3621*c3963bc0SZev Weiss data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM; 3622*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP; 3623*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP_TOLERANCE 3624*c3963bc0SZev Weiss = NCT6775_REG_CRITICAL_TEMP_TOLERANCE; 3625*c3963bc0SZev Weiss data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; 3626*c3963bc0SZev Weiss data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; 3627*c3963bc0SZev Weiss data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL; 3628*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL; 3629*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP; 3630*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL; 3631*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE; 3632*c3963bc0SZev Weiss data->REG_ALARM = NCT6775_REG_ALARM; 3633*c3963bc0SZev Weiss data->REG_BEEP = NCT6775_REG_BEEP; 3634*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6775_REG_TSI_TEMP; 3635*c3963bc0SZev Weiss 3636*c3963bc0SZev Weiss reg_temp = NCT6775_REG_TEMP; 3637*c3963bc0SZev Weiss reg_temp_mon = NCT6775_REG_TEMP_MON; 3638*c3963bc0SZev Weiss num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); 3639*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON); 3640*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6775_REG_TSI_TEMP); 3641*c3963bc0SZev Weiss reg_temp_over = NCT6775_REG_TEMP_OVER; 3642*c3963bc0SZev Weiss reg_temp_hyst = NCT6775_REG_TEMP_HYST; 3643*c3963bc0SZev Weiss reg_temp_config = NCT6775_REG_TEMP_CONFIG; 3644*c3963bc0SZev Weiss reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE; 3645*c3963bc0SZev Weiss reg_temp_crit = NCT6775_REG_TEMP_CRIT; 3646*c3963bc0SZev Weiss 3647*c3963bc0SZev Weiss break; 3648*c3963bc0SZev Weiss case nct6776: 3649*c3963bc0SZev Weiss data->in_num = 9; 3650*c3963bc0SZev Weiss data->pwm_num = 3; 3651*c3963bc0SZev Weiss data->auto_pwm_num = 4; 3652*c3963bc0SZev Weiss data->has_fan_div = false; 3653*c3963bc0SZev Weiss data->temp_fixed_num = 3; 3654*c3963bc0SZev Weiss data->num_temp_alarms = 3; 3655*c3963bc0SZev Weiss data->num_temp_beeps = 6; 3656*c3963bc0SZev Weiss 3657*c3963bc0SZev Weiss data->ALARM_BITS = NCT6776_ALARM_BITS; 3658*c3963bc0SZev Weiss data->BEEP_BITS = NCT6776_BEEP_BITS; 3659*c3963bc0SZev Weiss 3660*c3963bc0SZev Weiss data->fan_from_reg = fan_from_reg13; 3661*c3963bc0SZev Weiss data->fan_from_reg_min = fan_from_reg13; 3662*c3963bc0SZev Weiss data->target_temp_mask = 0xff; 3663*c3963bc0SZev Weiss data->tolerance_mask = 0x07; 3664*c3963bc0SZev Weiss data->speed_tolerance_limit = 63; 3665*c3963bc0SZev Weiss 3666*c3963bc0SZev Weiss data->temp_label = nct6776_temp_label; 3667*c3963bc0SZev Weiss data->temp_mask = NCT6776_TEMP_MASK; 3668*c3963bc0SZev Weiss data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK; 3669*c3963bc0SZev Weiss 3670*c3963bc0SZev Weiss data->REG_CONFIG = NCT6775_REG_CONFIG; 3671*c3963bc0SZev Weiss data->REG_VBAT = NCT6775_REG_VBAT; 3672*c3963bc0SZev Weiss data->REG_DIODE = NCT6775_REG_DIODE; 3673*c3963bc0SZev Weiss data->DIODE_MASK = NCT6775_DIODE_MASK; 3674*c3963bc0SZev Weiss data->REG_VIN = NCT6775_REG_IN; 3675*c3963bc0SZev Weiss data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; 3676*c3963bc0SZev Weiss data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; 3677*c3963bc0SZev Weiss data->REG_TARGET = NCT6775_REG_TARGET; 3678*c3963bc0SZev Weiss data->REG_FAN = NCT6775_REG_FAN; 3679*c3963bc0SZev Weiss data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; 3680*c3963bc0SZev Weiss data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; 3681*c3963bc0SZev Weiss data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES; 3682*c3963bc0SZev Weiss data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT; 3683*c3963bc0SZev Weiss data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME; 3684*c3963bc0SZev Weiss data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME; 3685*c3963bc0SZev Weiss data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME; 3686*c3963bc0SZev Weiss data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H; 3687*c3963bc0SZev Weiss data->REG_PWM[0] = NCT6775_REG_PWM; 3688*c3963bc0SZev Weiss data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT; 3689*c3963bc0SZev Weiss data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT; 3690*c3963bc0SZev Weiss data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP; 3691*c3963bc0SZev Weiss data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE; 3692*c3963bc0SZev Weiss data->REG_PWM_READ = NCT6775_REG_PWM_READ; 3693*c3963bc0SZev Weiss data->REG_PWM_MODE = NCT6776_REG_PWM_MODE; 3694*c3963bc0SZev Weiss data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK; 3695*c3963bc0SZev Weiss data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP; 3696*c3963bc0SZev Weiss data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM; 3697*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP; 3698*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP_TOLERANCE 3699*c3963bc0SZev Weiss = NCT6775_REG_CRITICAL_TEMP_TOLERANCE; 3700*c3963bc0SZev Weiss data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; 3701*c3963bc0SZev Weiss data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; 3702*c3963bc0SZev Weiss data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL; 3703*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL; 3704*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP; 3705*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL; 3706*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE; 3707*c3963bc0SZev Weiss data->REG_ALARM = NCT6775_REG_ALARM; 3708*c3963bc0SZev Weiss data->REG_BEEP = NCT6776_REG_BEEP; 3709*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6776_REG_TSI_TEMP; 3710*c3963bc0SZev Weiss 3711*c3963bc0SZev Weiss reg_temp = NCT6775_REG_TEMP; 3712*c3963bc0SZev Weiss reg_temp_mon = NCT6775_REG_TEMP_MON; 3713*c3963bc0SZev Weiss num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); 3714*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON); 3715*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6776_REG_TSI_TEMP); 3716*c3963bc0SZev Weiss reg_temp_over = NCT6775_REG_TEMP_OVER; 3717*c3963bc0SZev Weiss reg_temp_hyst = NCT6775_REG_TEMP_HYST; 3718*c3963bc0SZev Weiss reg_temp_config = NCT6776_REG_TEMP_CONFIG; 3719*c3963bc0SZev Weiss reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE; 3720*c3963bc0SZev Weiss reg_temp_crit = NCT6776_REG_TEMP_CRIT; 3721*c3963bc0SZev Weiss 3722*c3963bc0SZev Weiss break; 3723*c3963bc0SZev Weiss case nct6779: 3724*c3963bc0SZev Weiss data->in_num = 15; 3725*c3963bc0SZev Weiss data->pwm_num = 5; 3726*c3963bc0SZev Weiss data->auto_pwm_num = 4; 3727*c3963bc0SZev Weiss data->has_fan_div = false; 3728*c3963bc0SZev Weiss data->temp_fixed_num = 6; 3729*c3963bc0SZev Weiss data->num_temp_alarms = 2; 3730*c3963bc0SZev Weiss data->num_temp_beeps = 2; 3731*c3963bc0SZev Weiss 3732*c3963bc0SZev Weiss data->ALARM_BITS = NCT6779_ALARM_BITS; 3733*c3963bc0SZev Weiss data->BEEP_BITS = NCT6779_BEEP_BITS; 3734*c3963bc0SZev Weiss 3735*c3963bc0SZev Weiss data->fan_from_reg = fan_from_reg_rpm; 3736*c3963bc0SZev Weiss data->fan_from_reg_min = fan_from_reg13; 3737*c3963bc0SZev Weiss data->target_temp_mask = 0xff; 3738*c3963bc0SZev Weiss data->tolerance_mask = 0x07; 3739*c3963bc0SZev Weiss data->speed_tolerance_limit = 63; 3740*c3963bc0SZev Weiss 3741*c3963bc0SZev Weiss data->temp_label = nct6779_temp_label; 3742*c3963bc0SZev Weiss data->temp_mask = NCT6779_TEMP_MASK; 3743*c3963bc0SZev Weiss data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK; 3744*c3963bc0SZev Weiss 3745*c3963bc0SZev Weiss data->REG_CONFIG = NCT6775_REG_CONFIG; 3746*c3963bc0SZev Weiss data->REG_VBAT = NCT6775_REG_VBAT; 3747*c3963bc0SZev Weiss data->REG_DIODE = NCT6775_REG_DIODE; 3748*c3963bc0SZev Weiss data->DIODE_MASK = NCT6775_DIODE_MASK; 3749*c3963bc0SZev Weiss data->REG_VIN = NCT6779_REG_IN; 3750*c3963bc0SZev Weiss data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; 3751*c3963bc0SZev Weiss data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; 3752*c3963bc0SZev Weiss data->REG_TARGET = NCT6775_REG_TARGET; 3753*c3963bc0SZev Weiss data->REG_FAN = NCT6779_REG_FAN; 3754*c3963bc0SZev Weiss data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; 3755*c3963bc0SZev Weiss data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; 3756*c3963bc0SZev Weiss data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES; 3757*c3963bc0SZev Weiss data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT; 3758*c3963bc0SZev Weiss data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME; 3759*c3963bc0SZev Weiss data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME; 3760*c3963bc0SZev Weiss data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME; 3761*c3963bc0SZev Weiss data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H; 3762*c3963bc0SZev Weiss data->REG_PWM[0] = NCT6775_REG_PWM; 3763*c3963bc0SZev Weiss data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT; 3764*c3963bc0SZev Weiss data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT; 3765*c3963bc0SZev Weiss data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP; 3766*c3963bc0SZev Weiss data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE; 3767*c3963bc0SZev Weiss data->REG_PWM_READ = NCT6775_REG_PWM_READ; 3768*c3963bc0SZev Weiss data->REG_PWM_MODE = NCT6776_REG_PWM_MODE; 3769*c3963bc0SZev Weiss data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK; 3770*c3963bc0SZev Weiss data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP; 3771*c3963bc0SZev Weiss data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM; 3772*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP; 3773*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP_TOLERANCE 3774*c3963bc0SZev Weiss = NCT6775_REG_CRITICAL_TEMP_TOLERANCE; 3775*c3963bc0SZev Weiss data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE; 3776*c3963bc0SZev Weiss data->CRITICAL_PWM_ENABLE_MASK 3777*c3963bc0SZev Weiss = NCT6779_CRITICAL_PWM_ENABLE_MASK; 3778*c3963bc0SZev Weiss data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM; 3779*c3963bc0SZev Weiss data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; 3780*c3963bc0SZev Weiss data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; 3781*c3963bc0SZev Weiss data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL; 3782*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL; 3783*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP; 3784*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL; 3785*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE; 3786*c3963bc0SZev Weiss data->REG_ALARM = NCT6779_REG_ALARM; 3787*c3963bc0SZev Weiss data->REG_BEEP = NCT6776_REG_BEEP; 3788*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6776_REG_TSI_TEMP; 3789*c3963bc0SZev Weiss 3790*c3963bc0SZev Weiss reg_temp = NCT6779_REG_TEMP; 3791*c3963bc0SZev Weiss reg_temp_mon = NCT6779_REG_TEMP_MON; 3792*c3963bc0SZev Weiss num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); 3793*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); 3794*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6776_REG_TSI_TEMP); 3795*c3963bc0SZev Weiss reg_temp_over = NCT6779_REG_TEMP_OVER; 3796*c3963bc0SZev Weiss reg_temp_hyst = NCT6779_REG_TEMP_HYST; 3797*c3963bc0SZev Weiss reg_temp_config = NCT6779_REG_TEMP_CONFIG; 3798*c3963bc0SZev Weiss reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE; 3799*c3963bc0SZev Weiss reg_temp_crit = NCT6779_REG_TEMP_CRIT; 3800*c3963bc0SZev Weiss 3801*c3963bc0SZev Weiss break; 3802*c3963bc0SZev Weiss case nct6791: 3803*c3963bc0SZev Weiss case nct6792: 3804*c3963bc0SZev Weiss case nct6793: 3805*c3963bc0SZev Weiss case nct6795: 3806*c3963bc0SZev Weiss case nct6796: 3807*c3963bc0SZev Weiss case nct6797: 3808*c3963bc0SZev Weiss case nct6798: 3809*c3963bc0SZev Weiss data->in_num = 15; 3810*c3963bc0SZev Weiss data->pwm_num = (data->kind == nct6796 || 3811*c3963bc0SZev Weiss data->kind == nct6797 || 3812*c3963bc0SZev Weiss data->kind == nct6798) ? 7 : 6; 3813*c3963bc0SZev Weiss data->auto_pwm_num = 4; 3814*c3963bc0SZev Weiss data->has_fan_div = false; 3815*c3963bc0SZev Weiss data->temp_fixed_num = 6; 3816*c3963bc0SZev Weiss data->num_temp_alarms = 2; 3817*c3963bc0SZev Weiss data->num_temp_beeps = 2; 3818*c3963bc0SZev Weiss 3819*c3963bc0SZev Weiss data->ALARM_BITS = NCT6791_ALARM_BITS; 3820*c3963bc0SZev Weiss data->BEEP_BITS = NCT6779_BEEP_BITS; 3821*c3963bc0SZev Weiss 3822*c3963bc0SZev Weiss data->fan_from_reg = fan_from_reg_rpm; 3823*c3963bc0SZev Weiss data->fan_from_reg_min = fan_from_reg13; 3824*c3963bc0SZev Weiss data->target_temp_mask = 0xff; 3825*c3963bc0SZev Weiss data->tolerance_mask = 0x07; 3826*c3963bc0SZev Weiss data->speed_tolerance_limit = 63; 3827*c3963bc0SZev Weiss 3828*c3963bc0SZev Weiss switch (data->kind) { 3829*c3963bc0SZev Weiss default: 3830*c3963bc0SZev Weiss case nct6791: 3831*c3963bc0SZev Weiss data->temp_label = nct6779_temp_label; 3832*c3963bc0SZev Weiss data->temp_mask = NCT6791_TEMP_MASK; 3833*c3963bc0SZev Weiss data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK; 3834*c3963bc0SZev Weiss break; 3835*c3963bc0SZev Weiss case nct6792: 3836*c3963bc0SZev Weiss data->temp_label = nct6792_temp_label; 3837*c3963bc0SZev Weiss data->temp_mask = NCT6792_TEMP_MASK; 3838*c3963bc0SZev Weiss data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK; 3839*c3963bc0SZev Weiss break; 3840*c3963bc0SZev Weiss case nct6793: 3841*c3963bc0SZev Weiss data->temp_label = nct6793_temp_label; 3842*c3963bc0SZev Weiss data->temp_mask = NCT6793_TEMP_MASK; 3843*c3963bc0SZev Weiss data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK; 3844*c3963bc0SZev Weiss break; 3845*c3963bc0SZev Weiss case nct6795: 3846*c3963bc0SZev Weiss case nct6797: 3847*c3963bc0SZev Weiss data->temp_label = nct6795_temp_label; 3848*c3963bc0SZev Weiss data->temp_mask = NCT6795_TEMP_MASK; 3849*c3963bc0SZev Weiss data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK; 3850*c3963bc0SZev Weiss break; 3851*c3963bc0SZev Weiss case nct6796: 3852*c3963bc0SZev Weiss data->temp_label = nct6796_temp_label; 3853*c3963bc0SZev Weiss data->temp_mask = NCT6796_TEMP_MASK; 3854*c3963bc0SZev Weiss data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK; 3855*c3963bc0SZev Weiss break; 3856*c3963bc0SZev Weiss case nct6798: 3857*c3963bc0SZev Weiss data->temp_label = nct6798_temp_label; 3858*c3963bc0SZev Weiss data->temp_mask = NCT6798_TEMP_MASK; 3859*c3963bc0SZev Weiss data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK; 3860*c3963bc0SZev Weiss break; 3861*c3963bc0SZev Weiss } 3862*c3963bc0SZev Weiss 3863*c3963bc0SZev Weiss data->REG_CONFIG = NCT6775_REG_CONFIG; 3864*c3963bc0SZev Weiss data->REG_VBAT = NCT6775_REG_VBAT; 3865*c3963bc0SZev Weiss data->REG_DIODE = NCT6775_REG_DIODE; 3866*c3963bc0SZev Weiss data->DIODE_MASK = NCT6775_DIODE_MASK; 3867*c3963bc0SZev Weiss data->REG_VIN = NCT6779_REG_IN; 3868*c3963bc0SZev Weiss data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; 3869*c3963bc0SZev Weiss data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; 3870*c3963bc0SZev Weiss data->REG_TARGET = NCT6775_REG_TARGET; 3871*c3963bc0SZev Weiss data->REG_FAN = NCT6779_REG_FAN; 3872*c3963bc0SZev Weiss data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; 3873*c3963bc0SZev Weiss data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; 3874*c3963bc0SZev Weiss data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES; 3875*c3963bc0SZev Weiss data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT; 3876*c3963bc0SZev Weiss data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME; 3877*c3963bc0SZev Weiss data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME; 3878*c3963bc0SZev Weiss data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME; 3879*c3963bc0SZev Weiss data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H; 3880*c3963bc0SZev Weiss data->REG_PWM[0] = NCT6775_REG_PWM; 3881*c3963bc0SZev Weiss data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT; 3882*c3963bc0SZev Weiss data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT; 3883*c3963bc0SZev Weiss data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP; 3884*c3963bc0SZev Weiss data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE; 3885*c3963bc0SZev Weiss data->REG_PWM_READ = NCT6775_REG_PWM_READ; 3886*c3963bc0SZev Weiss data->REG_PWM_MODE = NCT6776_REG_PWM_MODE; 3887*c3963bc0SZev Weiss data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK; 3888*c3963bc0SZev Weiss data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP; 3889*c3963bc0SZev Weiss data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM; 3890*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP; 3891*c3963bc0SZev Weiss data->REG_CRITICAL_TEMP_TOLERANCE 3892*c3963bc0SZev Weiss = NCT6775_REG_CRITICAL_TEMP_TOLERANCE; 3893*c3963bc0SZev Weiss data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE; 3894*c3963bc0SZev Weiss data->CRITICAL_PWM_ENABLE_MASK 3895*c3963bc0SZev Weiss = NCT6779_CRITICAL_PWM_ENABLE_MASK; 3896*c3963bc0SZev Weiss data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM; 3897*c3963bc0SZev Weiss data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; 3898*c3963bc0SZev Weiss data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; 3899*c3963bc0SZev Weiss data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL; 3900*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL; 3901*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP; 3902*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL; 3903*c3963bc0SZev Weiss data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE; 3904*c3963bc0SZev Weiss data->REG_ALARM = NCT6791_REG_ALARM; 3905*c3963bc0SZev Weiss if (data->kind == nct6791) 3906*c3963bc0SZev Weiss data->REG_BEEP = NCT6776_REG_BEEP; 3907*c3963bc0SZev Weiss else 3908*c3963bc0SZev Weiss data->REG_BEEP = NCT6792_REG_BEEP; 3909*c3963bc0SZev Weiss switch (data->kind) { 3910*c3963bc0SZev Weiss case nct6791: 3911*c3963bc0SZev Weiss case nct6792: 3912*c3963bc0SZev Weiss case nct6793: 3913*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6776_REG_TSI_TEMP; 3914*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6776_REG_TSI_TEMP); 3915*c3963bc0SZev Weiss break; 3916*c3963bc0SZev Weiss case nct6795: 3917*c3963bc0SZev Weiss case nct6796: 3918*c3963bc0SZev Weiss case nct6797: 3919*c3963bc0SZev Weiss case nct6798: 3920*c3963bc0SZev Weiss data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP; 3921*c3963bc0SZev Weiss num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP); 3922*c3963bc0SZev Weiss break; 3923*c3963bc0SZev Weiss default: 3924*c3963bc0SZev Weiss num_reg_tsi_temp = 0; 3925*c3963bc0SZev Weiss break; 3926*c3963bc0SZev Weiss } 3927*c3963bc0SZev Weiss 3928*c3963bc0SZev Weiss reg_temp = NCT6779_REG_TEMP; 3929*c3963bc0SZev Weiss num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); 3930*c3963bc0SZev Weiss if (data->kind == nct6791) { 3931*c3963bc0SZev Weiss reg_temp_mon = NCT6779_REG_TEMP_MON; 3932*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); 3933*c3963bc0SZev Weiss } else { 3934*c3963bc0SZev Weiss reg_temp_mon = NCT6792_REG_TEMP_MON; 3935*c3963bc0SZev Weiss num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON); 3936*c3963bc0SZev Weiss } 3937*c3963bc0SZev Weiss reg_temp_over = NCT6779_REG_TEMP_OVER; 3938*c3963bc0SZev Weiss reg_temp_hyst = NCT6779_REG_TEMP_HYST; 3939*c3963bc0SZev Weiss reg_temp_config = NCT6779_REG_TEMP_CONFIG; 3940*c3963bc0SZev Weiss reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE; 3941*c3963bc0SZev Weiss reg_temp_crit = NCT6779_REG_TEMP_CRIT; 3942*c3963bc0SZev Weiss 3943*c3963bc0SZev Weiss break; 3944*c3963bc0SZev Weiss default: 3945*c3963bc0SZev Weiss return -ENODEV; 3946*c3963bc0SZev Weiss } 3947*c3963bc0SZev Weiss data->have_in = BIT(data->in_num) - 1; 3948*c3963bc0SZev Weiss data->have_temp = 0; 3949*c3963bc0SZev Weiss 3950*c3963bc0SZev Weiss /* 3951*c3963bc0SZev Weiss * On some boards, not all available temperature sources are monitored, 3952*c3963bc0SZev Weiss * even though some of the monitoring registers are unused. 3953*c3963bc0SZev Weiss * Get list of unused monitoring registers, then detect if any fan 3954*c3963bc0SZev Weiss * controls are configured to use unmonitored temperature sources. 3955*c3963bc0SZev Weiss * If so, assign the unmonitored temperature sources to available 3956*c3963bc0SZev Weiss * monitoring registers. 3957*c3963bc0SZev Weiss */ 3958*c3963bc0SZev Weiss mask = 0; 3959*c3963bc0SZev Weiss available = 0; 3960*c3963bc0SZev Weiss for (i = 0; i < num_reg_temp; i++) { 3961*c3963bc0SZev Weiss if (reg_temp[i] == 0) 3962*c3963bc0SZev Weiss continue; 3963*c3963bc0SZev Weiss 3964*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SOURCE[i], &src); 3965*c3963bc0SZev Weiss if (err) 3966*c3963bc0SZev Weiss return err; 3967*c3963bc0SZev Weiss src &= 0x1f; 3968*c3963bc0SZev Weiss if (!src || (mask & BIT(src))) 3969*c3963bc0SZev Weiss available |= BIT(i); 3970*c3963bc0SZev Weiss 3971*c3963bc0SZev Weiss mask |= BIT(src); 3972*c3963bc0SZev Weiss } 3973*c3963bc0SZev Weiss 3974*c3963bc0SZev Weiss /* 3975*c3963bc0SZev Weiss * Now find unmonitored temperature registers and enable monitoring 3976*c3963bc0SZev Weiss * if additional monitoring registers are available. 3977*c3963bc0SZev Weiss */ 3978*c3963bc0SZev Weiss err = add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask); 3979*c3963bc0SZev Weiss if (err) 3980*c3963bc0SZev Weiss return err; 3981*c3963bc0SZev Weiss err = add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask); 3982*c3963bc0SZev Weiss if (err) 3983*c3963bc0SZev Weiss return err; 3984*c3963bc0SZev Weiss 3985*c3963bc0SZev Weiss mask = 0; 3986*c3963bc0SZev Weiss s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */ 3987*c3963bc0SZev Weiss for (i = 0; i < num_reg_temp; i++) { 3988*c3963bc0SZev Weiss if (reg_temp[i] == 0) 3989*c3963bc0SZev Weiss continue; 3990*c3963bc0SZev Weiss 3991*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SOURCE[i], &src); 3992*c3963bc0SZev Weiss if (err) 3993*c3963bc0SZev Weiss return err; 3994*c3963bc0SZev Weiss src &= 0x1f; 3995*c3963bc0SZev Weiss if (!src || (mask & BIT(src))) 3996*c3963bc0SZev Weiss continue; 3997*c3963bc0SZev Weiss 3998*c3963bc0SZev Weiss if (!(data->temp_mask & BIT(src))) { 3999*c3963bc0SZev Weiss dev_info(dev, 4000*c3963bc0SZev Weiss "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", 4001*c3963bc0SZev Weiss src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]); 4002*c3963bc0SZev Weiss continue; 4003*c3963bc0SZev Weiss } 4004*c3963bc0SZev Weiss 4005*c3963bc0SZev Weiss mask |= BIT(src); 4006*c3963bc0SZev Weiss 4007*c3963bc0SZev Weiss /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ 4008*c3963bc0SZev Weiss if (src <= data->temp_fixed_num) { 4009*c3963bc0SZev Weiss data->have_temp |= BIT(src - 1); 4010*c3963bc0SZev Weiss data->have_temp_fixed |= BIT(src - 1); 4011*c3963bc0SZev Weiss data->reg_temp[0][src - 1] = reg_temp[i]; 4012*c3963bc0SZev Weiss data->reg_temp[1][src - 1] = reg_temp_over[i]; 4013*c3963bc0SZev Weiss data->reg_temp[2][src - 1] = reg_temp_hyst[i]; 4014*c3963bc0SZev Weiss if (reg_temp_crit_h && reg_temp_crit_h[i]) 4015*c3963bc0SZev Weiss data->reg_temp[3][src - 1] = reg_temp_crit_h[i]; 4016*c3963bc0SZev Weiss else if (reg_temp_crit[src - 1]) 4017*c3963bc0SZev Weiss data->reg_temp[3][src - 1] 4018*c3963bc0SZev Weiss = reg_temp_crit[src - 1]; 4019*c3963bc0SZev Weiss if (reg_temp_crit_l && reg_temp_crit_l[i]) 4020*c3963bc0SZev Weiss data->reg_temp[4][src - 1] = reg_temp_crit_l[i]; 4021*c3963bc0SZev Weiss data->reg_temp_config[src - 1] = reg_temp_config[i]; 4022*c3963bc0SZev Weiss data->temp_src[src - 1] = src; 4023*c3963bc0SZev Weiss continue; 4024*c3963bc0SZev Weiss } 4025*c3963bc0SZev Weiss 4026*c3963bc0SZev Weiss if (s >= NUM_TEMP) 4027*c3963bc0SZev Weiss continue; 4028*c3963bc0SZev Weiss 4029*c3963bc0SZev Weiss /* Use dynamic index for other sources */ 4030*c3963bc0SZev Weiss data->have_temp |= BIT(s); 4031*c3963bc0SZev Weiss data->reg_temp[0][s] = reg_temp[i]; 4032*c3963bc0SZev Weiss data->reg_temp[1][s] = reg_temp_over[i]; 4033*c3963bc0SZev Weiss data->reg_temp[2][s] = reg_temp_hyst[i]; 4034*c3963bc0SZev Weiss data->reg_temp_config[s] = reg_temp_config[i]; 4035*c3963bc0SZev Weiss if (reg_temp_crit_h && reg_temp_crit_h[i]) 4036*c3963bc0SZev Weiss data->reg_temp[3][s] = reg_temp_crit_h[i]; 4037*c3963bc0SZev Weiss else if (reg_temp_crit[src - 1]) 4038*c3963bc0SZev Weiss data->reg_temp[3][s] = reg_temp_crit[src - 1]; 4039*c3963bc0SZev Weiss if (reg_temp_crit_l && reg_temp_crit_l[i]) 4040*c3963bc0SZev Weiss data->reg_temp[4][s] = reg_temp_crit_l[i]; 4041*c3963bc0SZev Weiss 4042*c3963bc0SZev Weiss data->temp_src[s] = src; 4043*c3963bc0SZev Weiss s++; 4044*c3963bc0SZev Weiss } 4045*c3963bc0SZev Weiss 4046*c3963bc0SZev Weiss /* 4047*c3963bc0SZev Weiss * Repeat with temperatures used for fan control. 4048*c3963bc0SZev Weiss * This set of registers does not support limits. 4049*c3963bc0SZev Weiss */ 4050*c3963bc0SZev Weiss for (i = 0; i < num_reg_temp_mon; i++) { 4051*c3963bc0SZev Weiss if (reg_temp_mon[i] == 0) 4052*c3963bc0SZev Weiss continue; 4053*c3963bc0SZev Weiss 4054*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TEMP_SEL[i], &src); 4055*c3963bc0SZev Weiss if (err) 4056*c3963bc0SZev Weiss return err; 4057*c3963bc0SZev Weiss src &= 0x1f; 4058*c3963bc0SZev Weiss if (!src) 4059*c3963bc0SZev Weiss continue; 4060*c3963bc0SZev Weiss 4061*c3963bc0SZev Weiss if (!(data->temp_mask & BIT(src))) { 4062*c3963bc0SZev Weiss dev_info(dev, 4063*c3963bc0SZev Weiss "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", 4064*c3963bc0SZev Weiss src, i, data->REG_TEMP_SEL[i], 4065*c3963bc0SZev Weiss reg_temp_mon[i]); 4066*c3963bc0SZev Weiss continue; 4067*c3963bc0SZev Weiss } 4068*c3963bc0SZev Weiss 4069*c3963bc0SZev Weiss /* 4070*c3963bc0SZev Weiss * For virtual temperature sources, the 'virtual' temperature 4071*c3963bc0SZev Weiss * for each fan reflects a different temperature, and there 4072*c3963bc0SZev Weiss * are no duplicates. 4073*c3963bc0SZev Weiss */ 4074*c3963bc0SZev Weiss if (!(data->virt_temp_mask & BIT(src))) { 4075*c3963bc0SZev Weiss if (mask & BIT(src)) 4076*c3963bc0SZev Weiss continue; 4077*c3963bc0SZev Weiss mask |= BIT(src); 4078*c3963bc0SZev Weiss } 4079*c3963bc0SZev Weiss 4080*c3963bc0SZev Weiss /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ 4081*c3963bc0SZev Weiss if (src <= data->temp_fixed_num) { 4082*c3963bc0SZev Weiss if (data->have_temp & BIT(src - 1)) 4083*c3963bc0SZev Weiss continue; 4084*c3963bc0SZev Weiss data->have_temp |= BIT(src - 1); 4085*c3963bc0SZev Weiss data->have_temp_fixed |= BIT(src - 1); 4086*c3963bc0SZev Weiss data->reg_temp[0][src - 1] = reg_temp_mon[i]; 4087*c3963bc0SZev Weiss data->temp_src[src - 1] = src; 4088*c3963bc0SZev Weiss continue; 4089*c3963bc0SZev Weiss } 4090*c3963bc0SZev Weiss 4091*c3963bc0SZev Weiss if (s >= NUM_TEMP) 4092*c3963bc0SZev Weiss continue; 4093*c3963bc0SZev Weiss 4094*c3963bc0SZev Weiss /* Use dynamic index for other sources */ 4095*c3963bc0SZev Weiss data->have_temp |= BIT(s); 4096*c3963bc0SZev Weiss data->reg_temp[0][s] = reg_temp_mon[i]; 4097*c3963bc0SZev Weiss data->temp_src[s] = src; 4098*c3963bc0SZev Weiss s++; 4099*c3963bc0SZev Weiss } 4100*c3963bc0SZev Weiss 4101*c3963bc0SZev Weiss #ifdef USE_ALTERNATE 4102*c3963bc0SZev Weiss /* 4103*c3963bc0SZev Weiss * Go through the list of alternate temp registers and enable 4104*c3963bc0SZev Weiss * if possible. 4105*c3963bc0SZev Weiss * The temperature is already monitored if the respective bit in <mask> 4106*c3963bc0SZev Weiss * is set. 4107*c3963bc0SZev Weiss */ 4108*c3963bc0SZev Weiss for (i = 0; i < 31; i++) { 4109*c3963bc0SZev Weiss if (!(data->temp_mask & BIT(i + 1))) 4110*c3963bc0SZev Weiss continue; 4111*c3963bc0SZev Weiss if (!reg_temp_alternate[i]) 4112*c3963bc0SZev Weiss continue; 4113*c3963bc0SZev Weiss if (mask & BIT(i + 1)) 4114*c3963bc0SZev Weiss continue; 4115*c3963bc0SZev Weiss if (i < data->temp_fixed_num) { 4116*c3963bc0SZev Weiss if (data->have_temp & BIT(i)) 4117*c3963bc0SZev Weiss continue; 4118*c3963bc0SZev Weiss data->have_temp |= BIT(i); 4119*c3963bc0SZev Weiss data->have_temp_fixed |= BIT(i); 4120*c3963bc0SZev Weiss data->reg_temp[0][i] = reg_temp_alternate[i]; 4121*c3963bc0SZev Weiss if (i < num_reg_temp) { 4122*c3963bc0SZev Weiss data->reg_temp[1][i] = reg_temp_over[i]; 4123*c3963bc0SZev Weiss data->reg_temp[2][i] = reg_temp_hyst[i]; 4124*c3963bc0SZev Weiss } 4125*c3963bc0SZev Weiss data->temp_src[i] = i + 1; 4126*c3963bc0SZev Weiss continue; 4127*c3963bc0SZev Weiss } 4128*c3963bc0SZev Weiss 4129*c3963bc0SZev Weiss if (s >= NUM_TEMP) /* Abort if no more space */ 4130*c3963bc0SZev Weiss break; 4131*c3963bc0SZev Weiss 4132*c3963bc0SZev Weiss data->have_temp |= BIT(s); 4133*c3963bc0SZev Weiss data->reg_temp[0][s] = reg_temp_alternate[i]; 4134*c3963bc0SZev Weiss data->temp_src[s] = i + 1; 4135*c3963bc0SZev Weiss s++; 4136*c3963bc0SZev Weiss } 4137*c3963bc0SZev Weiss #endif /* USE_ALTERNATE */ 4138*c3963bc0SZev Weiss 4139*c3963bc0SZev Weiss /* Check which TSIx_TEMP registers are active */ 4140*c3963bc0SZev Weiss for (i = 0; i < num_reg_tsi_temp; i++) { 4141*c3963bc0SZev Weiss u16 tmp; 4142*c3963bc0SZev Weiss 4143*c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_TSI_TEMP[i], &tmp); 4144*c3963bc0SZev Weiss if (err) 4145*c3963bc0SZev Weiss return err; 4146*c3963bc0SZev Weiss if (tmp) 4147*c3963bc0SZev Weiss data->have_tsi_temp |= BIT(i); 4148*c3963bc0SZev Weiss } 4149*c3963bc0SZev Weiss 4150*c3963bc0SZev Weiss /* Initialize the chip */ 4151*c3963bc0SZev Weiss err = nct6775_init_device(data); 4152*c3963bc0SZev Weiss if (err) 4153*c3963bc0SZev Weiss return err; 4154*c3963bc0SZev Weiss 4155*c3963bc0SZev Weiss if (data->driver_init) { 4156*c3963bc0SZev Weiss err = data->driver_init(data); 4157*c3963bc0SZev Weiss if (err) 4158*c3963bc0SZev Weiss return err; 4159*c3963bc0SZev Weiss } 4160*c3963bc0SZev Weiss 4161*c3963bc0SZev Weiss /* Read fan clock dividers immediately */ 4162*c3963bc0SZev Weiss err = nct6775_init_fan_common(dev, data); 4163*c3963bc0SZev Weiss if (err) 4164*c3963bc0SZev Weiss return err; 4165*c3963bc0SZev Weiss 4166*c3963bc0SZev Weiss /* Register sysfs hooks */ 4167*c3963bc0SZev Weiss err = nct6775_add_template_attr_group(dev, data, &nct6775_pwm_template_group, 4168*c3963bc0SZev Weiss data->pwm_num); 4169*c3963bc0SZev Weiss if (err) 4170*c3963bc0SZev Weiss return err; 4171*c3963bc0SZev Weiss 4172*c3963bc0SZev Weiss err = nct6775_add_template_attr_group(dev, data, &nct6775_in_template_group, 4173*c3963bc0SZev Weiss fls(data->have_in)); 4174*c3963bc0SZev Weiss if (err) 4175*c3963bc0SZev Weiss return err; 4176*c3963bc0SZev Weiss 4177*c3963bc0SZev Weiss err = nct6775_add_template_attr_group(dev, data, &nct6775_fan_template_group, 4178*c3963bc0SZev Weiss fls(data->has_fan)); 4179*c3963bc0SZev Weiss if (err) 4180*c3963bc0SZev Weiss return err; 4181*c3963bc0SZev Weiss 4182*c3963bc0SZev Weiss err = nct6775_add_template_attr_group(dev, data, &nct6775_temp_template_group, 4183*c3963bc0SZev Weiss fls(data->have_temp)); 4184*c3963bc0SZev Weiss if (err) 4185*c3963bc0SZev Weiss return err; 4186*c3963bc0SZev Weiss 4187*c3963bc0SZev Weiss if (data->have_tsi_temp) { 4188*c3963bc0SZev Weiss tsi_temp_tg.templates = nct6775_tsi_temp_template; 4189*c3963bc0SZev Weiss tsi_temp_tg.is_visible = nct6775_tsi_temp_is_visible; 4190*c3963bc0SZev Weiss tsi_temp_tg.base = fls(data->have_temp) + 1; 4191*c3963bc0SZev Weiss err = nct6775_add_template_attr_group(dev, data, &tsi_temp_tg, 4192*c3963bc0SZev Weiss fls(data->have_tsi_temp)); 4193*c3963bc0SZev Weiss if (err) 4194*c3963bc0SZev Weiss return err; 4195*c3963bc0SZev Weiss } 4196*c3963bc0SZev Weiss 4197*c3963bc0SZev Weiss hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name, 4198*c3963bc0SZev Weiss data, data->groups); 4199*c3963bc0SZev Weiss return PTR_ERR_OR_ZERO(hwmon_dev); 4200*c3963bc0SZev Weiss } 4201*c3963bc0SZev Weiss EXPORT_SYMBOL_GPL(nct6775_probe); 4202*c3963bc0SZev Weiss 4203*c3963bc0SZev Weiss MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); 4204*c3963bc0SZev Weiss MODULE_DESCRIPTION("Core driver for NCT6775F and compatible chips"); 4205*c3963bc0SZev Weiss MODULE_LICENSE("GPL"); 4206