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