1792d376bSWei Song /* 2792d376bSWei Song * w83795.c - Linux kernel driver for hardware monitoring 3792d376bSWei Song * Copyright (C) 2008 Nuvoton Technology Corp. 4792d376bSWei Song * Wei Song 57c81c60fSJean Delvare * Copyright (C) 2010 Jean Delvare <jdelvare@suse.de> 6792d376bSWei Song * 7792d376bSWei Song * This program is free software; you can redistribute it and/or modify 8792d376bSWei Song * it under the terms of the GNU General Public License as published by 9792d376bSWei Song * the Free Software Foundation - version 2. 10792d376bSWei Song * 11792d376bSWei Song * This program is distributed in the hope that it will be useful, 12792d376bSWei Song * but WITHOUT ANY WARRANTY; without even the implied warranty of 13792d376bSWei Song * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14792d376bSWei Song * GNU General Public License for more details. 15792d376bSWei Song * 16792d376bSWei Song * You should have received a copy of the GNU General Public License 17792d376bSWei Song * along with this program; if not, write to the Free Software 18792d376bSWei Song * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19792d376bSWei Song * 02110-1301 USA. 20792d376bSWei Song * 21792d376bSWei Song * Supports following chips: 22792d376bSWei Song * 23792d376bSWei Song * Chip #vin #fanin #pwm #temp #dts wchipid vendid i2c ISA 24792d376bSWei Song * w83795g 21 14 8 6 8 0x79 0x5ca3 yes no 25792d376bSWei Song * w83795adg 18 14 2 6 8 0x79 0x5ca3 yes no 26792d376bSWei Song */ 27792d376bSWei Song 28792d376bSWei Song #include <linux/kernel.h> 29792d376bSWei Song #include <linux/module.h> 30792d376bSWei Song #include <linux/init.h> 31792d376bSWei Song #include <linux/slab.h> 32792d376bSWei Song #include <linux/i2c.h> 33792d376bSWei Song #include <linux/hwmon.h> 34792d376bSWei Song #include <linux/hwmon-sysfs.h> 35792d376bSWei Song #include <linux/err.h> 36792d376bSWei Song #include <linux/mutex.h> 37dcd8f392SJean Delvare #include <linux/jiffies.h> 38cdb1dc3fSBartosz Golaszewski #include <linux/util_macros.h> 39792d376bSWei Song 40792d376bSWei Song /* Addresses to scan */ 4186ef4d2fSJean Delvare static const unsigned short normal_i2c[] = { 4286ef4d2fSJean Delvare 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END 4386ef4d2fSJean Delvare }; 44792d376bSWei Song 45792d376bSWei Song 4690ab5ee9SRusty Russell static bool reset; 47792d376bSWei Song module_param(reset, bool, 0); 48792d376bSWei Song MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); 49792d376bSWei Song 50792d376bSWei Song 51792d376bSWei Song #define W83795_REG_BANKSEL 0x00 52792d376bSWei Song #define W83795_REG_VENDORID 0xfd 53792d376bSWei Song #define W83795_REG_CHIPID 0xfe 54792d376bSWei Song #define W83795_REG_DEVICEID 0xfb 552be381deSJean Delvare #define W83795_REG_DEVICEID_A 0xff 56792d376bSWei Song 57792d376bSWei Song #define W83795_REG_I2C_ADDR 0xfc 58792d376bSWei Song #define W83795_REG_CONFIG 0x01 59792d376bSWei Song #define W83795_REG_CONFIG_CONFIG48 0x04 6080646b95SJean Delvare #define W83795_REG_CONFIG_START 0x01 61792d376bSWei Song 62792d376bSWei Song /* Multi-Function Pin Ctrl Registers */ 63792d376bSWei Song #define W83795_REG_VOLT_CTRL1 0x02 64792d376bSWei Song #define W83795_REG_VOLT_CTRL2 0x03 65792d376bSWei Song #define W83795_REG_TEMP_CTRL1 0x04 66792d376bSWei Song #define W83795_REG_TEMP_CTRL2 0x05 67792d376bSWei Song #define W83795_REG_FANIN_CTRL1 0x06 68792d376bSWei Song #define W83795_REG_FANIN_CTRL2 0x07 69792d376bSWei Song #define W83795_REG_VMIGB_CTRL 0x08 70792d376bSWei Song 71792d376bSWei Song #define TEMP_READ 0 72792d376bSWei Song #define TEMP_CRIT 1 73792d376bSWei Song #define TEMP_CRIT_HYST 2 74792d376bSWei Song #define TEMP_WARN 3 75792d376bSWei Song #define TEMP_WARN_HYST 4 76c10b3ee8SGuenter Roeck /* 77c10b3ee8SGuenter Roeck * only crit and crit_hyst affect real-time alarm status 78c10b3ee8SGuenter Roeck * current crit crit_hyst warn warn_hyst 79c10b3ee8SGuenter Roeck */ 8086ef4d2fSJean Delvare static const u16 W83795_REG_TEMP[][5] = { 81792d376bSWei Song {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ 82792d376bSWei Song {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ 83792d376bSWei Song {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ 84792d376bSWei Song {0x24, 0xa2, 0xa3, 0xa4, 0xa5}, /* TD4/TR4 */ 85792d376bSWei Song {0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, /* TR5 */ 86792d376bSWei Song {0x20, 0xaa, 0xab, 0xac, 0xad}, /* TR6 */ 87792d376bSWei Song }; 88792d376bSWei Song 89792d376bSWei Song #define IN_READ 0 90792d376bSWei Song #define IN_MAX 1 91792d376bSWei Song #define IN_LOW 2 92792d376bSWei Song static const u16 W83795_REG_IN[][3] = { 93792d376bSWei Song /* Current, HL, LL */ 94792d376bSWei Song {0x10, 0x70, 0x71}, /* VSEN1 */ 95792d376bSWei Song {0x11, 0x72, 0x73}, /* VSEN2 */ 96792d376bSWei Song {0x12, 0x74, 0x75}, /* VSEN3 */ 97792d376bSWei Song {0x13, 0x76, 0x77}, /* VSEN4 */ 98792d376bSWei Song {0x14, 0x78, 0x79}, /* VSEN5 */ 99792d376bSWei Song {0x15, 0x7a, 0x7b}, /* VSEN6 */ 100792d376bSWei Song {0x16, 0x7c, 0x7d}, /* VSEN7 */ 101792d376bSWei Song {0x17, 0x7e, 0x7f}, /* VSEN8 */ 102792d376bSWei Song {0x18, 0x80, 0x81}, /* VSEN9 */ 103792d376bSWei Song {0x19, 0x82, 0x83}, /* VSEN10 */ 104792d376bSWei Song {0x1A, 0x84, 0x85}, /* VSEN11 */ 105792d376bSWei Song {0x1B, 0x86, 0x87}, /* VTT */ 106792d376bSWei Song {0x1C, 0x88, 0x89}, /* 3VDD */ 107792d376bSWei Song {0x1D, 0x8a, 0x8b}, /* 3VSB */ 108792d376bSWei Song {0x1E, 0x8c, 0x8d}, /* VBAT */ 109792d376bSWei Song {0x1F, 0xa6, 0xa7}, /* VSEN12 */ 110792d376bSWei Song {0x20, 0xaa, 0xab}, /* VSEN13 */ 111792d376bSWei Song {0x21, 0x96, 0x97}, /* VSEN14 */ 112792d376bSWei Song {0x22, 0x9a, 0x9b}, /* VSEN15 */ 113792d376bSWei Song {0x23, 0x9e, 0x9f}, /* VSEN16 */ 114792d376bSWei Song {0x24, 0xa2, 0xa3}, /* VSEN17 */ 115792d376bSWei Song }; 116792d376bSWei Song #define W83795_REG_VRLSB 0x3C 117792d376bSWei Song 118792d376bSWei Song static const u8 W83795_REG_IN_HL_LSB[] = { 119792d376bSWei Song 0x8e, /* VSEN1-4 */ 120792d376bSWei Song 0x90, /* VSEN5-8 */ 121792d376bSWei Song 0x92, /* VSEN9-11 */ 122792d376bSWei Song 0x94, /* VTT, 3VDD, 3VSB, 3VBAT */ 123792d376bSWei Song 0xa8, /* VSEN12 */ 124792d376bSWei Song 0xac, /* VSEN13 */ 125792d376bSWei Song 0x98, /* VSEN14 */ 126792d376bSWei Song 0x9c, /* VSEN15 */ 127792d376bSWei Song 0xa0, /* VSEN16 */ 128792d376bSWei Song 0xa4, /* VSEN17 */ 129792d376bSWei Song }; 130792d376bSWei Song 131792d376bSWei Song #define IN_LSB_REG(index, type) \ 132792d376bSWei Song (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ 133792d376bSWei Song : (W83795_REG_IN_HL_LSB[(index)] + 1)) 134792d376bSWei Song 135792d376bSWei Song #define IN_LSB_SHIFT 0 136792d376bSWei Song #define IN_LSB_IDX 1 137792d376bSWei Song static const u8 IN_LSB_SHIFT_IDX[][2] = { 138792d376bSWei Song /* High/Low LSB shift, LSB No. */ 139792d376bSWei Song {0x00, 0x00}, /* VSEN1 */ 140792d376bSWei Song {0x02, 0x00}, /* VSEN2 */ 141792d376bSWei Song {0x04, 0x00}, /* VSEN3 */ 142792d376bSWei Song {0x06, 0x00}, /* VSEN4 */ 143792d376bSWei Song {0x00, 0x01}, /* VSEN5 */ 144792d376bSWei Song {0x02, 0x01}, /* VSEN6 */ 145792d376bSWei Song {0x04, 0x01}, /* VSEN7 */ 146792d376bSWei Song {0x06, 0x01}, /* VSEN8 */ 147792d376bSWei Song {0x00, 0x02}, /* VSEN9 */ 148792d376bSWei Song {0x02, 0x02}, /* VSEN10 */ 149792d376bSWei Song {0x04, 0x02}, /* VSEN11 */ 150792d376bSWei Song {0x00, 0x03}, /* VTT */ 151792d376bSWei Song {0x02, 0x03}, /* 3VDD */ 152792d376bSWei Song {0x04, 0x03}, /* 3VSB */ 153792d376bSWei Song {0x06, 0x03}, /* VBAT */ 154792d376bSWei Song {0x06, 0x04}, /* VSEN12 */ 155792d376bSWei Song {0x06, 0x05}, /* VSEN13 */ 156792d376bSWei Song {0x06, 0x06}, /* VSEN14 */ 157792d376bSWei Song {0x06, 0x07}, /* VSEN15 */ 158792d376bSWei Song {0x06, 0x08}, /* VSEN16 */ 159792d376bSWei Song {0x06, 0x09}, /* VSEN17 */ 160792d376bSWei Song }; 161792d376bSWei Song 162792d376bSWei Song 163792d376bSWei Song #define W83795_REG_FAN(index) (0x2E + (index)) 164792d376bSWei Song #define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) 165792d376bSWei Song #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) 166792d376bSWei Song #define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ 1677eb8d508SJean Delvare (((index) & 1) ? 4 : 0) 168792d376bSWei Song 169792d376bSWei Song #define W83795_REG_VID_CTRL 0x6A 170792d376bSWei Song 171cf6b9ea6SJean Delvare #define W83795_REG_ALARM_CTRL 0x40 172cf6b9ea6SJean Delvare #define ALARM_CTRL_RTSACS (1 << 7) 173792d376bSWei Song #define W83795_REG_ALARM(index) (0x41 + (index)) 174792d376bSWei Song #define W83795_REG_CLR_CHASSIS 0x4D 175cf6b9ea6SJean Delvare #define W83795_REG_BEEP(index) (0x50 + (index)) 176792d376bSWei Song 17752d159eeSJean Delvare #define W83795_REG_OVT_CFG 0x58 17852d159eeSJean Delvare #define OVT_CFG_SEL (1 << 7) 17952d159eeSJean Delvare 180792d376bSWei Song 181792d376bSWei Song #define W83795_REG_FCMS1 0x201 182792d376bSWei Song #define W83795_REG_FCMS2 0x208 183792d376bSWei Song #define W83795_REG_TFMR(index) (0x202 + (index)) 184792d376bSWei Song #define W83795_REG_FOMC 0x20F 185792d376bSWei Song 186792d376bSWei Song #define W83795_REG_TSS(index) (0x209 + (index)) 187792d376bSWei Song 188edff2f8dSJean Delvare #define TSS_MAP_RESERVED 0xff 189edff2f8dSJean Delvare static const u8 tss_map[4][6] = { 190edff2f8dSJean Delvare { 0, 1, 2, 3, 4, 5}, 191edff2f8dSJean Delvare { 6, 7, 8, 9, 0, 1}, 192edff2f8dSJean Delvare {10, 11, 12, 13, 2, 3}, 193edff2f8dSJean Delvare { 4, 5, 4, 5, TSS_MAP_RESERVED, TSS_MAP_RESERVED}, 194edff2f8dSJean Delvare }; 195edff2f8dSJean Delvare 196792d376bSWei Song #define PWM_OUTPUT 0 197fd7f82b8SJean Delvare #define PWM_FREQ 1 198fd7f82b8SJean Delvare #define PWM_START 2 199fd7f82b8SJean Delvare #define PWM_NONSTOP 3 200fd7f82b8SJean Delvare #define PWM_STOP_TIME 4 201fd7f82b8SJean Delvare #define W83795_REG_PWM(index, nr) (0x210 + (nr) * 8 + (index)) 202792d376bSWei Song 203792d376bSWei Song #define W83795_REG_FTSH(index) (0x240 + (index) * 2) 204792d376bSWei Song #define W83795_REG_FTSL(index) (0x241 + (index) * 2) 205792d376bSWei Song #define W83795_REG_TFTS 0x250 206792d376bSWei Song 207792d376bSWei Song #define TEMP_PWM_TTTI 0 208792d376bSWei Song #define TEMP_PWM_CTFS 1 209792d376bSWei Song #define TEMP_PWM_HCT 2 210792d376bSWei Song #define TEMP_PWM_HOT 3 211792d376bSWei Song #define W83795_REG_TTTI(index) (0x260 + (index)) 212792d376bSWei Song #define W83795_REG_CTFS(index) (0x268 + (index)) 213792d376bSWei Song #define W83795_REG_HT(index) (0x270 + (index)) 214792d376bSWei Song 215792d376bSWei Song #define SF4_TEMP 0 216792d376bSWei Song #define SF4_PWM 1 217792d376bSWei Song #define W83795_REG_SF4_TEMP(temp_num, index) \ 218792d376bSWei Song (0x280 + 0x10 * (temp_num) + (index)) 219792d376bSWei Song #define W83795_REG_SF4_PWM(temp_num, index) \ 220792d376bSWei Song (0x288 + 0x10 * (temp_num) + (index)) 221792d376bSWei Song 222792d376bSWei Song #define W83795_REG_DTSC 0x301 223792d376bSWei Song #define W83795_REG_DTSE 0x302 224792d376bSWei Song #define W83795_REG_DTS(index) (0x26 + (index)) 22554891a3cSJean Delvare #define W83795_REG_PECI_TBASE(index) (0x320 + (index)) 226792d376bSWei Song 227792d376bSWei Song #define DTS_CRIT 0 228792d376bSWei Song #define DTS_CRIT_HYST 1 229792d376bSWei Song #define DTS_WARN 2 230792d376bSWei Song #define DTS_WARN_HYST 3 231792d376bSWei Song #define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 232792d376bSWei Song 233792d376bSWei Song #define SETUP_PWM_DEFAULT 0 234792d376bSWei Song #define SETUP_PWM_UPTIME 1 235792d376bSWei Song #define SETUP_PWM_DOWNTIME 2 236792d376bSWei Song #define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 237792d376bSWei Song 238792d376bSWei Song static inline u16 in_from_reg(u8 index, u16 val) 239792d376bSWei Song { 24049c7347aSJean Delvare /* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */ 24149c7347aSJean Delvare if (index >= 12 && index <= 14) 242792d376bSWei Song return val * 6; 243792d376bSWei Song else 244792d376bSWei Song return val * 2; 245792d376bSWei Song } 246792d376bSWei Song 247792d376bSWei Song static inline u16 in_to_reg(u8 index, u16 val) 248792d376bSWei Song { 24949c7347aSJean Delvare if (index >= 12 && index <= 14) 250792d376bSWei Song return val / 6; 251792d376bSWei Song else 252792d376bSWei Song return val / 2; 253792d376bSWei Song } 254792d376bSWei Song 255792d376bSWei Song static inline unsigned long fan_from_reg(u16 val) 256792d376bSWei Song { 2576c82b2f3SJean Delvare if ((val == 0xfff) || (val == 0)) 258792d376bSWei Song return 0; 259792d376bSWei Song return 1350000UL / val; 260792d376bSWei Song } 261792d376bSWei Song 262792d376bSWei Song static inline u16 fan_to_reg(long rpm) 263792d376bSWei Song { 264792d376bSWei Song if (rpm <= 0) 265792d376bSWei Song return 0x0fff; 2662a844c14SGuenter Roeck return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 267792d376bSWei Song } 268792d376bSWei Song 269792d376bSWei Song static inline unsigned long time_from_reg(u8 reg) 270792d376bSWei Song { 271792d376bSWei Song return reg * 100; 272792d376bSWei Song } 273792d376bSWei Song 274792d376bSWei Song static inline u8 time_to_reg(unsigned long val) 275792d376bSWei Song { 2762a844c14SGuenter Roeck return clamp_val((val + 50) / 100, 0, 0xff); 277792d376bSWei Song } 278792d376bSWei Song 279792d376bSWei Song static inline long temp_from_reg(s8 reg) 280792d376bSWei Song { 281792d376bSWei Song return reg * 1000; 282792d376bSWei Song } 283792d376bSWei Song 284792d376bSWei Song static inline s8 temp_to_reg(long val, s8 min, s8 max) 285792d376bSWei Song { 2862a844c14SGuenter Roeck return clamp_val(val / 1000, min, max); 287792d376bSWei Song } 288792d376bSWei Song 28901879a85SJean Delvare static const u16 pwm_freq_cksel0[16] = { 29001879a85SJean Delvare 1024, 512, 341, 256, 205, 171, 146, 128, 29101879a85SJean Delvare 85, 64, 32, 16, 8, 4, 2, 1 29201879a85SJean Delvare }; 29301879a85SJean Delvare 29401879a85SJean Delvare static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) 29501879a85SJean Delvare { 29601879a85SJean Delvare unsigned long base_clock; 29701879a85SJean Delvare 29801879a85SJean Delvare if (reg & 0x80) { 29901879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 30001879a85SJean Delvare return base_clock / ((reg & 0x7f) + 1); 30101879a85SJean Delvare } else 30201879a85SJean Delvare return pwm_freq_cksel0[reg & 0x0f]; 30301879a85SJean Delvare } 30401879a85SJean Delvare 30501879a85SJean Delvare static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) 30601879a85SJean Delvare { 30701879a85SJean Delvare unsigned long base_clock; 30801879a85SJean Delvare u8 reg0, reg1; 30901879a85SJean Delvare unsigned long best0, best1; 31001879a85SJean Delvare 31101879a85SJean Delvare /* Best fit for cksel = 0 */ 312cdb1dc3fSBartosz Golaszewski reg0 = find_closest_descending(val, pwm_freq_cksel0, 313cdb1dc3fSBartosz Golaszewski ARRAY_SIZE(pwm_freq_cksel0)); 31401879a85SJean Delvare if (val < 375) /* cksel = 1 can't beat this */ 31501879a85SJean Delvare return reg0; 31601879a85SJean Delvare best0 = pwm_freq_cksel0[reg0]; 31701879a85SJean Delvare 31801879a85SJean Delvare /* Best fit for cksel = 1 */ 31901879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 3202a844c14SGuenter Roeck reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); 32101879a85SJean Delvare best1 = base_clock / reg1; 32201879a85SJean Delvare reg1 = 0x80 | (reg1 - 1); 32301879a85SJean Delvare 32401879a85SJean Delvare /* Choose the closest one */ 32501879a85SJean Delvare if (abs(val - best0) > abs(val - best1)) 32601879a85SJean Delvare return reg1; 32701879a85SJean Delvare else 32801879a85SJean Delvare return reg0; 32901879a85SJean Delvare } 330792d376bSWei Song 331792d376bSWei Song enum chip_types {w83795g, w83795adg}; 332792d376bSWei Song 333792d376bSWei Song struct w83795_data { 334792d376bSWei Song struct device *hwmon_dev; 335792d376bSWei Song struct mutex update_lock; 336792d376bSWei Song unsigned long last_updated; /* In jiffies */ 337792d376bSWei Song enum chip_types chip_type; 338792d376bSWei Song 339792d376bSWei Song u8 bank; 340792d376bSWei Song 341792d376bSWei Song u32 has_in; /* Enable monitor VIN or not */ 3420e256018SJean Delvare u8 has_dyn_in; /* Only in2-0 can have this */ 343792d376bSWei Song u16 in[21][3]; /* Register value, read/high/low */ 344792d376bSWei Song u8 in_lsb[10][3]; /* LSB Register value, high/low */ 345792d376bSWei Song u8 has_gain; /* has gain: in17-20 * 8 */ 346792d376bSWei Song 347792d376bSWei Song u16 has_fan; /* Enable fan14-1 or not */ 348792d376bSWei Song u16 fan[14]; /* Register value combine */ 349792d376bSWei Song u16 fan_min[14]; /* Register value combine */ 350792d376bSWei Song 351792d376bSWei Song u8 has_temp; /* Enable monitor temp6-1 or not */ 352dd127f5cSJean Delvare s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 353792d376bSWei Song u8 temp_read_vrlsb[6]; 35439deb699SJean Delvare u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */ 355792d376bSWei Song u8 temp_src[3]; /* Register value */ 356792d376bSWei Song 357c10b3ee8SGuenter Roeck u8 enable_dts; /* 358c10b3ee8SGuenter Roeck * Enable PECI and SB-TSI, 359792d376bSWei Song * bit 0: =1 enable, =0 disable, 360c10b3ee8SGuenter Roeck * bit 1: =1 AMD SB-TSI, =0 Intel PECI 361c10b3ee8SGuenter Roeck */ 362792d376bSWei Song u8 has_dts; /* Enable monitor DTS temp */ 363dd127f5cSJean Delvare s8 dts[8]; /* Register value */ 364792d376bSWei Song u8 dts_read_vrlsb[8]; /* Register value */ 365dd127f5cSJean Delvare s8 dts_ext[4]; /* Register value */ 366792d376bSWei Song 367c10b3ee8SGuenter Roeck u8 has_pwm; /* 368c10b3ee8SGuenter Roeck * 795g supports 8 pwm, 795adg only supports 2, 369792d376bSWei Song * no config register, only affected by chip 370c10b3ee8SGuenter Roeck * type 371c10b3ee8SGuenter Roeck */ 372c10b3ee8SGuenter Roeck u8 pwm[8][5]; /* 373c10b3ee8SGuenter Roeck * Register value, output, freq, start, 374c10b3ee8SGuenter Roeck * non stop, stop time 375c10b3ee8SGuenter Roeck */ 37601879a85SJean Delvare u16 clkin; /* CLKIN frequency in kHz */ 377792d376bSWei Song u8 pwm_fcms[2]; /* Register value */ 378792d376bSWei Song u8 pwm_tfmr[6]; /* Register value */ 379792d376bSWei Song u8 pwm_fomc; /* Register value */ 380792d376bSWei Song 381c10b3ee8SGuenter Roeck u16 target_speed[8]; /* 382c10b3ee8SGuenter Roeck * Register value, target speed for speed 383c10b3ee8SGuenter Roeck * cruise 384c10b3ee8SGuenter Roeck */ 385792d376bSWei Song u8 tol_speed; /* tolerance of target speed */ 386792d376bSWei Song u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 387792d376bSWei Song u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 388792d376bSWei Song 389792d376bSWei Song u8 setup_pwm[3]; /* Register value */ 390792d376bSWei Song 391792d376bSWei Song u8 alarms[6]; /* Register value */ 39252d159eeSJean Delvare u8 enable_beep; 393792d376bSWei Song u8 beeps[6]; /* Register value */ 394792d376bSWei Song 395792d376bSWei Song char valid; 3962ae61de9SJean Delvare char valid_limits; 3971bb3450cSJean Delvare char valid_pwm_config; 398792d376bSWei Song }; 399792d376bSWei Song 400792d376bSWei Song /* 401792d376bSWei Song * Hardware access 402b2469f42SJean Delvare * We assume that nobdody can change the bank outside the driver. 403792d376bSWei Song */ 404792d376bSWei Song 405b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 406b2469f42SJean Delvare static int w83795_set_bank(struct i2c_client *client, u8 bank) 407792d376bSWei Song { 408792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 409b2469f42SJean Delvare int err; 410792d376bSWei Song 411b2469f42SJean Delvare /* If the same bank is already set, nothing to do */ 412b2469f42SJean Delvare if ((data->bank & 0x07) == bank) 413b2469f42SJean Delvare return 0; 414b2469f42SJean Delvare 415b2469f42SJean Delvare /* Change to new bank, preserve all other bits */ 416b2469f42SJean Delvare bank |= data->bank & ~0x07; 417b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 418b2469f42SJean Delvare if (err < 0) { 419792d376bSWei Song dev_err(&client->dev, 420b2469f42SJean Delvare "Failed to set bank to %d, err %d\n", 421b2469f42SJean Delvare (int)bank, err); 422b2469f42SJean Delvare return err; 423792d376bSWei Song } 424b2469f42SJean Delvare data->bank = bank; 425b2469f42SJean Delvare 426b2469f42SJean Delvare return 0; 427792d376bSWei Song } 428b2469f42SJean Delvare 429b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 430b2469f42SJean Delvare static u8 w83795_read(struct i2c_client *client, u16 reg) 431b2469f42SJean Delvare { 432b2469f42SJean Delvare int err; 433b2469f42SJean Delvare 434b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 435b2469f42SJean Delvare if (err < 0) 436b2469f42SJean Delvare return 0x00; /* Arbitrary */ 437b2469f42SJean Delvare 438b2469f42SJean Delvare err = i2c_smbus_read_byte_data(client, reg & 0xff); 439b2469f42SJean Delvare if (err < 0) { 440b2469f42SJean Delvare dev_err(&client->dev, 441b2469f42SJean Delvare "Failed to read from register 0x%03x, err %d\n", 442b2469f42SJean Delvare (int)reg, err); 443b2469f42SJean Delvare return 0x00; /* Arbitrary */ 444b2469f42SJean Delvare } 445b2469f42SJean Delvare return err; 446792d376bSWei Song } 447792d376bSWei Song 448792d376bSWei Song /* Must be called with data->update_lock held, except during initialization */ 449792d376bSWei Song static int w83795_write(struct i2c_client *client, u16 reg, u8 value) 450792d376bSWei Song { 451b2469f42SJean Delvare int err; 452792d376bSWei Song 453b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 454b2469f42SJean Delvare if (err < 0) 455b2469f42SJean Delvare return err; 456b2469f42SJean Delvare 457b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 458b2469f42SJean Delvare if (err < 0) 459792d376bSWei Song dev_err(&client->dev, 460b2469f42SJean Delvare "Failed to write to register 0x%03x, err %d\n", 461b2469f42SJean Delvare (int)reg, err); 462b2469f42SJean Delvare return err; 463792d376bSWei Song } 464792d376bSWei Song 4650d7237bfSJean Delvare static void w83795_update_limits(struct i2c_client *client) 4660d7237bfSJean Delvare { 4670d7237bfSJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 4680d7237bfSJean Delvare int i, limit; 469014bcd28SJean Delvare u8 lsb; 4700d7237bfSJean Delvare 4710d7237bfSJean Delvare /* Read the voltage limits */ 4720d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->in); i++) { 4730d7237bfSJean Delvare if (!(data->has_in & (1 << i))) 4740d7237bfSJean Delvare continue; 4750d7237bfSJean Delvare data->in[i][IN_MAX] = 4760d7237bfSJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 4770d7237bfSJean Delvare data->in[i][IN_LOW] = 4780d7237bfSJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 4790d7237bfSJean Delvare } 4800d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { 4810d7237bfSJean Delvare if ((i == 2 && data->chip_type == w83795adg) || 4820d7237bfSJean Delvare (i >= 4 && !(data->has_in & (1 << (i + 11))))) 4830d7237bfSJean Delvare continue; 4840d7237bfSJean Delvare data->in_lsb[i][IN_MAX] = 4850d7237bfSJean Delvare w83795_read(client, IN_LSB_REG(i, IN_MAX)); 4860d7237bfSJean Delvare data->in_lsb[i][IN_LOW] = 4870d7237bfSJean Delvare w83795_read(client, IN_LSB_REG(i, IN_LOW)); 4880d7237bfSJean Delvare } 4890d7237bfSJean Delvare 4900d7237bfSJean Delvare /* Read the fan limits */ 491014bcd28SJean Delvare lsb = 0; /* Silent false gcc warning */ 4920d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 493c10b3ee8SGuenter Roeck /* 494c10b3ee8SGuenter Roeck * Each register contains LSB for 2 fans, but we want to 495c10b3ee8SGuenter Roeck * read it only once to save time 496c10b3ee8SGuenter Roeck */ 4970d7237bfSJean Delvare if ((i & 1) == 0 && (data->has_fan & (3 << i))) 4980d7237bfSJean Delvare lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); 4990d7237bfSJean Delvare 5000d7237bfSJean Delvare if (!(data->has_fan & (1 << i))) 5010d7237bfSJean Delvare continue; 5020d7237bfSJean Delvare data->fan_min[i] = 5030d7237bfSJean Delvare w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 5040d7237bfSJean Delvare data->fan_min[i] |= 5050d7237bfSJean Delvare (lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; 5060d7237bfSJean Delvare } 5070d7237bfSJean Delvare 5080d7237bfSJean Delvare /* Read the temperature limits */ 5090d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 5100d7237bfSJean Delvare if (!(data->has_temp & (1 << i))) 5110d7237bfSJean Delvare continue; 5120d7237bfSJean Delvare for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++) 5130d7237bfSJean Delvare data->temp[i][limit] = 5140d7237bfSJean Delvare w83795_read(client, W83795_REG_TEMP[i][limit]); 5150d7237bfSJean Delvare } 5160d7237bfSJean Delvare 5170d7237bfSJean Delvare /* Read the DTS limits */ 518eb02755aSJean Delvare if (data->enable_dts) { 5190d7237bfSJean Delvare for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++) 5200d7237bfSJean Delvare data->dts_ext[limit] = 5210d7237bfSJean Delvare w83795_read(client, W83795_REG_DTS_EXT(limit)); 5220d7237bfSJean Delvare } 5230d7237bfSJean Delvare 5240d7237bfSJean Delvare /* Read beep settings */ 52552d159eeSJean Delvare if (data->enable_beep) { 5260d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->beeps); i++) 52752d159eeSJean Delvare data->beeps[i] = 52852d159eeSJean Delvare w83795_read(client, W83795_REG_BEEP(i)); 52952d159eeSJean Delvare } 5302ae61de9SJean Delvare 5312ae61de9SJean Delvare data->valid_limits = 1; 5320d7237bfSJean Delvare } 5330d7237bfSJean Delvare 5341bb3450cSJean Delvare static struct w83795_data *w83795_update_pwm_config(struct device *dev) 5350d7237bfSJean Delvare { 5361bb3450cSJean Delvare struct i2c_client *client = to_i2c_client(dev); 5370d7237bfSJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 5380d7237bfSJean Delvare int i, tmp; 5390d7237bfSJean Delvare 5401bb3450cSJean Delvare mutex_lock(&data->update_lock); 5411bb3450cSJean Delvare 5421bb3450cSJean Delvare if (data->valid_pwm_config) 5431bb3450cSJean Delvare goto END; 5441bb3450cSJean Delvare 5450d7237bfSJean Delvare /* Read temperature source selection */ 5460d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp_src); i++) 5470d7237bfSJean Delvare data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 5480d7237bfSJean Delvare 5490d7237bfSJean Delvare /* Read automatic fan speed control settings */ 5500d7237bfSJean Delvare data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 5510d7237bfSJean Delvare data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 5520d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) 5530d7237bfSJean Delvare data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 5540d7237bfSJean Delvare data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 5550d7237bfSJean Delvare for (i = 0; i < data->has_pwm; i++) { 5560d7237bfSJean Delvare for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) 5570d7237bfSJean Delvare data->pwm[i][tmp] = 5580d7237bfSJean Delvare w83795_read(client, W83795_REG_PWM(i, tmp)); 5590d7237bfSJean Delvare } 5600d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) { 5610d7237bfSJean Delvare data->target_speed[i] = 5620d7237bfSJean Delvare w83795_read(client, W83795_REG_FTSH(i)) << 4; 5630d7237bfSJean Delvare data->target_speed[i] |= 5640d7237bfSJean Delvare w83795_read(client, W83795_REG_FTSL(i)) >> 4; 5650d7237bfSJean Delvare } 5660d7237bfSJean Delvare data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 5670d7237bfSJean Delvare 5680d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { 5690d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_TTTI] = 5700d7237bfSJean Delvare w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 5710d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_CTFS] = 5720d7237bfSJean Delvare w83795_read(client, W83795_REG_CTFS(i)); 5730d7237bfSJean Delvare tmp = w83795_read(client, W83795_REG_HT(i)); 574eb02755aSJean Delvare data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4; 5750d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 5760d7237bfSJean Delvare } 5770d7237bfSJean Delvare 5780d7237bfSJean Delvare /* Read SmartFanIV trip points */ 5790d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { 5800d7237bfSJean Delvare for (tmp = 0; tmp < 7; tmp++) { 5810d7237bfSJean Delvare data->sf4_reg[i][SF4_TEMP][tmp] = 5820d7237bfSJean Delvare w83795_read(client, 5830d7237bfSJean Delvare W83795_REG_SF4_TEMP(i, tmp)); 5840d7237bfSJean Delvare data->sf4_reg[i][SF4_PWM][tmp] = 5850d7237bfSJean Delvare w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 5860d7237bfSJean Delvare } 5870d7237bfSJean Delvare } 5880d7237bfSJean Delvare 5890d7237bfSJean Delvare /* Read setup PWM */ 5900d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++) 5910d7237bfSJean Delvare data->setup_pwm[i] = 5920d7237bfSJean Delvare w83795_read(client, W83795_REG_SETUP_PWM(i)); 5931bb3450cSJean Delvare 5941bb3450cSJean Delvare data->valid_pwm_config = 1; 5951bb3450cSJean Delvare 5961bb3450cSJean Delvare END: 5971bb3450cSJean Delvare mutex_unlock(&data->update_lock); 5981bb3450cSJean Delvare return data; 5990d7237bfSJean Delvare } 6000d7237bfSJean Delvare 601792d376bSWei Song static struct w83795_data *w83795_update_device(struct device *dev) 602792d376bSWei Song { 603792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 604792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 605792d376bSWei Song u16 tmp; 606cf6b9ea6SJean Delvare u8 intrusion; 607792d376bSWei Song int i; 608792d376bSWei Song 609792d376bSWei Song mutex_lock(&data->update_lock); 610792d376bSWei Song 6112ae61de9SJean Delvare if (!data->valid_limits) 6122ae61de9SJean Delvare w83795_update_limits(client); 6132ae61de9SJean Delvare 614792d376bSWei Song if (!(time_after(jiffies, data->last_updated + HZ * 2) 615792d376bSWei Song || !data->valid)) 616792d376bSWei Song goto END; 617792d376bSWei Song 618792d376bSWei Song /* Update the voltages value */ 619792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 620792d376bSWei Song if (!(data->has_in & (1 << i))) 621792d376bSWei Song continue; 622792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 623a654b9d4SJean Delvare tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; 624792d376bSWei Song data->in[i][IN_READ] = tmp; 625792d376bSWei Song } 626792d376bSWei Song 6270e256018SJean Delvare /* in0-2 can have dynamic limits (W83795G only) */ 6280e256018SJean Delvare if (data->has_dyn_in) { 6290e256018SJean Delvare u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); 6300e256018SJean Delvare u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); 6310e256018SJean Delvare 6320e256018SJean Delvare for (i = 0; i < 3; i++) { 6330e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 6340e256018SJean Delvare continue; 6350e256018SJean Delvare data->in[i][IN_MAX] = 6360e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 6370e256018SJean Delvare data->in[i][IN_LOW] = 6380e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 6390e256018SJean Delvare data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; 6400e256018SJean Delvare data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; 6410e256018SJean Delvare } 6420e256018SJean Delvare } 6430e256018SJean Delvare 644792d376bSWei Song /* Update fan */ 645792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 646792d376bSWei Song if (!(data->has_fan & (1 << i))) 647792d376bSWei Song continue; 648792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 649eb02755aSJean Delvare data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; 650792d376bSWei Song } 651792d376bSWei Song 652792d376bSWei Song /* Update temperature */ 653792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 654792d376bSWei Song data->temp[i][TEMP_READ] = 655792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 656792d376bSWei Song data->temp_read_vrlsb[i] = 657792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 658792d376bSWei Song } 659792d376bSWei Song 660792d376bSWei Song /* Update dts temperature */ 661eb02755aSJean Delvare if (data->enable_dts) { 662792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 663792d376bSWei Song if (!(data->has_dts & (1 << i))) 664792d376bSWei Song continue; 665792d376bSWei Song data->dts[i] = 666792d376bSWei Song w83795_read(client, W83795_REG_DTS(i)); 667792d376bSWei Song data->dts_read_vrlsb[i] = 668792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 669792d376bSWei Song } 670792d376bSWei Song } 671792d376bSWei Song 672792d376bSWei Song /* Update pwm output */ 673792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 674792d376bSWei Song data->pwm[i][PWM_OUTPUT] = 675792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 676792d376bSWei Song } 677792d376bSWei Song 678c10b3ee8SGuenter Roeck /* 679c10b3ee8SGuenter Roeck * Update intrusion and alarms 680cf6b9ea6SJean Delvare * It is important to read intrusion first, because reading from 681c10b3ee8SGuenter Roeck * register SMI STS6 clears the interrupt status temporarily. 682c10b3ee8SGuenter Roeck */ 683cf6b9ea6SJean Delvare tmp = w83795_read(client, W83795_REG_ALARM_CTRL); 684cf6b9ea6SJean Delvare /* Switch to interrupt status for intrusion if needed */ 685cf6b9ea6SJean Delvare if (tmp & ALARM_CTRL_RTSACS) 686cf6b9ea6SJean Delvare w83795_write(client, W83795_REG_ALARM_CTRL, 687cf6b9ea6SJean Delvare tmp & ~ALARM_CTRL_RTSACS); 688cf6b9ea6SJean Delvare intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6); 689cf6b9ea6SJean Delvare /* Switch to real-time alarms */ 690cf6b9ea6SJean Delvare w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS); 691cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->alarms); i++) 692792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 693cf6b9ea6SJean Delvare data->alarms[5] |= intrusion; 694cf6b9ea6SJean Delvare /* Restore original configuration if needed */ 695cf6b9ea6SJean Delvare if (!(tmp & ALARM_CTRL_RTSACS)) 696cf6b9ea6SJean Delvare w83795_write(client, W83795_REG_ALARM_CTRL, 697cf6b9ea6SJean Delvare tmp & ~ALARM_CTRL_RTSACS); 698792d376bSWei Song 699792d376bSWei Song data->last_updated = jiffies; 700792d376bSWei Song data->valid = 1; 701792d376bSWei Song 702792d376bSWei Song END: 703792d376bSWei Song mutex_unlock(&data->update_lock); 704792d376bSWei Song return data; 705792d376bSWei Song } 706792d376bSWei Song 707792d376bSWei Song /* 708792d376bSWei Song * Sysfs attributes 709792d376bSWei Song */ 710792d376bSWei Song 711792d376bSWei Song #define ALARM_STATUS 0 712792d376bSWei Song #define BEEP_ENABLE 1 713792d376bSWei Song static ssize_t 714792d376bSWei Song show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 715792d376bSWei Song { 716792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 717792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 718792d376bSWei Song to_sensor_dev_attr_2(attr); 719792d376bSWei Song int nr = sensor_attr->nr; 720792d376bSWei Song int index = sensor_attr->index >> 3; 721792d376bSWei Song int bit = sensor_attr->index & 0x07; 722792d376bSWei Song u8 val; 723792d376bSWei Song 724eb02755aSJean Delvare if (nr == ALARM_STATUS) 725eb02755aSJean Delvare val = (data->alarms[index] >> bit) & 1; 726eb02755aSJean Delvare else /* BEEP_ENABLE */ 727eb02755aSJean Delvare val = (data->beeps[index] >> bit) & 1; 728792d376bSWei Song 729792d376bSWei Song return sprintf(buf, "%u\n", val); 730792d376bSWei Song } 731792d376bSWei Song 732792d376bSWei Song static ssize_t 733792d376bSWei Song store_beep(struct device *dev, struct device_attribute *attr, 734792d376bSWei Song const char *buf, size_t count) 735792d376bSWei Song { 736792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 737792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 738792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 739792d376bSWei Song to_sensor_dev_attr_2(attr); 740792d376bSWei Song int index = sensor_attr->index >> 3; 741792d376bSWei Song int shift = sensor_attr->index & 0x07; 742792d376bSWei Song u8 beep_bit = 1 << shift; 743792d376bSWei Song unsigned long val; 744792d376bSWei Song 745179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 746792d376bSWei Song return -EINVAL; 747792d376bSWei Song if (val != 0 && val != 1) 748792d376bSWei Song return -EINVAL; 749792d376bSWei Song 750792d376bSWei Song mutex_lock(&data->update_lock); 751792d376bSWei Song data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 752792d376bSWei Song data->beeps[index] &= ~beep_bit; 753792d376bSWei Song data->beeps[index] |= val << shift; 754792d376bSWei Song w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 755792d376bSWei Song mutex_unlock(&data->update_lock); 756792d376bSWei Song 757792d376bSWei Song return count; 758792d376bSWei Song } 759792d376bSWei Song 76024377101SJean Delvare /* Write 0 to clear chassis alarm */ 761792d376bSWei Song static ssize_t 762792d376bSWei Song store_chassis_clear(struct device *dev, 763792d376bSWei Song struct device_attribute *attr, const char *buf, 764792d376bSWei Song size_t count) 765792d376bSWei Song { 766792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 767792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 76824377101SJean Delvare unsigned long val; 76924377101SJean Delvare 770179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0 || val != 0) 77124377101SJean Delvare return -EINVAL; 772792d376bSWei Song 773792d376bSWei Song mutex_lock(&data->update_lock); 774792d376bSWei Song val = w83795_read(client, W83795_REG_CLR_CHASSIS); 775792d376bSWei Song val |= 0x80; 776792d376bSWei Song w83795_write(client, W83795_REG_CLR_CHASSIS, val); 777793c51d5SJean Delvare 778793c51d5SJean Delvare /* Clear status and force cache refresh */ 779793c51d5SJean Delvare w83795_read(client, W83795_REG_ALARM(5)); 780793c51d5SJean Delvare data->valid = 0; 781792d376bSWei Song mutex_unlock(&data->update_lock); 782792d376bSWei Song return count; 783792d376bSWei Song } 784792d376bSWei Song 785792d376bSWei Song #define FAN_INPUT 0 786792d376bSWei Song #define FAN_MIN 1 787792d376bSWei Song static ssize_t 788792d376bSWei Song show_fan(struct device *dev, struct device_attribute *attr, char *buf) 789792d376bSWei Song { 790792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 791792d376bSWei Song to_sensor_dev_attr_2(attr); 792792d376bSWei Song int nr = sensor_attr->nr; 793792d376bSWei Song int index = sensor_attr->index; 794792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 795792d376bSWei Song u16 val; 796792d376bSWei Song 797eb02755aSJean Delvare if (nr == FAN_INPUT) 798792d376bSWei Song val = data->fan[index] & 0x0fff; 799792d376bSWei Song else 800792d376bSWei Song val = data->fan_min[index] & 0x0fff; 801792d376bSWei Song 802792d376bSWei Song return sprintf(buf, "%lu\n", fan_from_reg(val)); 803792d376bSWei Song } 804792d376bSWei Song 805792d376bSWei Song static ssize_t 806792d376bSWei Song store_fan_min(struct device *dev, struct device_attribute *attr, 807792d376bSWei Song const char *buf, size_t count) 808792d376bSWei Song { 809792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 810792d376bSWei Song to_sensor_dev_attr_2(attr); 811792d376bSWei Song int index = sensor_attr->index; 812792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 813792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 814792d376bSWei Song unsigned long val; 815792d376bSWei Song 816179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val)) 817792d376bSWei Song return -EINVAL; 818792d376bSWei Song val = fan_to_reg(val); 819792d376bSWei Song 820792d376bSWei Song mutex_lock(&data->update_lock); 821792d376bSWei Song data->fan_min[index] = val; 822792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 823792d376bSWei Song val &= 0x0f; 8247eb8d508SJean Delvare if (index & 1) { 825792d376bSWei Song val <<= 4; 826792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 827792d376bSWei Song & 0x0f; 828792d376bSWei Song } else { 829792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 830792d376bSWei Song & 0xf0; 831792d376bSWei Song } 832792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 833792d376bSWei Song mutex_unlock(&data->update_lock); 834792d376bSWei Song 835792d376bSWei Song return count; 836792d376bSWei Song } 837792d376bSWei Song 838792d376bSWei Song static ssize_t 839792d376bSWei Song show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 840792d376bSWei Song { 8411bb3450cSJean Delvare struct w83795_data *data; 842792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 843792d376bSWei Song to_sensor_dev_attr_2(attr); 844792d376bSWei Song int nr = sensor_attr->nr; 845792d376bSWei Song int index = sensor_attr->index; 84601879a85SJean Delvare unsigned int val; 847792d376bSWei Song 8481bb3450cSJean Delvare data = nr == PWM_OUTPUT ? w83795_update_device(dev) 8491bb3450cSJean Delvare : w83795_update_pwm_config(dev); 8501bb3450cSJean Delvare 851792d376bSWei Song switch (nr) { 852792d376bSWei Song case PWM_STOP_TIME: 853792d376bSWei Song val = time_from_reg(data->pwm[index][nr]); 854792d376bSWei Song break; 85501879a85SJean Delvare case PWM_FREQ: 85601879a85SJean Delvare val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); 857792d376bSWei Song break; 858792d376bSWei Song default: 859792d376bSWei Song val = data->pwm[index][nr]; 860792d376bSWei Song break; 861792d376bSWei Song } 862792d376bSWei Song 863792d376bSWei Song return sprintf(buf, "%u\n", val); 864792d376bSWei Song } 865792d376bSWei Song 866792d376bSWei Song static ssize_t 867792d376bSWei Song store_pwm(struct device *dev, struct device_attribute *attr, 868792d376bSWei Song const char *buf, size_t count) 869792d376bSWei Song { 870792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 871792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 872792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 873792d376bSWei Song to_sensor_dev_attr_2(attr); 874792d376bSWei Song int nr = sensor_attr->nr; 875792d376bSWei Song int index = sensor_attr->index; 876792d376bSWei Song unsigned long val; 877792d376bSWei Song 878179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 879792d376bSWei Song return -EINVAL; 880792d376bSWei Song 881792d376bSWei Song mutex_lock(&data->update_lock); 882792d376bSWei Song switch (nr) { 883792d376bSWei Song case PWM_STOP_TIME: 884792d376bSWei Song val = time_to_reg(val); 885792d376bSWei Song break; 88601879a85SJean Delvare case PWM_FREQ: 88701879a85SJean Delvare val = pwm_freq_to_reg(val, data->clkin); 888792d376bSWei Song break; 889792d376bSWei Song default: 8902a844c14SGuenter Roeck val = clamp_val(val, 0, 0xff); 891792d376bSWei Song break; 892792d376bSWei Song } 893792d376bSWei Song w83795_write(client, W83795_REG_PWM(index, nr), val); 89401879a85SJean Delvare data->pwm[index][nr] = val; 895792d376bSWei Song mutex_unlock(&data->update_lock); 896792d376bSWei Song return count; 897792d376bSWei Song } 898792d376bSWei Song 899792d376bSWei Song static ssize_t 900792d376bSWei Song show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 901792d376bSWei Song { 902792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 903792d376bSWei Song to_sensor_dev_attr_2(attr); 9041bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 905792d376bSWei Song int index = sensor_attr->index; 906792d376bSWei Song u8 tmp; 907792d376bSWei Song 908ae51cd9bSJean Delvare /* Speed cruise mode */ 909ae51cd9bSJean Delvare if (data->pwm_fcms[0] & (1 << index)) { 910792d376bSWei Song tmp = 2; 911792d376bSWei Song goto out; 912792d376bSWei Song } 913ae51cd9bSJean Delvare /* Thermal cruise or SmartFan IV mode */ 914792d376bSWei Song for (tmp = 0; tmp < 6; tmp++) { 915792d376bSWei Song if (data->pwm_tfmr[tmp] & (1 << index)) { 916792d376bSWei Song tmp = 3; 917792d376bSWei Song goto out; 918792d376bSWei Song } 919792d376bSWei Song } 920ae51cd9bSJean Delvare /* Manual mode */ 921792d376bSWei Song tmp = 1; 922792d376bSWei Song 923792d376bSWei Song out: 924792d376bSWei Song return sprintf(buf, "%u\n", tmp); 925792d376bSWei Song } 926792d376bSWei Song 927792d376bSWei Song static ssize_t 928792d376bSWei Song store_pwm_enable(struct device *dev, struct device_attribute *attr, 929792d376bSWei Song const char *buf, size_t count) 930792d376bSWei Song { 931792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 9321bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 933792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 934792d376bSWei Song to_sensor_dev_attr_2(attr); 935792d376bSWei Song int index = sensor_attr->index; 936792d376bSWei Song unsigned long val; 937792d376bSWei Song int i; 938792d376bSWei Song 939179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 940792d376bSWei Song return -EINVAL; 941ae51cd9bSJean Delvare if (val < 1 || val > 2) 942792d376bSWei Song return -EINVAL; 943792d376bSWei Song 94472fea694SJean Delvare #ifndef CONFIG_SENSORS_W83795_FANCTRL 94572fea694SJean Delvare if (val > 1) { 94672fea694SJean Delvare dev_warn(dev, "Automatic fan speed control support disabled\n"); 94772fea694SJean Delvare dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n"); 94872fea694SJean Delvare return -EOPNOTSUPP; 94972fea694SJean Delvare } 95072fea694SJean Delvare #endif 95172fea694SJean Delvare 952792d376bSWei Song mutex_lock(&data->update_lock); 953792d376bSWei Song switch (val) { 954792d376bSWei Song case 1: 955ae51cd9bSJean Delvare /* Clear speed cruise mode bits */ 956792d376bSWei Song data->pwm_fcms[0] &= ~(1 << index); 957792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 958ae51cd9bSJean Delvare /* Clear thermal cruise mode bits */ 959792d376bSWei Song for (i = 0; i < 6; i++) { 960792d376bSWei Song data->pwm_tfmr[i] &= ~(1 << index); 961792d376bSWei Song w83795_write(client, W83795_REG_TFMR(i), 962792d376bSWei Song data->pwm_tfmr[i]); 963792d376bSWei Song } 964792d376bSWei Song break; 965792d376bSWei Song case 2: 966792d376bSWei Song data->pwm_fcms[0] |= (1 << index); 967792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 968792d376bSWei Song break; 969792d376bSWei Song } 970792d376bSWei Song mutex_unlock(&data->update_lock); 971792d376bSWei Song return count; 972792d376bSWei Song } 973792d376bSWei Song 974792d376bSWei Song static ssize_t 975d5ab845aSJean Delvare show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) 976d5ab845aSJean Delvare { 977d5ab845aSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 978d5ab845aSJean Delvare int index = to_sensor_dev_attr_2(attr)->index; 979d5ab845aSJean Delvare unsigned int mode; 980d5ab845aSJean Delvare 981d5ab845aSJean Delvare if (data->pwm_fomc & (1 << index)) 982d5ab845aSJean Delvare mode = 0; /* DC */ 983d5ab845aSJean Delvare else 984d5ab845aSJean Delvare mode = 1; /* PWM */ 985d5ab845aSJean Delvare 986d5ab845aSJean Delvare return sprintf(buf, "%u\n", mode); 987d5ab845aSJean Delvare } 988d5ab845aSJean Delvare 989edff2f8dSJean Delvare /* 990edff2f8dSJean Delvare * Check whether a given temperature source can ever be useful. 991edff2f8dSJean Delvare * Returns the number of selectable temperature channels which are 992edff2f8dSJean Delvare * enabled. 993edff2f8dSJean Delvare */ 994edff2f8dSJean Delvare static int w83795_tss_useful(const struct w83795_data *data, int tsrc) 995edff2f8dSJean Delvare { 996edff2f8dSJean Delvare int useful = 0, i; 997edff2f8dSJean Delvare 998edff2f8dSJean Delvare for (i = 0; i < 4; i++) { 999edff2f8dSJean Delvare if (tss_map[i][tsrc] == TSS_MAP_RESERVED) 1000edff2f8dSJean Delvare continue; 1001edff2f8dSJean Delvare if (tss_map[i][tsrc] < 6) /* Analog */ 1002edff2f8dSJean Delvare useful += (data->has_temp >> tss_map[i][tsrc]) & 1; 1003edff2f8dSJean Delvare else /* Digital */ 1004edff2f8dSJean Delvare useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1; 1005edff2f8dSJean Delvare } 1006edff2f8dSJean Delvare 1007edff2f8dSJean Delvare return useful; 1008edff2f8dSJean Delvare } 1009edff2f8dSJean Delvare 1010d5ab845aSJean Delvare static ssize_t 1011792d376bSWei Song show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 1012792d376bSWei Song { 1013792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1014792d376bSWei Song to_sensor_dev_attr_2(attr); 10151bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1016792d376bSWei Song int index = sensor_attr->index; 10172a2d27daSJean Delvare u8 tmp = data->temp_src[index / 2]; 1018792d376bSWei Song 10197eb8d508SJean Delvare if (index & 1) 10202a2d27daSJean Delvare tmp >>= 4; /* Pick high nibble */ 1021792d376bSWei Song else 10222a2d27daSJean Delvare tmp &= 0x0f; /* Pick low nibble */ 1023792d376bSWei Song 10242a2d27daSJean Delvare /* Look-up the actual temperature channel number */ 10252a2d27daSJean Delvare if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED) 10262a2d27daSJean Delvare return -EINVAL; /* Shouldn't happen */ 10272a2d27daSJean Delvare 10282a2d27daSJean Delvare return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1); 1029792d376bSWei Song } 1030792d376bSWei Song 1031792d376bSWei Song static ssize_t 1032792d376bSWei Song store_temp_src(struct device *dev, struct device_attribute *attr, 1033792d376bSWei Song const char *buf, size_t count) 1034792d376bSWei Song { 1035792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 10361bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1037792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1038792d376bSWei Song to_sensor_dev_attr_2(attr); 1039792d376bSWei Song int index = sensor_attr->index; 10402a2d27daSJean Delvare int tmp; 10412a2d27daSJean Delvare unsigned long channel; 1042792d376bSWei Song u8 val = index / 2; 1043792d376bSWei Song 1044179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &channel) < 0 || 10452a2d27daSJean Delvare channel < 1 || channel > 14) 1046792d376bSWei Song return -EINVAL; 10472a2d27daSJean Delvare 10482a2d27daSJean Delvare /* Check if request can be fulfilled */ 10492a2d27daSJean Delvare for (tmp = 0; tmp < 4; tmp++) { 10502a2d27daSJean Delvare if (tss_map[tmp][index] == channel - 1) 10512a2d27daSJean Delvare break; 10522a2d27daSJean Delvare } 10532a2d27daSJean Delvare if (tmp == 4) /* No match */ 10542a2d27daSJean Delvare return -EINVAL; 1055792d376bSWei Song 1056792d376bSWei Song mutex_lock(&data->update_lock); 10577eb8d508SJean Delvare if (index & 1) { 1058792d376bSWei Song tmp <<= 4; 1059792d376bSWei Song data->temp_src[val] &= 0x0f; 1060792d376bSWei Song } else { 1061792d376bSWei Song data->temp_src[val] &= 0xf0; 1062792d376bSWei Song } 1063792d376bSWei Song data->temp_src[val] |= tmp; 1064792d376bSWei Song w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 1065792d376bSWei Song mutex_unlock(&data->update_lock); 1066792d376bSWei Song 1067792d376bSWei Song return count; 1068792d376bSWei Song } 1069792d376bSWei Song 1070792d376bSWei Song #define TEMP_PWM_ENABLE 0 1071792d376bSWei Song #define TEMP_PWM_FAN_MAP 1 1072792d376bSWei Song static ssize_t 1073792d376bSWei Song show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 1074792d376bSWei Song char *buf) 1075792d376bSWei Song { 10761bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1077792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1078792d376bSWei Song to_sensor_dev_attr_2(attr); 1079792d376bSWei Song int nr = sensor_attr->nr; 1080792d376bSWei Song int index = sensor_attr->index; 1081792d376bSWei Song u8 tmp = 0xff; 1082792d376bSWei Song 1083792d376bSWei Song switch (nr) { 1084792d376bSWei Song case TEMP_PWM_ENABLE: 1085792d376bSWei Song tmp = (data->pwm_fcms[1] >> index) & 1; 1086792d376bSWei Song if (tmp) 1087792d376bSWei Song tmp = 4; 1088792d376bSWei Song else 1089792d376bSWei Song tmp = 3; 1090792d376bSWei Song break; 1091792d376bSWei Song case TEMP_PWM_FAN_MAP: 1092792d376bSWei Song tmp = data->pwm_tfmr[index]; 1093792d376bSWei Song break; 1094792d376bSWei Song } 1095792d376bSWei Song 1096792d376bSWei Song return sprintf(buf, "%u\n", tmp); 1097792d376bSWei Song } 1098792d376bSWei Song 1099792d376bSWei Song static ssize_t 1100792d376bSWei Song store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 1101792d376bSWei Song const char *buf, size_t count) 1102792d376bSWei Song { 1103792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 11041bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1105792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1106792d376bSWei Song to_sensor_dev_attr_2(attr); 1107792d376bSWei Song int nr = sensor_attr->nr; 1108792d376bSWei Song int index = sensor_attr->index; 1109792d376bSWei Song unsigned long tmp; 1110792d376bSWei Song 1111179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &tmp) < 0) 1112792d376bSWei Song return -EINVAL; 1113792d376bSWei Song 1114792d376bSWei Song switch (nr) { 1115792d376bSWei Song case TEMP_PWM_ENABLE: 1116eb02755aSJean Delvare if (tmp != 3 && tmp != 4) 1117792d376bSWei Song return -EINVAL; 1118792d376bSWei Song tmp -= 3; 1119792d376bSWei Song mutex_lock(&data->update_lock); 1120792d376bSWei Song data->pwm_fcms[1] &= ~(1 << index); 1121792d376bSWei Song data->pwm_fcms[1] |= tmp << index; 1122792d376bSWei Song w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 1123792d376bSWei Song mutex_unlock(&data->update_lock); 1124792d376bSWei Song break; 1125792d376bSWei Song case TEMP_PWM_FAN_MAP: 1126792d376bSWei Song mutex_lock(&data->update_lock); 11272a844c14SGuenter Roeck tmp = clamp_val(tmp, 0, 0xff); 1128792d376bSWei Song w83795_write(client, W83795_REG_TFMR(index), tmp); 1129792d376bSWei Song data->pwm_tfmr[index] = tmp; 1130792d376bSWei Song mutex_unlock(&data->update_lock); 1131792d376bSWei Song break; 1132792d376bSWei Song } 1133792d376bSWei Song return count; 1134792d376bSWei Song } 1135792d376bSWei Song 1136792d376bSWei Song #define FANIN_TARGET 0 1137792d376bSWei Song #define FANIN_TOL 1 1138792d376bSWei Song static ssize_t 1139792d376bSWei Song show_fanin(struct device *dev, struct device_attribute *attr, char *buf) 1140792d376bSWei Song { 11411bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1142792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1143792d376bSWei Song to_sensor_dev_attr_2(attr); 1144792d376bSWei Song int nr = sensor_attr->nr; 1145792d376bSWei Song int index = sensor_attr->index; 1146792d376bSWei Song u16 tmp = 0; 1147792d376bSWei Song 1148792d376bSWei Song switch (nr) { 1149792d376bSWei Song case FANIN_TARGET: 1150792d376bSWei Song tmp = fan_from_reg(data->target_speed[index]); 1151792d376bSWei Song break; 1152792d376bSWei Song case FANIN_TOL: 1153792d376bSWei Song tmp = data->tol_speed; 1154792d376bSWei Song break; 1155792d376bSWei Song } 1156792d376bSWei Song 1157792d376bSWei Song return sprintf(buf, "%u\n", tmp); 1158792d376bSWei Song } 1159792d376bSWei Song 1160792d376bSWei Song static ssize_t 1161792d376bSWei Song store_fanin(struct device *dev, struct device_attribute *attr, 1162792d376bSWei Song const char *buf, size_t count) 1163792d376bSWei Song { 1164792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1165792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1166792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1167792d376bSWei Song to_sensor_dev_attr_2(attr); 1168792d376bSWei Song int nr = sensor_attr->nr; 1169792d376bSWei Song int index = sensor_attr->index; 1170792d376bSWei Song unsigned long val; 1171792d376bSWei Song 1172179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1173792d376bSWei Song return -EINVAL; 1174792d376bSWei Song 1175792d376bSWei Song mutex_lock(&data->update_lock); 1176792d376bSWei Song switch (nr) { 1177792d376bSWei Song case FANIN_TARGET: 11782a844c14SGuenter Roeck val = fan_to_reg(clamp_val(val, 0, 0xfff)); 1179eb02755aSJean Delvare w83795_write(client, W83795_REG_FTSH(index), val >> 4); 1180792d376bSWei Song w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 1181792d376bSWei Song data->target_speed[index] = val; 1182792d376bSWei Song break; 1183792d376bSWei Song case FANIN_TOL: 11842a844c14SGuenter Roeck val = clamp_val(val, 0, 0x3f); 1185792d376bSWei Song w83795_write(client, W83795_REG_TFTS, val); 1186792d376bSWei Song data->tol_speed = val; 1187792d376bSWei Song break; 1188792d376bSWei Song } 1189792d376bSWei Song mutex_unlock(&data->update_lock); 1190792d376bSWei Song 1191792d376bSWei Song return count; 1192792d376bSWei Song } 1193792d376bSWei Song 1194792d376bSWei Song 1195792d376bSWei Song static ssize_t 1196792d376bSWei Song show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1197792d376bSWei Song { 11981bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1199792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1200792d376bSWei Song to_sensor_dev_attr_2(attr); 1201792d376bSWei Song int nr = sensor_attr->nr; 1202792d376bSWei Song int index = sensor_attr->index; 1203792d376bSWei Song long tmp = temp_from_reg(data->pwm_temp[index][nr]); 1204792d376bSWei Song 1205792d376bSWei Song return sprintf(buf, "%ld\n", tmp); 1206792d376bSWei Song } 1207792d376bSWei Song 1208792d376bSWei Song static ssize_t 1209792d376bSWei Song store_temp_pwm(struct device *dev, struct device_attribute *attr, 1210792d376bSWei Song const char *buf, size_t count) 1211792d376bSWei Song { 1212792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1213792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1214792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1215792d376bSWei Song to_sensor_dev_attr_2(attr); 1216792d376bSWei Song int nr = sensor_attr->nr; 1217792d376bSWei Song int index = sensor_attr->index; 1218792d376bSWei Song unsigned long val; 1219792d376bSWei Song u8 tmp; 1220792d376bSWei Song 1221179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1222792d376bSWei Song return -EINVAL; 1223792d376bSWei Song val /= 1000; 1224792d376bSWei Song 1225792d376bSWei Song mutex_lock(&data->update_lock); 1226792d376bSWei Song switch (nr) { 1227792d376bSWei Song case TEMP_PWM_TTTI: 12282a844c14SGuenter Roeck val = clamp_val(val, 0, 0x7f); 1229792d376bSWei Song w83795_write(client, W83795_REG_TTTI(index), val); 1230792d376bSWei Song break; 1231792d376bSWei Song case TEMP_PWM_CTFS: 12322a844c14SGuenter Roeck val = clamp_val(val, 0, 0x7f); 1233792d376bSWei Song w83795_write(client, W83795_REG_CTFS(index), val); 1234792d376bSWei Song break; 1235792d376bSWei Song case TEMP_PWM_HCT: 12362a844c14SGuenter Roeck val = clamp_val(val, 0, 0x0f); 1237792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1238792d376bSWei Song tmp &= 0x0f; 1239792d376bSWei Song tmp |= (val << 4) & 0xf0; 1240792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1241792d376bSWei Song break; 1242792d376bSWei Song case TEMP_PWM_HOT: 12432a844c14SGuenter Roeck val = clamp_val(val, 0, 0x0f); 1244792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1245792d376bSWei Song tmp &= 0xf0; 1246792d376bSWei Song tmp |= val & 0x0f; 1247792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1248792d376bSWei Song break; 1249792d376bSWei Song } 1250792d376bSWei Song data->pwm_temp[index][nr] = val; 1251792d376bSWei Song mutex_unlock(&data->update_lock); 1252792d376bSWei Song 1253792d376bSWei Song return count; 1254792d376bSWei Song } 1255792d376bSWei Song 1256792d376bSWei Song static ssize_t 1257792d376bSWei Song show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1258792d376bSWei Song { 12591bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1260792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1261792d376bSWei Song to_sensor_dev_attr_2(attr); 1262792d376bSWei Song int nr = sensor_attr->nr; 1263792d376bSWei Song int index = sensor_attr->index; 1264792d376bSWei Song 1265792d376bSWei Song return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 1266792d376bSWei Song } 1267792d376bSWei Song 1268792d376bSWei Song static ssize_t 1269792d376bSWei Song store_sf4_pwm(struct device *dev, struct device_attribute *attr, 1270792d376bSWei Song const char *buf, size_t count) 1271792d376bSWei Song { 1272792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1273792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1274792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1275792d376bSWei Song to_sensor_dev_attr_2(attr); 1276792d376bSWei Song int nr = sensor_attr->nr; 1277792d376bSWei Song int index = sensor_attr->index; 1278792d376bSWei Song unsigned long val; 1279792d376bSWei Song 1280179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1281792d376bSWei Song return -EINVAL; 1282792d376bSWei Song 1283792d376bSWei Song mutex_lock(&data->update_lock); 1284792d376bSWei Song w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 1285792d376bSWei Song data->sf4_reg[index][SF4_PWM][nr] = val; 1286792d376bSWei Song mutex_unlock(&data->update_lock); 1287792d376bSWei Song 1288792d376bSWei Song return count; 1289792d376bSWei Song } 1290792d376bSWei Song 1291792d376bSWei Song static ssize_t 1292792d376bSWei Song show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 1293792d376bSWei Song { 12941bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1295792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1296792d376bSWei Song to_sensor_dev_attr_2(attr); 1297792d376bSWei Song int nr = sensor_attr->nr; 1298792d376bSWei Song int index = sensor_attr->index; 1299792d376bSWei Song 1300792d376bSWei Song return sprintf(buf, "%u\n", 1301792d376bSWei Song (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 1302792d376bSWei Song } 1303792d376bSWei Song 1304792d376bSWei Song static ssize_t 1305792d376bSWei Song store_sf4_temp(struct device *dev, struct device_attribute *attr, 1306792d376bSWei Song const char *buf, size_t count) 1307792d376bSWei Song { 1308792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1309792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1310792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1311792d376bSWei Song to_sensor_dev_attr_2(attr); 1312792d376bSWei Song int nr = sensor_attr->nr; 1313792d376bSWei Song int index = sensor_attr->index; 1314792d376bSWei Song unsigned long val; 1315792d376bSWei Song 1316179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1317792d376bSWei Song return -EINVAL; 1318792d376bSWei Song val /= 1000; 1319792d376bSWei Song 1320792d376bSWei Song mutex_lock(&data->update_lock); 1321792d376bSWei Song w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 1322792d376bSWei Song data->sf4_reg[index][SF4_TEMP][nr] = val; 1323792d376bSWei Song mutex_unlock(&data->update_lock); 1324792d376bSWei Song 1325792d376bSWei Song return count; 1326792d376bSWei Song } 1327792d376bSWei Song 1328792d376bSWei Song 1329792d376bSWei Song static ssize_t 1330792d376bSWei Song show_temp(struct device *dev, struct device_attribute *attr, char *buf) 1331792d376bSWei Song { 1332792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1333792d376bSWei Song to_sensor_dev_attr_2(attr); 1334792d376bSWei Song int nr = sensor_attr->nr; 1335792d376bSWei Song int index = sensor_attr->index; 1336792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1337dd127f5cSJean Delvare long temp = temp_from_reg(data->temp[index][nr]); 1338792d376bSWei Song 1339eb02755aSJean Delvare if (nr == TEMP_READ) 1340a654b9d4SJean Delvare temp += (data->temp_read_vrlsb[index] >> 6) * 250; 1341792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1342792d376bSWei Song } 1343792d376bSWei Song 1344792d376bSWei Song static ssize_t 1345792d376bSWei Song store_temp(struct device *dev, struct device_attribute *attr, 1346792d376bSWei Song const char *buf, size_t count) 1347792d376bSWei Song { 1348792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1349792d376bSWei Song to_sensor_dev_attr_2(attr); 1350792d376bSWei Song int nr = sensor_attr->nr; 1351792d376bSWei Song int index = sensor_attr->index; 1352792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1353792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1354792d376bSWei Song long tmp; 1355792d376bSWei Song 1356179c4fdbSFrans Meulenbroeks if (kstrtol(buf, 10, &tmp) < 0) 1357792d376bSWei Song return -EINVAL; 1358792d376bSWei Song 1359792d376bSWei Song mutex_lock(&data->update_lock); 1360792d376bSWei Song data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 1361792d376bSWei Song w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 1362792d376bSWei Song mutex_unlock(&data->update_lock); 1363792d376bSWei Song return count; 1364792d376bSWei Song } 1365792d376bSWei Song 1366792d376bSWei Song 1367792d376bSWei Song static ssize_t 1368792d376bSWei Song show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) 1369792d376bSWei Song { 137021fc9775SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 137139deb699SJean Delvare int tmp; 1372792d376bSWei Song 1373792d376bSWei Song if (data->enable_dts & 2) 1374792d376bSWei Song tmp = 5; 1375792d376bSWei Song else 1376792d376bSWei Song tmp = 6; 1377792d376bSWei Song 1378792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1379792d376bSWei Song } 1380792d376bSWei Song 1381792d376bSWei Song static ssize_t 1382792d376bSWei Song show_dts(struct device *dev, struct device_attribute *attr, char *buf) 1383792d376bSWei Song { 1384792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1385792d376bSWei Song to_sensor_dev_attr_2(attr); 1386792d376bSWei Song int index = sensor_attr->index; 1387792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1388dd127f5cSJean Delvare long temp = temp_from_reg(data->dts[index]); 1389792d376bSWei Song 1390a654b9d4SJean Delvare temp += (data->dts_read_vrlsb[index] >> 6) * 250; 1391792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1392792d376bSWei Song } 1393792d376bSWei Song 1394792d376bSWei Song static ssize_t 1395792d376bSWei Song show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 1396792d376bSWei Song { 1397792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1398792d376bSWei Song to_sensor_dev_attr_2(attr); 1399792d376bSWei Song int nr = sensor_attr->nr; 140021fc9775SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 1401dd127f5cSJean Delvare long temp = temp_from_reg(data->dts_ext[nr]); 1402792d376bSWei Song 1403792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1404792d376bSWei Song } 1405792d376bSWei Song 1406792d376bSWei Song static ssize_t 1407792d376bSWei Song store_dts_ext(struct device *dev, struct device_attribute *attr, 1408792d376bSWei Song const char *buf, size_t count) 1409792d376bSWei Song { 1410792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1411792d376bSWei Song to_sensor_dev_attr_2(attr); 1412792d376bSWei Song int nr = sensor_attr->nr; 1413792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1414792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1415792d376bSWei Song long tmp; 1416792d376bSWei Song 1417179c4fdbSFrans Meulenbroeks if (kstrtol(buf, 10, &tmp) < 0) 1418792d376bSWei Song return -EINVAL; 1419792d376bSWei Song 1420792d376bSWei Song mutex_lock(&data->update_lock); 1421792d376bSWei Song data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 1422792d376bSWei Song w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 1423792d376bSWei Song mutex_unlock(&data->update_lock); 1424792d376bSWei Song return count; 1425792d376bSWei Song } 1426792d376bSWei Song 1427792d376bSWei Song 1428792d376bSWei Song static ssize_t 1429792d376bSWei Song show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 1430792d376bSWei Song { 143121fc9775SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 1432792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1433792d376bSWei Song to_sensor_dev_attr_2(attr); 1434792d376bSWei Song int index = sensor_attr->index; 143539deb699SJean Delvare int tmp; 1436792d376bSWei Song 143739deb699SJean Delvare if (data->temp_mode & (1 << index)) 143839deb699SJean Delvare tmp = 3; /* Thermal diode */ 1439792d376bSWei Song else 144039deb699SJean Delvare tmp = 4; /* Thermistor */ 1441792d376bSWei Song 1442792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1443792d376bSWei Song } 1444792d376bSWei Song 144539deb699SJean Delvare /* Only for temp1-4 (temp5-6 can only be thermistor) */ 1446792d376bSWei Song static ssize_t 1447792d376bSWei Song store_temp_mode(struct device *dev, struct device_attribute *attr, 1448792d376bSWei Song const char *buf, size_t count) 1449792d376bSWei Song { 1450792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1451792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1452792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1453792d376bSWei Song to_sensor_dev_attr_2(attr); 1454792d376bSWei Song int index = sensor_attr->index; 145539deb699SJean Delvare int reg_shift; 1456792d376bSWei Song unsigned long val; 1457792d376bSWei Song u8 tmp; 1458792d376bSWei Song 1459179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1460792d376bSWei Song return -EINVAL; 1461792d376bSWei Song if ((val != 4) && (val != 3)) 1462792d376bSWei Song return -EINVAL; 1463792d376bSWei Song 1464792d376bSWei Song mutex_lock(&data->update_lock); 1465792d376bSWei Song if (val == 3) { 146639deb699SJean Delvare /* Thermal diode */ 146739deb699SJean Delvare val = 0x01; 1468792d376bSWei Song data->temp_mode |= 1 << index; 1469792d376bSWei Song } else if (val == 4) { 147039deb699SJean Delvare /* Thermistor */ 147139deb699SJean Delvare val = 0x03; 147239deb699SJean Delvare data->temp_mode &= ~(1 << index); 1473792d376bSWei Song } 1474792d376bSWei Song 147539deb699SJean Delvare reg_shift = 2 * index; 1476792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 147739deb699SJean Delvare tmp &= ~(0x03 << reg_shift); 147839deb699SJean Delvare tmp |= val << reg_shift; 1479792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 1480792d376bSWei Song 1481792d376bSWei Song mutex_unlock(&data->update_lock); 1482792d376bSWei Song return count; 1483792d376bSWei Song } 1484792d376bSWei Song 1485792d376bSWei Song 1486792d376bSWei Song /* show/store VIN */ 1487792d376bSWei Song static ssize_t 1488792d376bSWei Song show_in(struct device *dev, struct device_attribute *attr, char *buf) 1489792d376bSWei Song { 1490792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1491792d376bSWei Song to_sensor_dev_attr_2(attr); 1492792d376bSWei Song int nr = sensor_attr->nr; 1493792d376bSWei Song int index = sensor_attr->index; 1494792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1495792d376bSWei Song u16 val = data->in[index][nr]; 1496792d376bSWei Song u8 lsb_idx; 1497792d376bSWei Song 1498792d376bSWei Song switch (nr) { 1499792d376bSWei Song case IN_READ: 1500792d376bSWei Song /* calculate this value again by sensors as sensors3.conf */ 1501792d376bSWei Song if ((index >= 17) && 15026f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1503792d376bSWei Song val *= 8; 1504792d376bSWei Song break; 1505792d376bSWei Song case IN_MAX: 1506792d376bSWei Song case IN_LOW: 1507792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1508792d376bSWei Song val <<= 2; 1509792d376bSWei Song val |= (data->in_lsb[lsb_idx][nr] >> 15105d2cd958SJean Delvare IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03; 1511792d376bSWei Song if ((index >= 17) && 15126f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1513792d376bSWei Song val *= 8; 1514792d376bSWei Song break; 1515792d376bSWei Song } 1516792d376bSWei Song val = in_from_reg(index, val); 1517792d376bSWei Song 1518792d376bSWei Song return sprintf(buf, "%d\n", val); 1519792d376bSWei Song } 1520792d376bSWei Song 1521792d376bSWei Song static ssize_t 1522792d376bSWei Song store_in(struct device *dev, struct device_attribute *attr, 1523792d376bSWei Song const char *buf, size_t count) 1524792d376bSWei Song { 1525792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1526792d376bSWei Song to_sensor_dev_attr_2(attr); 1527792d376bSWei Song int nr = sensor_attr->nr; 1528792d376bSWei Song int index = sensor_attr->index; 1529792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1530792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1531792d376bSWei Song unsigned long val; 1532792d376bSWei Song u8 tmp; 1533792d376bSWei Song u8 lsb_idx; 1534792d376bSWei Song 1535179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1536792d376bSWei Song return -EINVAL; 1537792d376bSWei Song val = in_to_reg(index, val); 1538792d376bSWei Song 1539792d376bSWei Song if ((index >= 17) && 15406f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1541792d376bSWei Song val /= 8; 15422a844c14SGuenter Roeck val = clamp_val(val, 0, 0x3FF); 1543792d376bSWei Song mutex_lock(&data->update_lock); 1544792d376bSWei Song 1545792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1546792d376bSWei Song tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 1547792d376bSWei Song tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 1548792d376bSWei Song tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 1549792d376bSWei Song w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 1550792d376bSWei Song data->in_lsb[lsb_idx][nr] = tmp; 1551792d376bSWei Song 1552792d376bSWei Song tmp = (val >> 2) & 0xff; 1553792d376bSWei Song w83795_write(client, W83795_REG_IN[index][nr], tmp); 1554792d376bSWei Song data->in[index][nr] = tmp; 1555792d376bSWei Song 1556792d376bSWei Song mutex_unlock(&data->update_lock); 1557792d376bSWei Song return count; 1558792d376bSWei Song } 1559792d376bSWei Song 1560792d376bSWei Song 156100030af2SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 1562792d376bSWei Song static ssize_t 1563792d376bSWei Song show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 1564792d376bSWei Song { 1565792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1566792d376bSWei Song to_sensor_dev_attr_2(attr); 1567792d376bSWei Song int nr = sensor_attr->nr; 15681bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1569792d376bSWei Song u16 val = data->setup_pwm[nr]; 1570792d376bSWei Song 1571792d376bSWei Song switch (nr) { 1572792d376bSWei Song case SETUP_PWM_UPTIME: 1573792d376bSWei Song case SETUP_PWM_DOWNTIME: 1574792d376bSWei Song val = time_from_reg(val); 1575792d376bSWei Song break; 1576792d376bSWei Song } 1577792d376bSWei Song 1578792d376bSWei Song return sprintf(buf, "%d\n", val); 1579792d376bSWei Song } 1580792d376bSWei Song 1581792d376bSWei Song static ssize_t 1582792d376bSWei Song store_sf_setup(struct device *dev, struct device_attribute *attr, 1583792d376bSWei Song const char *buf, size_t count) 1584792d376bSWei Song { 1585792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1586792d376bSWei Song to_sensor_dev_attr_2(attr); 1587792d376bSWei Song int nr = sensor_attr->nr; 1588792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1589792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1590792d376bSWei Song unsigned long val; 1591792d376bSWei Song 1592179c4fdbSFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 1593792d376bSWei Song return -EINVAL; 1594792d376bSWei Song 1595792d376bSWei Song switch (nr) { 1596792d376bSWei Song case SETUP_PWM_DEFAULT: 15972a844c14SGuenter Roeck val = clamp_val(val, 0, 0xff); 1598792d376bSWei Song break; 1599792d376bSWei Song case SETUP_PWM_UPTIME: 1600792d376bSWei Song case SETUP_PWM_DOWNTIME: 1601792d376bSWei Song val = time_to_reg(val); 1602792d376bSWei Song if (val == 0) 1603792d376bSWei Song return -EINVAL; 1604792d376bSWei Song break; 1605792d376bSWei Song } 1606792d376bSWei Song 1607792d376bSWei Song mutex_lock(&data->update_lock); 1608792d376bSWei Song data->setup_pwm[nr] = val; 1609792d376bSWei Song w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 1610792d376bSWei Song mutex_unlock(&data->update_lock); 1611792d376bSWei Song return count; 1612792d376bSWei Song } 161300030af2SJean Delvare #endif 1614792d376bSWei Song 1615792d376bSWei Song 1616792d376bSWei Song #define NOT_USED -1 1617792d376bSWei Song 1618c10b3ee8SGuenter Roeck /* 1619c10b3ee8SGuenter Roeck * Don't change the attribute order, _max, _min and _beep are accessed by index 1620c10b3ee8SGuenter Roeck * somewhere else in the code 1621c10b3ee8SGuenter Roeck */ 162287df0dadSJean Delvare #define SENSOR_ATTR_IN(index) { \ 1623792d376bSWei Song SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 1624792d376bSWei Song IN_READ, index), \ 1625792d376bSWei Song SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 1626792d376bSWei Song store_in, IN_MAX, index), \ 1627792d376bSWei Song SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 1628792d376bSWei Song store_in, IN_LOW, index), \ 1629792d376bSWei Song SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 1630792d376bSWei Song NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 1631792d376bSWei Song SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 1632792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 163387df0dadSJean Delvare index + ((index > 14) ? 1 : 0)) } 1634792d376bSWei Song 1635c10b3ee8SGuenter Roeck /* 1636c10b3ee8SGuenter Roeck * Don't change the attribute order, _beep is accessed by index 1637c10b3ee8SGuenter Roeck * somewhere else in the code 1638c10b3ee8SGuenter Roeck */ 163987df0dadSJean Delvare #define SENSOR_ATTR_FAN(index) { \ 1640792d376bSWei Song SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 1641792d376bSWei Song NULL, FAN_INPUT, index - 1), \ 1642792d376bSWei Song SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 1643792d376bSWei Song show_fan, store_fan_min, FAN_MIN, index - 1), \ 1644792d376bSWei Song SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 1645792d376bSWei Song NULL, ALARM_STATUS, index + 31), \ 1646792d376bSWei Song SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 164787df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 1648792d376bSWei Song 1649b5f6a90aSJean Delvare #define SENSOR_ATTR_PWM(index) { \ 1650792d376bSWei Song SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 1651792d376bSWei Song store_pwm, PWM_OUTPUT, index - 1), \ 165272fea694SJean Delvare SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 165372fea694SJean Delvare show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 165472fea694SJean Delvare SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO, \ 165572fea694SJean Delvare show_pwm_mode, NULL, NOT_USED, index - 1), \ 165672fea694SJean Delvare SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ 165772fea694SJean Delvare show_pwm, store_pwm, PWM_FREQ, index - 1), \ 1658792d376bSWei Song SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 1659792d376bSWei Song show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 1660792d376bSWei Song SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 1661792d376bSWei Song show_pwm, store_pwm, PWM_START, index - 1), \ 1662792d376bSWei Song SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 1663792d376bSWei Song show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 1664b2cc528eSJean Delvare SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 1665b2cc528eSJean Delvare show_fanin, store_fanin, FANIN_TARGET, index - 1) } 1666792d376bSWei Song 1667c10b3ee8SGuenter Roeck /* 1668c10b3ee8SGuenter Roeck * Don't change the attribute order, _beep is accessed by index 1669c10b3ee8SGuenter Roeck * somewhere else in the code 1670c10b3ee8SGuenter Roeck */ 167187df0dadSJean Delvare #define SENSOR_ATTR_DTS(index) { \ 1672792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 1673792d376bSWei Song show_dts_mode, NULL, NOT_USED, index - 7), \ 1674792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 1675792d376bSWei Song NULL, NOT_USED, index - 7), \ 1676a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ 1677792d376bSWei Song store_dts_ext, DTS_CRIT, NOT_USED), \ 1678a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1679792d376bSWei Song show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 1680a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 1681792d376bSWei Song store_dts_ext, DTS_WARN, NOT_USED), \ 1682a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1683792d376bSWei Song show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 1684792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1685792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 1686792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 168787df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 1688792d376bSWei Song 1689c10b3ee8SGuenter Roeck /* 1690c10b3ee8SGuenter Roeck * Don't change the attribute order, _beep is accessed by index 1691c10b3ee8SGuenter Roeck * somewhere else in the code 1692c10b3ee8SGuenter Roeck */ 169387df0dadSJean Delvare #define SENSOR_ATTR_TEMP(index) { \ 169409aaf681SHuacai Chen SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 5 ? S_IWUSR : 0), \ 1695792d376bSWei Song show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 1696792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 1697792d376bSWei Song NULL, TEMP_READ, index - 1), \ 1698a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ 1699792d376bSWei Song store_temp, TEMP_CRIT, index - 1), \ 1700a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1701792d376bSWei Song show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 1702a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 1703792d376bSWei Song store_temp, TEMP_WARN, index - 1), \ 1704a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1705792d376bSWei Song show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 1706792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1707792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, \ 1708792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1709792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 1710792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 1711792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1712792d376bSWei Song SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 1713792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1714792d376bSWei Song TEMP_PWM_ENABLE, index - 1), \ 1715792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 1716792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1717792d376bSWei Song TEMP_PWM_FAN_MAP, index - 1), \ 1718792d376bSWei Song SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 1719792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 1720a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ 1721792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 1722a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ 1723792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 1724792d376bSWei Song SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 1725792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 1726792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 1727792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 1728792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 1729792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 1730792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 1731792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 1732792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 1733792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 1734792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 1735792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 1736792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 1737792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 1738792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 1739792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 1740792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 1741792d376bSWei Song show_sf4_temp, store_sf4_temp, 0, index - 1), \ 1742792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 1743792d376bSWei Song show_sf4_temp, store_sf4_temp, 1, index - 1), \ 1744792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 1745792d376bSWei Song show_sf4_temp, store_sf4_temp, 2, index - 1), \ 1746792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 1747792d376bSWei Song show_sf4_temp, store_sf4_temp, 3, index - 1), \ 1748792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 1749792d376bSWei Song show_sf4_temp, store_sf4_temp, 4, index - 1), \ 1750792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 1751792d376bSWei Song show_sf4_temp, store_sf4_temp, 5, index - 1), \ 1752792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 175387df0dadSJean Delvare show_sf4_temp, store_sf4_temp, 6, index - 1) } 1754792d376bSWei Song 1755792d376bSWei Song 175687df0dadSJean Delvare static struct sensor_device_attribute_2 w83795_in[][5] = { 1757792d376bSWei Song SENSOR_ATTR_IN(0), 1758792d376bSWei Song SENSOR_ATTR_IN(1), 1759792d376bSWei Song SENSOR_ATTR_IN(2), 1760792d376bSWei Song SENSOR_ATTR_IN(3), 1761792d376bSWei Song SENSOR_ATTR_IN(4), 1762792d376bSWei Song SENSOR_ATTR_IN(5), 1763792d376bSWei Song SENSOR_ATTR_IN(6), 1764792d376bSWei Song SENSOR_ATTR_IN(7), 1765792d376bSWei Song SENSOR_ATTR_IN(8), 1766792d376bSWei Song SENSOR_ATTR_IN(9), 1767792d376bSWei Song SENSOR_ATTR_IN(10), 1768792d376bSWei Song SENSOR_ATTR_IN(11), 1769792d376bSWei Song SENSOR_ATTR_IN(12), 1770792d376bSWei Song SENSOR_ATTR_IN(13), 1771792d376bSWei Song SENSOR_ATTR_IN(14), 1772792d376bSWei Song SENSOR_ATTR_IN(15), 1773792d376bSWei Song SENSOR_ATTR_IN(16), 1774792d376bSWei Song SENSOR_ATTR_IN(17), 1775792d376bSWei Song SENSOR_ATTR_IN(18), 1776792d376bSWei Song SENSOR_ATTR_IN(19), 1777792d376bSWei Song SENSOR_ATTR_IN(20), 1778792d376bSWei Song }; 1779792d376bSWei Song 178086ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_fan[][4] = { 1781792d376bSWei Song SENSOR_ATTR_FAN(1), 1782792d376bSWei Song SENSOR_ATTR_FAN(2), 1783792d376bSWei Song SENSOR_ATTR_FAN(3), 1784792d376bSWei Song SENSOR_ATTR_FAN(4), 1785792d376bSWei Song SENSOR_ATTR_FAN(5), 1786792d376bSWei Song SENSOR_ATTR_FAN(6), 1787792d376bSWei Song SENSOR_ATTR_FAN(7), 1788792d376bSWei Song SENSOR_ATTR_FAN(8), 1789792d376bSWei Song SENSOR_ATTR_FAN(9), 1790792d376bSWei Song SENSOR_ATTR_FAN(10), 1791792d376bSWei Song SENSOR_ATTR_FAN(11), 1792792d376bSWei Song SENSOR_ATTR_FAN(12), 1793792d376bSWei Song SENSOR_ATTR_FAN(13), 1794792d376bSWei Song SENSOR_ATTR_FAN(14), 1795792d376bSWei Song }; 1796792d376bSWei Song 1797edff2f8dSJean Delvare static const struct sensor_device_attribute_2 w83795_temp[][28] = { 1798792d376bSWei Song SENSOR_ATTR_TEMP(1), 1799792d376bSWei Song SENSOR_ATTR_TEMP(2), 1800792d376bSWei Song SENSOR_ATTR_TEMP(3), 1801792d376bSWei Song SENSOR_ATTR_TEMP(4), 1802792d376bSWei Song SENSOR_ATTR_TEMP(5), 1803792d376bSWei Song SENSOR_ATTR_TEMP(6), 1804792d376bSWei Song }; 1805792d376bSWei Song 180686ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_dts[][8] = { 1807792d376bSWei Song SENSOR_ATTR_DTS(7), 1808792d376bSWei Song SENSOR_ATTR_DTS(8), 1809792d376bSWei Song SENSOR_ATTR_DTS(9), 1810792d376bSWei Song SENSOR_ATTR_DTS(10), 1811792d376bSWei Song SENSOR_ATTR_DTS(11), 1812792d376bSWei Song SENSOR_ATTR_DTS(12), 1813792d376bSWei Song SENSOR_ATTR_DTS(13), 1814792d376bSWei Song SENSOR_ATTR_DTS(14), 1815792d376bSWei Song }; 1816792d376bSWei Song 1817d5ab845aSJean Delvare static const struct sensor_device_attribute_2 w83795_pwm[][8] = { 1818b5f6a90aSJean Delvare SENSOR_ATTR_PWM(1), 1819b5f6a90aSJean Delvare SENSOR_ATTR_PWM(2), 1820792d376bSWei Song SENSOR_ATTR_PWM(3), 1821792d376bSWei Song SENSOR_ATTR_PWM(4), 1822792d376bSWei Song SENSOR_ATTR_PWM(5), 1823792d376bSWei Song SENSOR_ATTR_PWM(6), 1824792d376bSWei Song SENSOR_ATTR_PWM(7), 1825792d376bSWei Song SENSOR_ATTR_PWM(8), 1826792d376bSWei Song }; 1827792d376bSWei Song 1828edff2f8dSJean Delvare static const struct sensor_device_attribute_2 w83795_tss[6] = { 1829edff2f8dSJean Delvare SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO, 1830edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 0), 1831edff2f8dSJean Delvare SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO, 1832edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 1), 1833edff2f8dSJean Delvare SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO, 1834edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 2), 1835edff2f8dSJean Delvare SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO, 1836edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 3), 1837edff2f8dSJean Delvare SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO, 1838edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 4), 1839edff2f8dSJean Delvare SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO, 1840edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 5), 1841edff2f8dSJean Delvare }; 1842edff2f8dSJean Delvare 184386ef4d2fSJean Delvare static const struct sensor_device_attribute_2 sda_single_files[] = { 184424377101SJean Delvare SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, 1845792d376bSWei Song store_chassis_clear, ALARM_STATUS, 46), 184600030af2SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 1847792d376bSWei Song SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 1848792d376bSWei Song store_fanin, FANIN_TOL, NOT_USED), 1849792d376bSWei Song SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 1850792d376bSWei Song store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 1851792d376bSWei Song SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 1852792d376bSWei Song store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 1853792d376bSWei Song SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 1854792d376bSWei Song store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 185500030af2SJean Delvare #endif 1856792d376bSWei Song }; 1857792d376bSWei Song 185852d159eeSJean Delvare static const struct sensor_device_attribute_2 sda_beep_files[] = { 185952d159eeSJean Delvare SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep, 186052d159eeSJean Delvare store_beep, BEEP_ENABLE, 46), 186152d159eeSJean Delvare SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, 186252d159eeSJean Delvare store_beep, BEEP_ENABLE, 47), 186352d159eeSJean Delvare }; 186452d159eeSJean Delvare 1865792d376bSWei Song /* 1866792d376bSWei Song * Driver interface 1867792d376bSWei Song */ 1868792d376bSWei Song 1869792d376bSWei Song static void w83795_init_client(struct i2c_client *client) 1870792d376bSWei Song { 187101879a85SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 187201879a85SJean Delvare static const u16 clkin[4] = { /* in kHz */ 187301879a85SJean Delvare 14318, 24000, 33333, 48000 187401879a85SJean Delvare }; 187580646b95SJean Delvare u8 config; 187680646b95SJean Delvare 1877792d376bSWei Song if (reset) 1878792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 0x80); 1879792d376bSWei Song 188080646b95SJean Delvare /* Start monitoring if needed */ 188180646b95SJean Delvare config = w83795_read(client, W83795_REG_CONFIG); 188280646b95SJean Delvare if (!(config & W83795_REG_CONFIG_START)) { 188380646b95SJean Delvare dev_info(&client->dev, "Enabling monitoring operations\n"); 1884792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 188580646b95SJean Delvare config | W83795_REG_CONFIG_START); 188680646b95SJean Delvare } 188701879a85SJean Delvare 188801879a85SJean Delvare data->clkin = clkin[(config >> 3) & 0x3]; 188901879a85SJean Delvare dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); 1890792d376bSWei Song } 1891792d376bSWei Song 18922be381deSJean Delvare static int w83795_get_device_id(struct i2c_client *client) 18932be381deSJean Delvare { 18942be381deSJean Delvare int device_id; 18952be381deSJean Delvare 18962be381deSJean Delvare device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 18972be381deSJean Delvare 1898c10b3ee8SGuenter Roeck /* 1899c10b3ee8SGuenter Roeck * Special case for rev. A chips; can't be checked first because later 1900c10b3ee8SGuenter Roeck * revisions emulate this for compatibility 1901c10b3ee8SGuenter Roeck */ 19022be381deSJean Delvare if (device_id < 0 || (device_id & 0xf0) != 0x50) { 19032be381deSJean Delvare int alt_id; 19042be381deSJean Delvare 19052be381deSJean Delvare alt_id = i2c_smbus_read_byte_data(client, 19062be381deSJean Delvare W83795_REG_DEVICEID_A); 19072be381deSJean Delvare if (alt_id == 0x50) 19082be381deSJean Delvare device_id = alt_id; 19092be381deSJean Delvare } 19102be381deSJean Delvare 19112be381deSJean Delvare return device_id; 19122be381deSJean Delvare } 19132be381deSJean Delvare 1914792d376bSWei Song /* Return 0 if detection is successful, -ENODEV otherwise */ 1915792d376bSWei Song static int w83795_detect(struct i2c_client *client, 1916792d376bSWei Song struct i2c_board_info *info) 1917792d376bSWei Song { 19182be381deSJean Delvare int bank, vendor_id, device_id, expected, i2c_addr, config; 1919792d376bSWei Song struct i2c_adapter *adapter = client->adapter; 1920792d376bSWei Song unsigned short address = client->addr; 1921093d1a47SJean Delvare const char *chip_name; 1922792d376bSWei Song 1923792d376bSWei Song if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1924792d376bSWei Song return -ENODEV; 1925792d376bSWei Song bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 19262be381deSJean Delvare if (bank < 0 || (bank & 0x7c)) { 19272be381deSJean Delvare dev_dbg(&adapter->dev, 19282be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 19292be381deSJean Delvare address, "bank"); 19302be381deSJean Delvare return -ENODEV; 19312be381deSJean Delvare } 1932792d376bSWei Song 1933792d376bSWei Song /* Check Nuvoton vendor ID */ 19342be381deSJean Delvare vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 19352be381deSJean Delvare expected = bank & 0x80 ? 0x5c : 0xa3; 19362be381deSJean Delvare if (vendor_id != expected) { 19372be381deSJean Delvare dev_dbg(&adapter->dev, 19382be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 19392be381deSJean Delvare address, "vendor id"); 19402be381deSJean Delvare return -ENODEV; 19412be381deSJean Delvare } 19422be381deSJean Delvare 19432be381deSJean Delvare /* Check device ID */ 19442be381deSJean Delvare device_id = w83795_get_device_id(client) | 19452be381deSJean Delvare (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 19462be381deSJean Delvare if ((device_id >> 4) != 0x795) { 19472be381deSJean Delvare dev_dbg(&adapter->dev, 19482be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 19492be381deSJean Delvare address, "device id\n"); 1950792d376bSWei Song return -ENODEV; 1951792d376bSWei Song } 1952792d376bSWei Song 1953c10b3ee8SGuenter Roeck /* 1954c10b3ee8SGuenter Roeck * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 1955c10b3ee8SGuenter Roeck * should match 1956c10b3ee8SGuenter Roeck */ 19572be381deSJean Delvare if ((bank & 0x07) == 0) { 19582be381deSJean Delvare i2c_addr = i2c_smbus_read_byte_data(client, 19592be381deSJean Delvare W83795_REG_I2C_ADDR); 19602be381deSJean Delvare if ((i2c_addr & 0x7f) != address) { 19612be381deSJean Delvare dev_dbg(&adapter->dev, 19622be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, " 19632be381deSJean Delvare "check %s\n", address, "i2c addr"); 1964792d376bSWei Song return -ENODEV; 1965792d376bSWei Song } 1966792d376bSWei Song } 1967792d376bSWei Song 1968c10b3ee8SGuenter Roeck /* 1969c10b3ee8SGuenter Roeck * Check 795 chip type: 795G or 795ADG 1970c10b3ee8SGuenter Roeck * Usually we don't write to chips during detection, but here we don't 1971c10b3ee8SGuenter Roeck * quite have the choice; hopefully it's OK, we are about to return 1972c10b3ee8SGuenter Roeck * success anyway 1973c10b3ee8SGuenter Roeck */ 1974093d1a47SJean Delvare if ((bank & 0x07) != 0) 1975093d1a47SJean Delvare i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 1976093d1a47SJean Delvare bank & ~0x07); 19772be381deSJean Delvare config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 19782be381deSJean Delvare if (config & W83795_REG_CONFIG_CONFIG48) 1979093d1a47SJean Delvare chip_name = "w83795adg"; 19802be381deSJean Delvare else 1981093d1a47SJean Delvare chip_name = "w83795g"; 1982792d376bSWei Song 1983093d1a47SJean Delvare strlcpy(info->type, chip_name, I2C_NAME_SIZE); 19842be381deSJean Delvare dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 19852be381deSJean Delvare 'A' + (device_id & 0xf), address); 1986792d376bSWei Song 1987792d376bSWei Song return 0; 1988792d376bSWei Song } 1989792d376bSWei Song 199072fea694SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 199172fea694SJean Delvare #define NUM_PWM_ATTRIBUTES ARRAY_SIZE(w83795_pwm[0]) 199272fea694SJean Delvare #define NUM_TEMP_ATTRIBUTES ARRAY_SIZE(w83795_temp[0]) 199372fea694SJean Delvare #else 199472fea694SJean Delvare #define NUM_PWM_ATTRIBUTES 4 199572fea694SJean Delvare #define NUM_TEMP_ATTRIBUTES 8 199672fea694SJean Delvare #endif 199772fea694SJean Delvare 19986f3dcde9SJean Delvare static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 19996f3dcde9SJean Delvare const struct device_attribute *)) 2000892514a6SJean Delvare { 2001892514a6SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 200287df0dadSJean Delvare int err, i, j; 2003892514a6SJean Delvare 2004892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 200587df0dadSJean Delvare if (!(data->has_in & (1 << i))) 2006892514a6SJean Delvare continue; 200787df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 200852d159eeSJean Delvare if (j == 4 && !data->enable_beep) 200952d159eeSJean Delvare continue; 201087df0dadSJean Delvare err = fn(dev, &w83795_in[i][j].dev_attr); 2011892514a6SJean Delvare if (err) 2012892514a6SJean Delvare return err; 2013892514a6SJean Delvare } 201487df0dadSJean Delvare } 2015892514a6SJean Delvare 2016892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 201787df0dadSJean Delvare if (!(data->has_fan & (1 << i))) 2018892514a6SJean Delvare continue; 201987df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 202052d159eeSJean Delvare if (j == 3 && !data->enable_beep) 202152d159eeSJean Delvare continue; 202287df0dadSJean Delvare err = fn(dev, &w83795_fan[i][j].dev_attr); 2023892514a6SJean Delvare if (err) 2024892514a6SJean Delvare return err; 2025892514a6SJean Delvare } 202687df0dadSJean Delvare } 2027892514a6SJean Delvare 2028edff2f8dSJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) { 2029edff2f8dSJean Delvare j = w83795_tss_useful(data, i); 2030edff2f8dSJean Delvare if (!j) 2031edff2f8dSJean Delvare continue; 2032edff2f8dSJean Delvare err = fn(dev, &w83795_tss[i].dev_attr); 2033edff2f8dSJean Delvare if (err) 2034edff2f8dSJean Delvare return err; 2035edff2f8dSJean Delvare } 2036edff2f8dSJean Delvare 2037892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 20386f3dcde9SJean Delvare err = fn(dev, &sda_single_files[i].dev_attr); 2039892514a6SJean Delvare if (err) 2040892514a6SJean Delvare return err; 2041892514a6SJean Delvare } 2042892514a6SJean Delvare 204352d159eeSJean Delvare if (data->enable_beep) { 204452d159eeSJean Delvare for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) { 204552d159eeSJean Delvare err = fn(dev, &sda_beep_files[i].dev_attr); 204652d159eeSJean Delvare if (err) 204752d159eeSJean Delvare return err; 204852d159eeSJean Delvare } 204952d159eeSJean Delvare } 205052d159eeSJean Delvare 2051b5f6a90aSJean Delvare for (i = 0; i < data->has_pwm; i++) { 205272fea694SJean Delvare for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) { 2053b5f6a90aSJean Delvare err = fn(dev, &w83795_pwm[i][j].dev_attr); 2054892514a6SJean Delvare if (err) 2055892514a6SJean Delvare return err; 2056892514a6SJean Delvare } 2057892514a6SJean Delvare } 2058892514a6SJean Delvare 2059892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 206087df0dadSJean Delvare if (!(data->has_temp & (1 << i))) 2061892514a6SJean Delvare continue; 206272fea694SJean Delvare for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) { 206352d159eeSJean Delvare if (j == 7 && !data->enable_beep) 206452d159eeSJean Delvare continue; 206587df0dadSJean Delvare err = fn(dev, &w83795_temp[i][j].dev_attr); 2066892514a6SJean Delvare if (err) 2067892514a6SJean Delvare return err; 2068892514a6SJean Delvare } 206987df0dadSJean Delvare } 2070892514a6SJean Delvare 2071eb02755aSJean Delvare if (data->enable_dts) { 2072892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 207387df0dadSJean Delvare if (!(data->has_dts & (1 << i))) 2074892514a6SJean Delvare continue; 207587df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 207652d159eeSJean Delvare if (j == 7 && !data->enable_beep) 207752d159eeSJean Delvare continue; 207887df0dadSJean Delvare err = fn(dev, &w83795_dts[i][j].dev_attr); 2079892514a6SJean Delvare if (err) 2080892514a6SJean Delvare return err; 2081892514a6SJean Delvare } 2082892514a6SJean Delvare } 208387df0dadSJean Delvare } 2084892514a6SJean Delvare 2085892514a6SJean Delvare return 0; 2086892514a6SJean Delvare } 2087892514a6SJean Delvare 20886f3dcde9SJean Delvare /* We need a wrapper that fits in w83795_handle_files */ 20896f3dcde9SJean Delvare static int device_remove_file_wrapper(struct device *dev, 20906f3dcde9SJean Delvare const struct device_attribute *attr) 20912fa09878SJean Delvare { 20926f3dcde9SJean Delvare device_remove_file(dev, attr); 20936f3dcde9SJean Delvare return 0; 20942fa09878SJean Delvare } 20952fa09878SJean Delvare 20960e256018SJean Delvare static void w83795_check_dynamic_in_limits(struct i2c_client *client) 20970e256018SJean Delvare { 20980e256018SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 20990e256018SJean Delvare u8 vid_ctl; 21000e256018SJean Delvare int i, err_max, err_min; 21010e256018SJean Delvare 21020e256018SJean Delvare vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); 21030e256018SJean Delvare 21040e256018SJean Delvare /* Return immediately if VRM isn't configured */ 21050e256018SJean Delvare if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) 21060e256018SJean Delvare return; 21070e256018SJean Delvare 21080e256018SJean Delvare data->has_dyn_in = (vid_ctl >> 3) & 0x07; 21090e256018SJean Delvare for (i = 0; i < 2; i++) { 21100e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 21110e256018SJean Delvare continue; 21120e256018SJean Delvare 21130e256018SJean Delvare /* Voltage limits in dynamic mode, switch to read-only */ 21140e256018SJean Delvare err_max = sysfs_chmod_file(&client->dev.kobj, 21150e256018SJean Delvare &w83795_in[i][2].dev_attr.attr, 21160e256018SJean Delvare S_IRUGO); 21170e256018SJean Delvare err_min = sysfs_chmod_file(&client->dev.kobj, 21180e256018SJean Delvare &w83795_in[i][3].dev_attr.attr, 21190e256018SJean Delvare S_IRUGO); 21200e256018SJean Delvare if (err_max || err_min) 2121b55f3757SGuenter Roeck dev_warn(&client->dev, 2122b55f3757SGuenter Roeck "Failed to set in%d limits read-only (%d, %d)\n", 2123b55f3757SGuenter Roeck i, err_max, err_min); 21240e256018SJean Delvare else 2125b55f3757SGuenter Roeck dev_info(&client->dev, 2126b55f3757SGuenter Roeck "in%d limits set dynamically from VID\n", i); 21270e256018SJean Delvare } 21280e256018SJean Delvare } 21290e256018SJean Delvare 213071caf46fSJean Delvare /* Check pins that can be used for either temperature or voltage monitoring */ 213171caf46fSJean Delvare static void w83795_apply_temp_config(struct w83795_data *data, u8 config, 213271caf46fSJean Delvare int temp_chan, int in_chan) 213371caf46fSJean Delvare { 213471caf46fSJean Delvare /* config is a 2-bit value */ 213571caf46fSJean Delvare switch (config) { 213671caf46fSJean Delvare case 0x2: /* Voltage monitoring */ 213771caf46fSJean Delvare data->has_in |= 1 << in_chan; 213871caf46fSJean Delvare break; 213971caf46fSJean Delvare case 0x1: /* Thermal diode */ 214071caf46fSJean Delvare if (temp_chan >= 4) 214171caf46fSJean Delvare break; 214271caf46fSJean Delvare data->temp_mode |= 1 << temp_chan; 214371caf46fSJean Delvare /* fall through */ 214471caf46fSJean Delvare case 0x3: /* Thermistor */ 214571caf46fSJean Delvare data->has_temp |= 1 << temp_chan; 214671caf46fSJean Delvare break; 214771caf46fSJean Delvare } 214871caf46fSJean Delvare } 214971caf46fSJean Delvare 2150792d376bSWei Song static int w83795_probe(struct i2c_client *client, 2151792d376bSWei Song const struct i2c_device_id *id) 2152792d376bSWei Song { 2153792d376bSWei Song int i; 2154792d376bSWei Song u8 tmp; 2155792d376bSWei Song struct device *dev = &client->dev; 2156792d376bSWei Song struct w83795_data *data; 215771caf46fSJean Delvare int err; 2158792d376bSWei Song 21594cb14a3aSGuenter Roeck data = devm_kzalloc(dev, sizeof(struct w83795_data), GFP_KERNEL); 21604cb14a3aSGuenter Roeck if (!data) 21614cb14a3aSGuenter Roeck return -ENOMEM; 2162792d376bSWei Song 2163792d376bSWei Song i2c_set_clientdata(client, data); 2164093d1a47SJean Delvare data->chip_type = id->driver_data; 2165792d376bSWei Song data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 2166792d376bSWei Song mutex_init(&data->update_lock); 2167792d376bSWei Song 2168792d376bSWei Song /* Initialize the chip */ 2169792d376bSWei Song w83795_init_client(client); 2170792d376bSWei Song 217171caf46fSJean Delvare /* Check which voltages and fans are present */ 217271caf46fSJean Delvare data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) 217371caf46fSJean Delvare | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); 217471caf46fSJean Delvare data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) 217571caf46fSJean Delvare | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); 2176792d376bSWei Song 217771caf46fSJean Delvare /* Check which analog temperatures and extra voltages are present */ 2178792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 2179792d376bSWei Song if (tmp & 0x20) 2180792d376bSWei Song data->enable_dts = 1; 218171caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); 218271caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 4, 15); 2183792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 218471caf46fSJean Delvare w83795_apply_temp_config(data, tmp >> 6, 3, 20); 218571caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); 218671caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); 218771caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 0, 17); 2188792d376bSWei Song 2189792d376bSWei Song /* Check DTS enable status */ 219071caf46fSJean Delvare if (data->enable_dts) { 2191792d376bSWei Song if (1 & w83795_read(client, W83795_REG_DTSC)) 2192792d376bSWei Song data->enable_dts |= 2; 2193792d376bSWei Song data->has_dts = w83795_read(client, W83795_REG_DTSE); 2194792d376bSWei Song } 2195792d376bSWei Song 219654891a3cSJean Delvare /* Report PECI Tbase values */ 219754891a3cSJean Delvare if (data->enable_dts == 1) { 219854891a3cSJean Delvare for (i = 0; i < 8; i++) { 219954891a3cSJean Delvare if (!(data->has_dts & (1 << i))) 220054891a3cSJean Delvare continue; 220154891a3cSJean Delvare tmp = w83795_read(client, W83795_REG_PECI_TBASE(i)); 220254891a3cSJean Delvare dev_info(&client->dev, 220354891a3cSJean Delvare "PECI agent %d Tbase temperature: %u\n", 220454891a3cSJean Delvare i + 1, (unsigned int)tmp & 0x7f); 220554891a3cSJean Delvare } 220654891a3cSJean Delvare } 220754891a3cSJean Delvare 2208792d376bSWei Song data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 2209792d376bSWei Song 2210792d376bSWei Song /* pwm and smart fan */ 2211792d376bSWei Song if (data->chip_type == w83795g) 2212792d376bSWei Song data->has_pwm = 8; 2213792d376bSWei Song else 2214792d376bSWei Song data->has_pwm = 2; 2215792d376bSWei Song 221652d159eeSJean Delvare /* Check if BEEP pin is available */ 221752d159eeSJean Delvare if (data->chip_type == w83795g) { 221852d159eeSJean Delvare /* The W83795G has a dedicated BEEP pin */ 221952d159eeSJean Delvare data->enable_beep = 1; 222052d159eeSJean Delvare } else { 2221c10b3ee8SGuenter Roeck /* 2222c10b3ee8SGuenter Roeck * The W83795ADG has a shared pin for OVT# and BEEP, so you 2223c10b3ee8SGuenter Roeck * can't have both 2224c10b3ee8SGuenter Roeck */ 222552d159eeSJean Delvare tmp = w83795_read(client, W83795_REG_OVT_CFG); 222652d159eeSJean Delvare if ((tmp & OVT_CFG_SEL) == 0) 222752d159eeSJean Delvare data->enable_beep = 1; 222852d159eeSJean Delvare } 222952d159eeSJean Delvare 22306f3dcde9SJean Delvare err = w83795_handle_files(dev, device_create_file); 2231792d376bSWei Song if (err) 2232792d376bSWei Song goto exit_remove; 2233792d376bSWei Song 22340e256018SJean Delvare if (data->chip_type == w83795g) 22350e256018SJean Delvare w83795_check_dynamic_in_limits(client); 22360e256018SJean Delvare 2237792d376bSWei Song data->hwmon_dev = hwmon_device_register(dev); 2238792d376bSWei Song if (IS_ERR(data->hwmon_dev)) { 2239792d376bSWei Song err = PTR_ERR(data->hwmon_dev); 2240792d376bSWei Song goto exit_remove; 2241792d376bSWei Song } 2242792d376bSWei Song 2243792d376bSWei Song return 0; 2244792d376bSWei Song 2245792d376bSWei Song exit_remove: 22466f3dcde9SJean Delvare w83795_handle_files(dev, device_remove_file_wrapper); 2247792d376bSWei Song return err; 2248792d376bSWei Song } 2249792d376bSWei Song 2250792d376bSWei Song static int w83795_remove(struct i2c_client *client) 2251792d376bSWei Song { 2252792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 2253792d376bSWei Song 2254792d376bSWei Song hwmon_device_unregister(data->hwmon_dev); 22556f3dcde9SJean Delvare w83795_handle_files(&client->dev, device_remove_file_wrapper); 2256792d376bSWei Song 2257792d376bSWei Song return 0; 2258792d376bSWei Song } 2259792d376bSWei Song 2260792d376bSWei Song 2261792d376bSWei Song static const struct i2c_device_id w83795_id[] = { 2262093d1a47SJean Delvare { "w83795g", w83795g }, 2263093d1a47SJean Delvare { "w83795adg", w83795adg }, 2264792d376bSWei Song { } 2265792d376bSWei Song }; 2266792d376bSWei Song MODULE_DEVICE_TABLE(i2c, w83795_id); 2267792d376bSWei Song 2268792d376bSWei Song static struct i2c_driver w83795_driver = { 2269792d376bSWei Song .driver = { 2270792d376bSWei Song .name = "w83795", 2271792d376bSWei Song }, 2272792d376bSWei Song .probe = w83795_probe, 2273792d376bSWei Song .remove = w83795_remove, 2274792d376bSWei Song .id_table = w83795_id, 2275792d376bSWei Song 2276792d376bSWei Song .class = I2C_CLASS_HWMON, 2277792d376bSWei Song .detect = w83795_detect, 2278792d376bSWei Song .address_list = normal_i2c, 2279792d376bSWei Song }; 2280792d376bSWei Song 2281f0967eeaSAxel Lin module_i2c_driver(w83795_driver); 2282792d376bSWei Song 22837c81c60fSJean Delvare MODULE_AUTHOR("Wei Song, Jean Delvare <jdelvare@suse.de>"); 2284315bacfdSJean Delvare MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 2285792d376bSWei Song MODULE_LICENSE("GPL"); 2286