1792d376bSWei Song /* 2792d376bSWei Song * w83795.c - Linux kernel driver for hardware monitoring 3792d376bSWei Song * Copyright (C) 2008 Nuvoton Technology Corp. 4792d376bSWei Song * Wei Song 5792d376bSWei Song * 6792d376bSWei Song * This program is free software; you can redistribute it and/or modify 7792d376bSWei Song * it under the terms of the GNU General Public License as published by 8792d376bSWei Song * the Free Software Foundation - version 2. 9792d376bSWei Song * 10792d376bSWei Song * This program is distributed in the hope that it will be useful, 11792d376bSWei Song * but WITHOUT ANY WARRANTY; without even the implied warranty of 12792d376bSWei Song * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13792d376bSWei Song * GNU General Public License for more details. 14792d376bSWei Song * 15792d376bSWei Song * You should have received a copy of the GNU General Public License 16792d376bSWei Song * along with this program; if not, write to the Free Software 17792d376bSWei Song * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18792d376bSWei Song * 02110-1301 USA. 19792d376bSWei Song * 20792d376bSWei Song * Supports following chips: 21792d376bSWei Song * 22792d376bSWei Song * Chip #vin #fanin #pwm #temp #dts wchipid vendid i2c ISA 23792d376bSWei Song * w83795g 21 14 8 6 8 0x79 0x5ca3 yes no 24792d376bSWei Song * w83795adg 18 14 2 6 8 0x79 0x5ca3 yes no 25792d376bSWei Song */ 26792d376bSWei Song 27792d376bSWei Song #include <linux/kernel.h> 28792d376bSWei Song #include <linux/module.h> 29792d376bSWei Song #include <linux/init.h> 30792d376bSWei Song #include <linux/slab.h> 31792d376bSWei Song #include <linux/i2c.h> 32792d376bSWei Song #include <linux/hwmon.h> 33792d376bSWei Song #include <linux/hwmon-sysfs.h> 34792d376bSWei Song #include <linux/err.h> 35792d376bSWei Song #include <linux/mutex.h> 36792d376bSWei Song #include <linux/delay.h> 37792d376bSWei Song 38792d376bSWei Song /* Addresses to scan */ 3986ef4d2fSJean Delvare static const unsigned short normal_i2c[] = { 4086ef4d2fSJean Delvare 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END 4186ef4d2fSJean Delvare }; 42792d376bSWei Song 43792d376bSWei Song 44792d376bSWei Song static int reset; 45792d376bSWei Song module_param(reset, bool, 0); 46792d376bSWei Song MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); 47792d376bSWei Song 48792d376bSWei Song 49792d376bSWei Song #define W83795_REG_BANKSEL 0x00 50792d376bSWei Song #define W83795_REG_VENDORID 0xfd 51792d376bSWei Song #define W83795_REG_CHIPID 0xfe 52792d376bSWei Song #define W83795_REG_DEVICEID 0xfb 532be381deSJean Delvare #define W83795_REG_DEVICEID_A 0xff 54792d376bSWei Song 55792d376bSWei Song #define W83795_REG_I2C_ADDR 0xfc 56792d376bSWei Song #define W83795_REG_CONFIG 0x01 57792d376bSWei Song #define W83795_REG_CONFIG_CONFIG48 0x04 5880646b95SJean Delvare #define W83795_REG_CONFIG_START 0x01 59792d376bSWei Song 60792d376bSWei Song /* Multi-Function Pin Ctrl Registers */ 61792d376bSWei Song #define W83795_REG_VOLT_CTRL1 0x02 62792d376bSWei Song #define W83795_REG_VOLT_CTRL2 0x03 63792d376bSWei Song #define W83795_REG_TEMP_CTRL1 0x04 64792d376bSWei Song #define W83795_REG_TEMP_CTRL2 0x05 65792d376bSWei Song #define W83795_REG_FANIN_CTRL1 0x06 66792d376bSWei Song #define W83795_REG_FANIN_CTRL2 0x07 67792d376bSWei Song #define W83795_REG_VMIGB_CTRL 0x08 68792d376bSWei Song 69792d376bSWei Song #define TEMP_READ 0 70792d376bSWei Song #define TEMP_CRIT 1 71792d376bSWei Song #define TEMP_CRIT_HYST 2 72792d376bSWei Song #define TEMP_WARN 3 73792d376bSWei Song #define TEMP_WARN_HYST 4 74792d376bSWei Song /* only crit and crit_hyst affect real-time alarm status 75792d376bSWei Song * current crit crit_hyst warn warn_hyst */ 7686ef4d2fSJean Delvare static const u16 W83795_REG_TEMP[][5] = { 77792d376bSWei Song {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ 78792d376bSWei Song {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ 79792d376bSWei Song {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ 80792d376bSWei Song {0x24, 0xa2, 0xa3, 0xa4, 0xa5}, /* TD4/TR4 */ 81792d376bSWei Song {0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, /* TR5 */ 82792d376bSWei Song {0x20, 0xaa, 0xab, 0xac, 0xad}, /* TR6 */ 83792d376bSWei Song }; 84792d376bSWei Song 85792d376bSWei Song #define IN_READ 0 86792d376bSWei Song #define IN_MAX 1 87792d376bSWei Song #define IN_LOW 2 88792d376bSWei Song static const u16 W83795_REG_IN[][3] = { 89792d376bSWei Song /* Current, HL, LL */ 90792d376bSWei Song {0x10, 0x70, 0x71}, /* VSEN1 */ 91792d376bSWei Song {0x11, 0x72, 0x73}, /* VSEN2 */ 92792d376bSWei Song {0x12, 0x74, 0x75}, /* VSEN3 */ 93792d376bSWei Song {0x13, 0x76, 0x77}, /* VSEN4 */ 94792d376bSWei Song {0x14, 0x78, 0x79}, /* VSEN5 */ 95792d376bSWei Song {0x15, 0x7a, 0x7b}, /* VSEN6 */ 96792d376bSWei Song {0x16, 0x7c, 0x7d}, /* VSEN7 */ 97792d376bSWei Song {0x17, 0x7e, 0x7f}, /* VSEN8 */ 98792d376bSWei Song {0x18, 0x80, 0x81}, /* VSEN9 */ 99792d376bSWei Song {0x19, 0x82, 0x83}, /* VSEN10 */ 100792d376bSWei Song {0x1A, 0x84, 0x85}, /* VSEN11 */ 101792d376bSWei Song {0x1B, 0x86, 0x87}, /* VTT */ 102792d376bSWei Song {0x1C, 0x88, 0x89}, /* 3VDD */ 103792d376bSWei Song {0x1D, 0x8a, 0x8b}, /* 3VSB */ 104792d376bSWei Song {0x1E, 0x8c, 0x8d}, /* VBAT */ 105792d376bSWei Song {0x1F, 0xa6, 0xa7}, /* VSEN12 */ 106792d376bSWei Song {0x20, 0xaa, 0xab}, /* VSEN13 */ 107792d376bSWei Song {0x21, 0x96, 0x97}, /* VSEN14 */ 108792d376bSWei Song {0x22, 0x9a, 0x9b}, /* VSEN15 */ 109792d376bSWei Song {0x23, 0x9e, 0x9f}, /* VSEN16 */ 110792d376bSWei Song {0x24, 0xa2, 0xa3}, /* VSEN17 */ 111792d376bSWei Song }; 112792d376bSWei Song #define W83795_REG_VRLSB 0x3C 113792d376bSWei Song 114792d376bSWei Song static const u8 W83795_REG_IN_HL_LSB[] = { 115792d376bSWei Song 0x8e, /* VSEN1-4 */ 116792d376bSWei Song 0x90, /* VSEN5-8 */ 117792d376bSWei Song 0x92, /* VSEN9-11 */ 118792d376bSWei Song 0x94, /* VTT, 3VDD, 3VSB, 3VBAT */ 119792d376bSWei Song 0xa8, /* VSEN12 */ 120792d376bSWei Song 0xac, /* VSEN13 */ 121792d376bSWei Song 0x98, /* VSEN14 */ 122792d376bSWei Song 0x9c, /* VSEN15 */ 123792d376bSWei Song 0xa0, /* VSEN16 */ 124792d376bSWei Song 0xa4, /* VSEN17 */ 125792d376bSWei Song }; 126792d376bSWei Song 127792d376bSWei Song #define IN_LSB_REG(index, type) \ 128792d376bSWei Song (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ 129792d376bSWei Song : (W83795_REG_IN_HL_LSB[(index)] + 1)) 130792d376bSWei Song 131792d376bSWei Song #define IN_LSB_SHIFT 0 132792d376bSWei Song #define IN_LSB_IDX 1 133792d376bSWei Song static const u8 IN_LSB_SHIFT_IDX[][2] = { 134792d376bSWei Song /* High/Low LSB shift, LSB No. */ 135792d376bSWei Song {0x00, 0x00}, /* VSEN1 */ 136792d376bSWei Song {0x02, 0x00}, /* VSEN2 */ 137792d376bSWei Song {0x04, 0x00}, /* VSEN3 */ 138792d376bSWei Song {0x06, 0x00}, /* VSEN4 */ 139792d376bSWei Song {0x00, 0x01}, /* VSEN5 */ 140792d376bSWei Song {0x02, 0x01}, /* VSEN6 */ 141792d376bSWei Song {0x04, 0x01}, /* VSEN7 */ 142792d376bSWei Song {0x06, 0x01}, /* VSEN8 */ 143792d376bSWei Song {0x00, 0x02}, /* VSEN9 */ 144792d376bSWei Song {0x02, 0x02}, /* VSEN10 */ 145792d376bSWei Song {0x04, 0x02}, /* VSEN11 */ 146792d376bSWei Song {0x00, 0x03}, /* VTT */ 147792d376bSWei Song {0x02, 0x03}, /* 3VDD */ 148792d376bSWei Song {0x04, 0x03}, /* 3VSB */ 149792d376bSWei Song {0x06, 0x03}, /* VBAT */ 150792d376bSWei Song {0x06, 0x04}, /* VSEN12 */ 151792d376bSWei Song {0x06, 0x05}, /* VSEN13 */ 152792d376bSWei Song {0x06, 0x06}, /* VSEN14 */ 153792d376bSWei Song {0x06, 0x07}, /* VSEN15 */ 154792d376bSWei Song {0x06, 0x08}, /* VSEN16 */ 155792d376bSWei Song {0x06, 0x09}, /* VSEN17 */ 156792d376bSWei Song }; 157792d376bSWei Song 158792d376bSWei Song 159792d376bSWei Song #define W83795_REG_FAN(index) (0x2E + (index)) 160792d376bSWei Song #define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) 161792d376bSWei Song #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) 162792d376bSWei Song #define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ 1637eb8d508SJean Delvare (((index) & 1) ? 4 : 0) 164792d376bSWei Song 165792d376bSWei Song #define W83795_REG_VID_CTRL 0x6A 166792d376bSWei Song 167792d376bSWei Song #define W83795_REG_ALARM(index) (0x41 + (index)) 168792d376bSWei Song #define W83795_REG_BEEP(index) (0x50 + (index)) 169792d376bSWei Song 170792d376bSWei Song #define W83795_REG_CLR_CHASSIS 0x4D 171792d376bSWei Song 172792d376bSWei Song 173792d376bSWei Song #define W83795_REG_FCMS1 0x201 174792d376bSWei Song #define W83795_REG_FCMS2 0x208 175792d376bSWei Song #define W83795_REG_TFMR(index) (0x202 + (index)) 176792d376bSWei Song #define W83795_REG_FOMC 0x20F 177792d376bSWei Song 178792d376bSWei Song #define W83795_REG_TSS(index) (0x209 + (index)) 179792d376bSWei Song 180792d376bSWei Song #define PWM_OUTPUT 0 181fd7f82b8SJean Delvare #define PWM_FREQ 1 182fd7f82b8SJean Delvare #define PWM_START 2 183fd7f82b8SJean Delvare #define PWM_NONSTOP 3 184fd7f82b8SJean Delvare #define PWM_STOP_TIME 4 185fd7f82b8SJean Delvare #define W83795_REG_PWM(index, nr) (0x210 + (nr) * 8 + (index)) 186792d376bSWei Song 187792d376bSWei Song #define W83795_REG_FTSH(index) (0x240 + (index) * 2) 188792d376bSWei Song #define W83795_REG_FTSL(index) (0x241 + (index) * 2) 189792d376bSWei Song #define W83795_REG_TFTS 0x250 190792d376bSWei Song 191792d376bSWei Song #define TEMP_PWM_TTTI 0 192792d376bSWei Song #define TEMP_PWM_CTFS 1 193792d376bSWei Song #define TEMP_PWM_HCT 2 194792d376bSWei Song #define TEMP_PWM_HOT 3 195792d376bSWei Song #define W83795_REG_TTTI(index) (0x260 + (index)) 196792d376bSWei Song #define W83795_REG_CTFS(index) (0x268 + (index)) 197792d376bSWei Song #define W83795_REG_HT(index) (0x270 + (index)) 198792d376bSWei Song 199792d376bSWei Song #define SF4_TEMP 0 200792d376bSWei Song #define SF4_PWM 1 201792d376bSWei Song #define W83795_REG_SF4_TEMP(temp_num, index) \ 202792d376bSWei Song (0x280 + 0x10 * (temp_num) + (index)) 203792d376bSWei Song #define W83795_REG_SF4_PWM(temp_num, index) \ 204792d376bSWei Song (0x288 + 0x10 * (temp_num) + (index)) 205792d376bSWei Song 206792d376bSWei Song #define W83795_REG_DTSC 0x301 207792d376bSWei Song #define W83795_REG_DTSE 0x302 208792d376bSWei Song #define W83795_REG_DTS(index) (0x26 + (index)) 20954891a3cSJean Delvare #define W83795_REG_PECI_TBASE(index) (0x320 + (index)) 210792d376bSWei Song 211792d376bSWei Song #define DTS_CRIT 0 212792d376bSWei Song #define DTS_CRIT_HYST 1 213792d376bSWei Song #define DTS_WARN 2 214792d376bSWei Song #define DTS_WARN_HYST 3 215792d376bSWei Song #define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 216792d376bSWei Song 217792d376bSWei Song #define SETUP_PWM_DEFAULT 0 218792d376bSWei Song #define SETUP_PWM_UPTIME 1 219792d376bSWei Song #define SETUP_PWM_DOWNTIME 2 220792d376bSWei Song #define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 221792d376bSWei Song 222792d376bSWei Song static inline u16 in_from_reg(u8 index, u16 val) 223792d376bSWei Song { 22449c7347aSJean Delvare /* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */ 22549c7347aSJean Delvare if (index >= 12 && index <= 14) 226792d376bSWei Song return val * 6; 227792d376bSWei Song else 228792d376bSWei Song return val * 2; 229792d376bSWei Song } 230792d376bSWei Song 231792d376bSWei Song static inline u16 in_to_reg(u8 index, u16 val) 232792d376bSWei Song { 23349c7347aSJean Delvare if (index >= 12 && index <= 14) 234792d376bSWei Song return val / 6; 235792d376bSWei Song else 236792d376bSWei Song return val / 2; 237792d376bSWei Song } 238792d376bSWei Song 239792d376bSWei Song static inline unsigned long fan_from_reg(u16 val) 240792d376bSWei Song { 2416c82b2f3SJean Delvare if ((val == 0xfff) || (val == 0)) 242792d376bSWei Song return 0; 243792d376bSWei Song return 1350000UL / val; 244792d376bSWei Song } 245792d376bSWei Song 246792d376bSWei Song static inline u16 fan_to_reg(long rpm) 247792d376bSWei Song { 248792d376bSWei Song if (rpm <= 0) 249792d376bSWei Song return 0x0fff; 250792d376bSWei Song return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 251792d376bSWei Song } 252792d376bSWei Song 253792d376bSWei Song static inline unsigned long time_from_reg(u8 reg) 254792d376bSWei Song { 255792d376bSWei Song return reg * 100; 256792d376bSWei Song } 257792d376bSWei Song 258792d376bSWei Song static inline u8 time_to_reg(unsigned long val) 259792d376bSWei Song { 260792d376bSWei Song return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); 261792d376bSWei Song } 262792d376bSWei Song 263792d376bSWei Song static inline long temp_from_reg(s8 reg) 264792d376bSWei Song { 265792d376bSWei Song return reg * 1000; 266792d376bSWei Song } 267792d376bSWei Song 268792d376bSWei Song static inline s8 temp_to_reg(long val, s8 min, s8 max) 269792d376bSWei Song { 270dd127f5cSJean Delvare return SENSORS_LIMIT(val / 1000, min, max); 271792d376bSWei Song } 272792d376bSWei Song 27301879a85SJean Delvare static const u16 pwm_freq_cksel0[16] = { 27401879a85SJean Delvare 1024, 512, 341, 256, 205, 171, 146, 128, 27501879a85SJean Delvare 85, 64, 32, 16, 8, 4, 2, 1 27601879a85SJean Delvare }; 27701879a85SJean Delvare 27801879a85SJean Delvare static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) 27901879a85SJean Delvare { 28001879a85SJean Delvare unsigned long base_clock; 28101879a85SJean Delvare 28201879a85SJean Delvare if (reg & 0x80) { 28301879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 28401879a85SJean Delvare return base_clock / ((reg & 0x7f) + 1); 28501879a85SJean Delvare } else 28601879a85SJean Delvare return pwm_freq_cksel0[reg & 0x0f]; 28701879a85SJean Delvare } 28801879a85SJean Delvare 28901879a85SJean Delvare static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) 29001879a85SJean Delvare { 29101879a85SJean Delvare unsigned long base_clock; 29201879a85SJean Delvare u8 reg0, reg1; 29301879a85SJean Delvare unsigned long best0, best1; 29401879a85SJean Delvare 29501879a85SJean Delvare /* Best fit for cksel = 0 */ 29601879a85SJean Delvare for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { 29701879a85SJean Delvare if (val > (pwm_freq_cksel0[reg0] + 29801879a85SJean Delvare pwm_freq_cksel0[reg0 + 1]) / 2) 29901879a85SJean Delvare break; 30001879a85SJean Delvare } 30101879a85SJean Delvare if (val < 375) /* cksel = 1 can't beat this */ 30201879a85SJean Delvare return reg0; 30301879a85SJean Delvare best0 = pwm_freq_cksel0[reg0]; 30401879a85SJean Delvare 30501879a85SJean Delvare /* Best fit for cksel = 1 */ 30601879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 30701879a85SJean Delvare reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); 30801879a85SJean Delvare best1 = base_clock / reg1; 30901879a85SJean Delvare reg1 = 0x80 | (reg1 - 1); 31001879a85SJean Delvare 31101879a85SJean Delvare /* Choose the closest one */ 31201879a85SJean Delvare if (abs(val - best0) > abs(val - best1)) 31301879a85SJean Delvare return reg1; 31401879a85SJean Delvare else 31501879a85SJean Delvare return reg0; 31601879a85SJean Delvare } 317792d376bSWei Song 318792d376bSWei Song enum chip_types {w83795g, w83795adg}; 319792d376bSWei Song 320792d376bSWei Song struct w83795_data { 321792d376bSWei Song struct device *hwmon_dev; 322792d376bSWei Song struct mutex update_lock; 323792d376bSWei Song unsigned long last_updated; /* In jiffies */ 324792d376bSWei Song enum chip_types chip_type; 325792d376bSWei Song 326792d376bSWei Song u8 bank; 327792d376bSWei Song 328792d376bSWei Song u32 has_in; /* Enable monitor VIN or not */ 3290e256018SJean Delvare u8 has_dyn_in; /* Only in2-0 can have this */ 330792d376bSWei Song u16 in[21][3]; /* Register value, read/high/low */ 331792d376bSWei Song u8 in_lsb[10][3]; /* LSB Register value, high/low */ 332792d376bSWei Song u8 has_gain; /* has gain: in17-20 * 8 */ 333792d376bSWei Song 334792d376bSWei Song u16 has_fan; /* Enable fan14-1 or not */ 335792d376bSWei Song u16 fan[14]; /* Register value combine */ 336792d376bSWei Song u16 fan_min[14]; /* Register value combine */ 337792d376bSWei Song 338792d376bSWei Song u8 has_temp; /* Enable monitor temp6-1 or not */ 339dd127f5cSJean Delvare s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 340792d376bSWei Song u8 temp_read_vrlsb[6]; 34139deb699SJean Delvare u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */ 342792d376bSWei Song u8 temp_src[3]; /* Register value */ 343792d376bSWei Song 344792d376bSWei Song u8 enable_dts; /* Enable PECI and SB-TSI, 345792d376bSWei Song * bit 0: =1 enable, =0 disable, 346792d376bSWei Song * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ 347792d376bSWei Song u8 has_dts; /* Enable monitor DTS temp */ 348dd127f5cSJean Delvare s8 dts[8]; /* Register value */ 349792d376bSWei Song u8 dts_read_vrlsb[8]; /* Register value */ 350dd127f5cSJean Delvare s8 dts_ext[4]; /* Register value */ 351792d376bSWei Song 352792d376bSWei Song u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, 353792d376bSWei Song * no config register, only affected by chip 354792d376bSWei Song * type */ 355fd7f82b8SJean Delvare u8 pwm[8][5]; /* Register value, output, freq, start, 356fd7f82b8SJean Delvare * non stop, stop time */ 35701879a85SJean Delvare u16 clkin; /* CLKIN frequency in kHz */ 358792d376bSWei Song u8 pwm_fcms[2]; /* Register value */ 359792d376bSWei Song u8 pwm_tfmr[6]; /* Register value */ 360792d376bSWei Song u8 pwm_fomc; /* Register value */ 361792d376bSWei Song 362792d376bSWei Song u16 target_speed[8]; /* Register value, target speed for speed 363792d376bSWei Song * cruise */ 364792d376bSWei Song u8 tol_speed; /* tolerance of target speed */ 365792d376bSWei Song u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 366792d376bSWei Song u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 367792d376bSWei Song 368792d376bSWei Song u8 setup_pwm[3]; /* Register value */ 369792d376bSWei Song 370792d376bSWei Song u8 alarms[6]; /* Register value */ 371792d376bSWei Song u8 beeps[6]; /* Register value */ 372792d376bSWei Song 373792d376bSWei Song char valid; 374792d376bSWei Song }; 375792d376bSWei Song 376792d376bSWei Song /* 377792d376bSWei Song * Hardware access 378b2469f42SJean Delvare * We assume that nobdody can change the bank outside the driver. 379792d376bSWei Song */ 380792d376bSWei Song 381b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 382b2469f42SJean Delvare static int w83795_set_bank(struct i2c_client *client, u8 bank) 383792d376bSWei Song { 384792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 385b2469f42SJean Delvare int err; 386792d376bSWei Song 387b2469f42SJean Delvare /* If the same bank is already set, nothing to do */ 388b2469f42SJean Delvare if ((data->bank & 0x07) == bank) 389b2469f42SJean Delvare return 0; 390b2469f42SJean Delvare 391b2469f42SJean Delvare /* Change to new bank, preserve all other bits */ 392b2469f42SJean Delvare bank |= data->bank & ~0x07; 393b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 394b2469f42SJean Delvare if (err < 0) { 395792d376bSWei Song dev_err(&client->dev, 396b2469f42SJean Delvare "Failed to set bank to %d, err %d\n", 397b2469f42SJean Delvare (int)bank, err); 398b2469f42SJean Delvare return err; 399792d376bSWei Song } 400b2469f42SJean Delvare data->bank = bank; 401b2469f42SJean Delvare 402b2469f42SJean Delvare return 0; 403792d376bSWei Song } 404b2469f42SJean Delvare 405b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 406b2469f42SJean Delvare static u8 w83795_read(struct i2c_client *client, u16 reg) 407b2469f42SJean Delvare { 408b2469f42SJean Delvare int err; 409b2469f42SJean Delvare 410b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 411b2469f42SJean Delvare if (err < 0) 412b2469f42SJean Delvare return 0x00; /* Arbitrary */ 413b2469f42SJean Delvare 414b2469f42SJean Delvare err = i2c_smbus_read_byte_data(client, reg & 0xff); 415b2469f42SJean Delvare if (err < 0) { 416b2469f42SJean Delvare dev_err(&client->dev, 417b2469f42SJean Delvare "Failed to read from register 0x%03x, err %d\n", 418b2469f42SJean Delvare (int)reg, err); 419b2469f42SJean Delvare return 0x00; /* Arbitrary */ 420b2469f42SJean Delvare } 421b2469f42SJean Delvare return err; 422792d376bSWei Song } 423792d376bSWei Song 424792d376bSWei Song /* Must be called with data->update_lock held, except during initialization */ 425792d376bSWei Song static int w83795_write(struct i2c_client *client, u16 reg, u8 value) 426792d376bSWei Song { 427b2469f42SJean Delvare int err; 428792d376bSWei Song 429b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 430b2469f42SJean Delvare if (err < 0) 431b2469f42SJean Delvare return err; 432b2469f42SJean Delvare 433b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 434b2469f42SJean Delvare if (err < 0) 435792d376bSWei Song dev_err(&client->dev, 436b2469f42SJean Delvare "Failed to write to register 0x%03x, err %d\n", 437b2469f42SJean Delvare (int)reg, err); 438b2469f42SJean Delvare return err; 439792d376bSWei Song } 440792d376bSWei Song 4410d7237bfSJean Delvare static void w83795_update_limits(struct i2c_client *client) 4420d7237bfSJean Delvare { 4430d7237bfSJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 4440d7237bfSJean Delvare int i, limit; 4450d7237bfSJean Delvare 4460d7237bfSJean Delvare /* Read the voltage limits */ 4470d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->in); i++) { 4480d7237bfSJean Delvare if (!(data->has_in & (1 << i))) 4490d7237bfSJean Delvare continue; 4500d7237bfSJean Delvare data->in[i][IN_MAX] = 4510d7237bfSJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 4520d7237bfSJean Delvare data->in[i][IN_LOW] = 4530d7237bfSJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 4540d7237bfSJean Delvare } 4550d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { 4560d7237bfSJean Delvare if ((i == 2 && data->chip_type == w83795adg) || 4570d7237bfSJean Delvare (i >= 4 && !(data->has_in & (1 << (i + 11))))) 4580d7237bfSJean Delvare continue; 4590d7237bfSJean Delvare data->in_lsb[i][IN_MAX] = 4600d7237bfSJean Delvare w83795_read(client, IN_LSB_REG(i, IN_MAX)); 4610d7237bfSJean Delvare data->in_lsb[i][IN_LOW] = 4620d7237bfSJean Delvare w83795_read(client, IN_LSB_REG(i, IN_LOW)); 4630d7237bfSJean Delvare } 4640d7237bfSJean Delvare 4650d7237bfSJean Delvare /* Read the fan limits */ 4660d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 4670d7237bfSJean Delvare u8 lsb; 4680d7237bfSJean Delvare 4690d7237bfSJean Delvare /* Each register contains LSB for 2 fans, but we want to 4700d7237bfSJean Delvare * read it only once to save time */ 4710d7237bfSJean Delvare if ((i & 1) == 0 && (data->has_fan & (3 << i))) 4720d7237bfSJean Delvare lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); 4730d7237bfSJean Delvare 4740d7237bfSJean Delvare if (!(data->has_fan & (1 << i))) 4750d7237bfSJean Delvare continue; 4760d7237bfSJean Delvare data->fan_min[i] = 4770d7237bfSJean Delvare w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 4780d7237bfSJean Delvare data->fan_min[i] |= 4790d7237bfSJean Delvare (lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; 4800d7237bfSJean Delvare } 4810d7237bfSJean Delvare 4820d7237bfSJean Delvare /* Read the temperature limits */ 4830d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 4840d7237bfSJean Delvare if (!(data->has_temp & (1 << i))) 4850d7237bfSJean Delvare continue; 4860d7237bfSJean Delvare for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++) 4870d7237bfSJean Delvare data->temp[i][limit] = 4880d7237bfSJean Delvare w83795_read(client, W83795_REG_TEMP[i][limit]); 4890d7237bfSJean Delvare } 4900d7237bfSJean Delvare 4910d7237bfSJean Delvare /* Read the DTS limits */ 4920d7237bfSJean Delvare if (data->enable_dts != 0) { 4930d7237bfSJean Delvare for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++) 4940d7237bfSJean Delvare data->dts_ext[limit] = 4950d7237bfSJean Delvare w83795_read(client, W83795_REG_DTS_EXT(limit)); 4960d7237bfSJean Delvare } 4970d7237bfSJean Delvare 4980d7237bfSJean Delvare /* Read beep settings */ 4990d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->beeps); i++) 5000d7237bfSJean Delvare data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); 5010d7237bfSJean Delvare } 5020d7237bfSJean Delvare 5030d7237bfSJean Delvare static void w83795_update_pwm_config(struct i2c_client *client) 5040d7237bfSJean Delvare { 5050d7237bfSJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 5060d7237bfSJean Delvare int i, tmp; 5070d7237bfSJean Delvare 5080d7237bfSJean Delvare /* Read temperature source selection */ 5090d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp_src); i++) 5100d7237bfSJean Delvare data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 5110d7237bfSJean Delvare 5120d7237bfSJean Delvare /* Read automatic fan speed control settings */ 5130d7237bfSJean Delvare data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 5140d7237bfSJean Delvare data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 5150d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) 5160d7237bfSJean Delvare data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 5170d7237bfSJean Delvare data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 5180d7237bfSJean Delvare for (i = 0; i < data->has_pwm; i++) { 5190d7237bfSJean Delvare for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) 5200d7237bfSJean Delvare data->pwm[i][tmp] = 5210d7237bfSJean Delvare w83795_read(client, W83795_REG_PWM(i, tmp)); 5220d7237bfSJean Delvare } 5230d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) { 5240d7237bfSJean Delvare data->target_speed[i] = 5250d7237bfSJean Delvare w83795_read(client, W83795_REG_FTSH(i)) << 4; 5260d7237bfSJean Delvare data->target_speed[i] |= 5270d7237bfSJean Delvare w83795_read(client, W83795_REG_FTSL(i)) >> 4; 5280d7237bfSJean Delvare } 5290d7237bfSJean Delvare data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 5300d7237bfSJean Delvare 5310d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { 5320d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_TTTI] = 5330d7237bfSJean Delvare w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 5340d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_CTFS] = 5350d7237bfSJean Delvare w83795_read(client, W83795_REG_CTFS(i)); 5360d7237bfSJean Delvare tmp = w83795_read(client, W83795_REG_HT(i)); 5370d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; 5380d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 5390d7237bfSJean Delvare } 5400d7237bfSJean Delvare 5410d7237bfSJean Delvare /* Read SmartFanIV trip points */ 5420d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { 5430d7237bfSJean Delvare for (tmp = 0; tmp < 7; tmp++) { 5440d7237bfSJean Delvare data->sf4_reg[i][SF4_TEMP][tmp] = 5450d7237bfSJean Delvare w83795_read(client, 5460d7237bfSJean Delvare W83795_REG_SF4_TEMP(i, tmp)); 5470d7237bfSJean Delvare data->sf4_reg[i][SF4_PWM][tmp] = 5480d7237bfSJean Delvare w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 5490d7237bfSJean Delvare } 5500d7237bfSJean Delvare } 5510d7237bfSJean Delvare 5520d7237bfSJean Delvare /* Read setup PWM */ 5530d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++) 5540d7237bfSJean Delvare data->setup_pwm[i] = 5550d7237bfSJean Delvare w83795_read(client, W83795_REG_SETUP_PWM(i)); 5560d7237bfSJean Delvare } 5570d7237bfSJean Delvare 558792d376bSWei Song static struct w83795_data *w83795_update_device(struct device *dev) 559792d376bSWei Song { 560792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 561792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 562792d376bSWei Song u16 tmp; 563792d376bSWei Song int i; 564792d376bSWei Song 565792d376bSWei Song mutex_lock(&data->update_lock); 566792d376bSWei Song 567792d376bSWei Song if (!(time_after(jiffies, data->last_updated + HZ * 2) 568792d376bSWei Song || !data->valid)) 569792d376bSWei Song goto END; 570792d376bSWei Song 571792d376bSWei Song /* Update the voltages value */ 572792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 573792d376bSWei Song if (!(data->has_in & (1 << i))) 574792d376bSWei Song continue; 575792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 576a654b9d4SJean Delvare tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; 577792d376bSWei Song data->in[i][IN_READ] = tmp; 578792d376bSWei Song } 579792d376bSWei Song 5800e256018SJean Delvare /* in0-2 can have dynamic limits (W83795G only) */ 5810e256018SJean Delvare if (data->has_dyn_in) { 5820e256018SJean Delvare u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); 5830e256018SJean Delvare u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); 5840e256018SJean Delvare 5850e256018SJean Delvare for (i = 0; i < 3; i++) { 5860e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 5870e256018SJean Delvare continue; 5880e256018SJean Delvare data->in[i][IN_MAX] = 5890e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 5900e256018SJean Delvare data->in[i][IN_LOW] = 5910e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 5920e256018SJean Delvare data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; 5930e256018SJean Delvare data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; 5940e256018SJean Delvare } 5950e256018SJean Delvare } 5960e256018SJean Delvare 597792d376bSWei Song /* Update fan */ 598792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 599792d376bSWei Song if (!(data->has_fan & (1 << i))) 600792d376bSWei Song continue; 601792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 602792d376bSWei Song data->fan[i] |= 6036c82b2f3SJean Delvare (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; 604792d376bSWei Song } 605792d376bSWei Song 606792d376bSWei Song /* Update temperature */ 607792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 608792d376bSWei Song data->temp[i][TEMP_READ] = 609792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 610792d376bSWei Song data->temp_read_vrlsb[i] = 611792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 612792d376bSWei Song } 613792d376bSWei Song 614792d376bSWei Song /* Update dts temperature */ 615792d376bSWei Song if (data->enable_dts != 0) { 616792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 617792d376bSWei Song if (!(data->has_dts & (1 << i))) 618792d376bSWei Song continue; 619792d376bSWei Song data->dts[i] = 620792d376bSWei Song w83795_read(client, W83795_REG_DTS(i)); 621792d376bSWei Song data->dts_read_vrlsb[i] = 622792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 623792d376bSWei Song } 624792d376bSWei Song } 625792d376bSWei Song 626792d376bSWei Song /* Update pwm output */ 627792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 628792d376bSWei Song data->pwm[i][PWM_OUTPUT] = 629792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 630792d376bSWei Song } 631792d376bSWei Song 632792d376bSWei Song /* update alarm */ 633cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->alarms); i++) 634792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 635792d376bSWei Song 636792d376bSWei Song data->last_updated = jiffies; 637792d376bSWei Song data->valid = 1; 638792d376bSWei Song 639792d376bSWei Song END: 640792d376bSWei Song mutex_unlock(&data->update_lock); 641792d376bSWei Song return data; 642792d376bSWei Song } 643792d376bSWei Song 644792d376bSWei Song /* 645792d376bSWei Song * Sysfs attributes 646792d376bSWei Song */ 647792d376bSWei Song 648792d376bSWei Song #define ALARM_STATUS 0 649792d376bSWei Song #define BEEP_ENABLE 1 650792d376bSWei Song static ssize_t 651792d376bSWei Song show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 652792d376bSWei Song { 653792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 654792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 655792d376bSWei Song to_sensor_dev_attr_2(attr); 656792d376bSWei Song int nr = sensor_attr->nr; 657792d376bSWei Song int index = sensor_attr->index >> 3; 658792d376bSWei Song int bit = sensor_attr->index & 0x07; 659792d376bSWei Song u8 val; 660792d376bSWei Song 661792d376bSWei Song if (ALARM_STATUS == nr) { 662792d376bSWei Song val = (data->alarms[index] >> (bit)) & 1; 663792d376bSWei Song } else { /* BEEP_ENABLE */ 664792d376bSWei Song val = (data->beeps[index] >> (bit)) & 1; 665792d376bSWei Song } 666792d376bSWei Song 667792d376bSWei Song return sprintf(buf, "%u\n", val); 668792d376bSWei Song } 669792d376bSWei Song 670792d376bSWei Song static ssize_t 671792d376bSWei Song store_beep(struct device *dev, struct device_attribute *attr, 672792d376bSWei Song const char *buf, size_t count) 673792d376bSWei Song { 674792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 675792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 676792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 677792d376bSWei Song to_sensor_dev_attr_2(attr); 678792d376bSWei Song int index = sensor_attr->index >> 3; 679792d376bSWei Song int shift = sensor_attr->index & 0x07; 680792d376bSWei Song u8 beep_bit = 1 << shift; 681792d376bSWei Song unsigned long val; 682792d376bSWei Song 683792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 684792d376bSWei Song return -EINVAL; 685792d376bSWei Song if (val != 0 && val != 1) 686792d376bSWei Song return -EINVAL; 687792d376bSWei Song 688792d376bSWei Song mutex_lock(&data->update_lock); 689792d376bSWei Song data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 690792d376bSWei Song data->beeps[index] &= ~beep_bit; 691792d376bSWei Song data->beeps[index] |= val << shift; 692792d376bSWei Song w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 693792d376bSWei Song mutex_unlock(&data->update_lock); 694792d376bSWei Song 695792d376bSWei Song return count; 696792d376bSWei Song } 697792d376bSWei Song 698792d376bSWei Song /* Write any value to clear chassis alarm */ 699792d376bSWei Song static ssize_t 700792d376bSWei Song store_chassis_clear(struct device *dev, 701792d376bSWei Song struct device_attribute *attr, const char *buf, 702792d376bSWei Song size_t count) 703792d376bSWei Song { 704792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 705792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 706792d376bSWei Song u8 val; 707792d376bSWei Song 708792d376bSWei Song mutex_lock(&data->update_lock); 709792d376bSWei Song val = w83795_read(client, W83795_REG_CLR_CHASSIS); 710792d376bSWei Song val |= 0x80; 711792d376bSWei Song w83795_write(client, W83795_REG_CLR_CHASSIS, val); 712792d376bSWei Song mutex_unlock(&data->update_lock); 713792d376bSWei Song return count; 714792d376bSWei Song } 715792d376bSWei Song 716792d376bSWei Song #define FAN_INPUT 0 717792d376bSWei Song #define FAN_MIN 1 718792d376bSWei Song static ssize_t 719792d376bSWei Song show_fan(struct device *dev, struct device_attribute *attr, char *buf) 720792d376bSWei Song { 721792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 722792d376bSWei Song to_sensor_dev_attr_2(attr); 723792d376bSWei Song int nr = sensor_attr->nr; 724792d376bSWei Song int index = sensor_attr->index; 725792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 726792d376bSWei Song u16 val; 727792d376bSWei Song 728792d376bSWei Song if (FAN_INPUT == nr) 729792d376bSWei Song val = data->fan[index] & 0x0fff; 730792d376bSWei Song else 731792d376bSWei Song val = data->fan_min[index] & 0x0fff; 732792d376bSWei Song 733792d376bSWei Song return sprintf(buf, "%lu\n", fan_from_reg(val)); 734792d376bSWei Song } 735792d376bSWei Song 736792d376bSWei Song static ssize_t 737792d376bSWei Song store_fan_min(struct device *dev, struct device_attribute *attr, 738792d376bSWei Song const char *buf, size_t count) 739792d376bSWei Song { 740792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 741792d376bSWei Song to_sensor_dev_attr_2(attr); 742792d376bSWei Song int index = sensor_attr->index; 743792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 744792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 745792d376bSWei Song unsigned long val; 746792d376bSWei Song 747792d376bSWei Song if (strict_strtoul(buf, 10, &val)) 748792d376bSWei Song return -EINVAL; 749792d376bSWei Song val = fan_to_reg(val); 750792d376bSWei Song 751792d376bSWei Song mutex_lock(&data->update_lock); 752792d376bSWei Song data->fan_min[index] = val; 753792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 754792d376bSWei Song val &= 0x0f; 7557eb8d508SJean Delvare if (index & 1) { 756792d376bSWei Song val <<= 4; 757792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 758792d376bSWei Song & 0x0f; 759792d376bSWei Song } else { 760792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 761792d376bSWei Song & 0xf0; 762792d376bSWei Song } 763792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 764792d376bSWei Song mutex_unlock(&data->update_lock); 765792d376bSWei Song 766792d376bSWei Song return count; 767792d376bSWei Song } 768792d376bSWei Song 769792d376bSWei Song static ssize_t 770792d376bSWei Song show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 771792d376bSWei Song { 772792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 773792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 774792d376bSWei Song to_sensor_dev_attr_2(attr); 775792d376bSWei Song int nr = sensor_attr->nr; 776792d376bSWei Song int index = sensor_attr->index; 77701879a85SJean Delvare unsigned int val; 778792d376bSWei Song 779792d376bSWei Song switch (nr) { 780792d376bSWei Song case PWM_STOP_TIME: 781792d376bSWei Song val = time_from_reg(data->pwm[index][nr]); 782792d376bSWei Song break; 78301879a85SJean Delvare case PWM_FREQ: 78401879a85SJean Delvare val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); 785792d376bSWei Song break; 786792d376bSWei Song default: 787792d376bSWei Song val = data->pwm[index][nr]; 788792d376bSWei Song break; 789792d376bSWei Song } 790792d376bSWei Song 791792d376bSWei Song return sprintf(buf, "%u\n", val); 792792d376bSWei Song } 793792d376bSWei Song 794792d376bSWei Song static ssize_t 795792d376bSWei Song store_pwm(struct device *dev, struct device_attribute *attr, 796792d376bSWei Song const char *buf, size_t count) 797792d376bSWei Song { 798792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 799792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 800792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 801792d376bSWei Song to_sensor_dev_attr_2(attr); 802792d376bSWei Song int nr = sensor_attr->nr; 803792d376bSWei Song int index = sensor_attr->index; 804792d376bSWei Song unsigned long val; 805792d376bSWei Song 806792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 807792d376bSWei Song return -EINVAL; 808792d376bSWei Song 809792d376bSWei Song mutex_lock(&data->update_lock); 810792d376bSWei Song switch (nr) { 811792d376bSWei Song case PWM_STOP_TIME: 812792d376bSWei Song val = time_to_reg(val); 813792d376bSWei Song break; 81401879a85SJean Delvare case PWM_FREQ: 81501879a85SJean Delvare val = pwm_freq_to_reg(val, data->clkin); 816792d376bSWei Song break; 817792d376bSWei Song default: 818792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 819792d376bSWei Song break; 820792d376bSWei Song } 821792d376bSWei Song w83795_write(client, W83795_REG_PWM(index, nr), val); 82201879a85SJean Delvare data->pwm[index][nr] = val; 823792d376bSWei Song mutex_unlock(&data->update_lock); 824792d376bSWei Song return count; 825792d376bSWei Song } 826792d376bSWei Song 827792d376bSWei Song static ssize_t 828792d376bSWei Song show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 829792d376bSWei Song { 830792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 831792d376bSWei Song to_sensor_dev_attr_2(attr); 832792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 833792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 834792d376bSWei Song int index = sensor_attr->index; 835792d376bSWei Song u8 tmp; 836792d376bSWei Song 837792d376bSWei Song if (1 == (data->pwm_fcms[0] & (1 << index))) { 838792d376bSWei Song tmp = 2; 839792d376bSWei Song goto out; 840792d376bSWei Song } 841792d376bSWei Song for (tmp = 0; tmp < 6; tmp++) { 842792d376bSWei Song if (data->pwm_tfmr[tmp] & (1 << index)) { 843792d376bSWei Song tmp = 3; 844792d376bSWei Song goto out; 845792d376bSWei Song } 846792d376bSWei Song } 847792d376bSWei Song if (data->pwm_fomc & (1 << index)) 848792d376bSWei Song tmp = 0; 849792d376bSWei Song else 850792d376bSWei Song tmp = 1; 851792d376bSWei Song 852792d376bSWei Song out: 853792d376bSWei Song return sprintf(buf, "%u\n", tmp); 854792d376bSWei Song } 855792d376bSWei Song 856792d376bSWei Song static ssize_t 857792d376bSWei Song store_pwm_enable(struct device *dev, struct device_attribute *attr, 858792d376bSWei Song const char *buf, size_t count) 859792d376bSWei Song { 860792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 861792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 862792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 863792d376bSWei Song to_sensor_dev_attr_2(attr); 864792d376bSWei Song int index = sensor_attr->index; 865792d376bSWei Song unsigned long val; 866792d376bSWei Song int i; 867792d376bSWei Song 868792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 869792d376bSWei Song return -EINVAL; 870792d376bSWei Song if (val > 2) 871792d376bSWei Song return -EINVAL; 872792d376bSWei Song 873792d376bSWei Song mutex_lock(&data->update_lock); 874792d376bSWei Song switch (val) { 875792d376bSWei Song case 0: 876792d376bSWei Song case 1: 877792d376bSWei Song data->pwm_fcms[0] &= ~(1 << index); 878792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 879792d376bSWei Song for (i = 0; i < 6; i++) { 880792d376bSWei Song data->pwm_tfmr[i] &= ~(1 << index); 881792d376bSWei Song w83795_write(client, W83795_REG_TFMR(i), 882792d376bSWei Song data->pwm_tfmr[i]); 883792d376bSWei Song } 884792d376bSWei Song data->pwm_fomc |= 1 << index; 885792d376bSWei Song data->pwm_fomc ^= val << index; 886792d376bSWei Song w83795_write(client, W83795_REG_FOMC, data->pwm_fomc); 887792d376bSWei Song break; 888792d376bSWei Song case 2: 889792d376bSWei Song data->pwm_fcms[0] |= (1 << index); 890792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 891792d376bSWei Song break; 892792d376bSWei Song } 893792d376bSWei Song mutex_unlock(&data->update_lock); 894792d376bSWei Song return count; 895792d376bSWei Song } 896792d376bSWei Song 897792d376bSWei Song static ssize_t 898792d376bSWei Song show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 899792d376bSWei Song { 900792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 901792d376bSWei Song to_sensor_dev_attr_2(attr); 902792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 903792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 904792d376bSWei Song int index = sensor_attr->index; 905792d376bSWei Song u8 val = index / 2; 906792d376bSWei Song u8 tmp = data->temp_src[val]; 907792d376bSWei Song 9087eb8d508SJean Delvare if (index & 1) 909792d376bSWei Song val = 4; 910792d376bSWei Song else 911792d376bSWei Song val = 0; 912792d376bSWei Song tmp >>= val; 913792d376bSWei Song tmp &= 0x0f; 914792d376bSWei Song 915792d376bSWei Song return sprintf(buf, "%u\n", tmp); 916792d376bSWei Song } 917792d376bSWei Song 918792d376bSWei Song static ssize_t 919792d376bSWei Song store_temp_src(struct device *dev, struct device_attribute *attr, 920792d376bSWei Song const char *buf, size_t count) 921792d376bSWei Song { 922792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 923792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 924792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 925792d376bSWei Song to_sensor_dev_attr_2(attr); 926792d376bSWei Song int index = sensor_attr->index; 927792d376bSWei Song unsigned long tmp; 928792d376bSWei Song u8 val = index / 2; 929792d376bSWei Song 930792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 931792d376bSWei Song return -EINVAL; 932792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 15); 933792d376bSWei Song 934792d376bSWei Song mutex_lock(&data->update_lock); 9357eb8d508SJean Delvare if (index & 1) { 936792d376bSWei Song tmp <<= 4; 937792d376bSWei Song data->temp_src[val] &= 0x0f; 938792d376bSWei Song } else { 939792d376bSWei Song data->temp_src[val] &= 0xf0; 940792d376bSWei Song } 941792d376bSWei Song data->temp_src[val] |= tmp; 942792d376bSWei Song w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 943792d376bSWei Song mutex_unlock(&data->update_lock); 944792d376bSWei Song 945792d376bSWei Song return count; 946792d376bSWei Song } 947792d376bSWei Song 948792d376bSWei Song #define TEMP_PWM_ENABLE 0 949792d376bSWei Song #define TEMP_PWM_FAN_MAP 1 950792d376bSWei Song static ssize_t 951792d376bSWei Song show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 952792d376bSWei Song char *buf) 953792d376bSWei Song { 954792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 955792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 956792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 957792d376bSWei Song to_sensor_dev_attr_2(attr); 958792d376bSWei Song int nr = sensor_attr->nr; 959792d376bSWei Song int index = sensor_attr->index; 960792d376bSWei Song u8 tmp = 0xff; 961792d376bSWei Song 962792d376bSWei Song switch (nr) { 963792d376bSWei Song case TEMP_PWM_ENABLE: 964792d376bSWei Song tmp = (data->pwm_fcms[1] >> index) & 1; 965792d376bSWei Song if (tmp) 966792d376bSWei Song tmp = 4; 967792d376bSWei Song else 968792d376bSWei Song tmp = 3; 969792d376bSWei Song break; 970792d376bSWei Song case TEMP_PWM_FAN_MAP: 971792d376bSWei Song tmp = data->pwm_tfmr[index]; 972792d376bSWei Song break; 973792d376bSWei Song } 974792d376bSWei Song 975792d376bSWei Song return sprintf(buf, "%u\n", tmp); 976792d376bSWei Song } 977792d376bSWei Song 978792d376bSWei Song static ssize_t 979792d376bSWei Song store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 980792d376bSWei Song const char *buf, size_t count) 981792d376bSWei Song { 982792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 983792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 984792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 985792d376bSWei Song to_sensor_dev_attr_2(attr); 986792d376bSWei Song int nr = sensor_attr->nr; 987792d376bSWei Song int index = sensor_attr->index; 988792d376bSWei Song unsigned long tmp; 989792d376bSWei Song 990792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 991792d376bSWei Song return -EINVAL; 992792d376bSWei Song 993792d376bSWei Song switch (nr) { 994792d376bSWei Song case TEMP_PWM_ENABLE: 995792d376bSWei Song if ((tmp != 3) && (tmp != 4)) 996792d376bSWei Song return -EINVAL; 997792d376bSWei Song tmp -= 3; 998792d376bSWei Song mutex_lock(&data->update_lock); 999792d376bSWei Song data->pwm_fcms[1] &= ~(1 << index); 1000792d376bSWei Song data->pwm_fcms[1] |= tmp << index; 1001792d376bSWei Song w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 1002792d376bSWei Song mutex_unlock(&data->update_lock); 1003792d376bSWei Song break; 1004792d376bSWei Song case TEMP_PWM_FAN_MAP: 1005792d376bSWei Song mutex_lock(&data->update_lock); 1006792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 0xff); 1007792d376bSWei Song w83795_write(client, W83795_REG_TFMR(index), tmp); 1008792d376bSWei Song data->pwm_tfmr[index] = tmp; 1009792d376bSWei Song mutex_unlock(&data->update_lock); 1010792d376bSWei Song break; 1011792d376bSWei Song } 1012792d376bSWei Song return count; 1013792d376bSWei Song } 1014792d376bSWei Song 1015792d376bSWei Song #define FANIN_TARGET 0 1016792d376bSWei Song #define FANIN_TOL 1 1017792d376bSWei Song static ssize_t 1018792d376bSWei Song show_fanin(struct device *dev, struct device_attribute *attr, char *buf) 1019792d376bSWei Song { 1020792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1021792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1022792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1023792d376bSWei Song to_sensor_dev_attr_2(attr); 1024792d376bSWei Song int nr = sensor_attr->nr; 1025792d376bSWei Song int index = sensor_attr->index; 1026792d376bSWei Song u16 tmp = 0; 1027792d376bSWei Song 1028792d376bSWei Song switch (nr) { 1029792d376bSWei Song case FANIN_TARGET: 1030792d376bSWei Song tmp = fan_from_reg(data->target_speed[index]); 1031792d376bSWei Song break; 1032792d376bSWei Song case FANIN_TOL: 1033792d376bSWei Song tmp = data->tol_speed; 1034792d376bSWei Song break; 1035792d376bSWei Song } 1036792d376bSWei Song 1037792d376bSWei Song return sprintf(buf, "%u\n", tmp); 1038792d376bSWei Song } 1039792d376bSWei Song 1040792d376bSWei Song static ssize_t 1041792d376bSWei Song store_fanin(struct device *dev, struct device_attribute *attr, 1042792d376bSWei Song const char *buf, size_t count) 1043792d376bSWei Song { 1044792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1045792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1046792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1047792d376bSWei Song to_sensor_dev_attr_2(attr); 1048792d376bSWei Song int nr = sensor_attr->nr; 1049792d376bSWei Song int index = sensor_attr->index; 1050792d376bSWei Song unsigned long val; 1051792d376bSWei Song 1052792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1053792d376bSWei Song return -EINVAL; 1054792d376bSWei Song 1055792d376bSWei Song mutex_lock(&data->update_lock); 1056792d376bSWei Song switch (nr) { 1057792d376bSWei Song case FANIN_TARGET: 1058792d376bSWei Song val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); 1059792d376bSWei Song w83795_write(client, W83795_REG_FTSH(index), (val >> 4) & 0xff); 1060792d376bSWei Song w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 1061792d376bSWei Song data->target_speed[index] = val; 1062792d376bSWei Song break; 1063792d376bSWei Song case FANIN_TOL: 1064792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3f); 1065792d376bSWei Song w83795_write(client, W83795_REG_TFTS, val); 1066792d376bSWei Song data->tol_speed = val; 1067792d376bSWei Song break; 1068792d376bSWei Song } 1069792d376bSWei Song mutex_unlock(&data->update_lock); 1070792d376bSWei Song 1071792d376bSWei Song return count; 1072792d376bSWei Song } 1073792d376bSWei Song 1074792d376bSWei Song 1075792d376bSWei Song static ssize_t 1076792d376bSWei Song show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1077792d376bSWei Song { 1078792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1079792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1080792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1081792d376bSWei Song to_sensor_dev_attr_2(attr); 1082792d376bSWei Song int nr = sensor_attr->nr; 1083792d376bSWei Song int index = sensor_attr->index; 1084792d376bSWei Song long tmp = temp_from_reg(data->pwm_temp[index][nr]); 1085792d376bSWei Song 1086792d376bSWei Song return sprintf(buf, "%ld\n", tmp); 1087792d376bSWei Song } 1088792d376bSWei Song 1089792d376bSWei Song static ssize_t 1090792d376bSWei Song store_temp_pwm(struct device *dev, struct device_attribute *attr, 1091792d376bSWei Song const char *buf, size_t count) 1092792d376bSWei Song { 1093792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1094792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1095792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1096792d376bSWei Song to_sensor_dev_attr_2(attr); 1097792d376bSWei Song int nr = sensor_attr->nr; 1098792d376bSWei Song int index = sensor_attr->index; 1099792d376bSWei Song unsigned long val; 1100792d376bSWei Song u8 tmp; 1101792d376bSWei Song 1102792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1103792d376bSWei Song return -EINVAL; 1104792d376bSWei Song val /= 1000; 1105792d376bSWei Song 1106792d376bSWei Song mutex_lock(&data->update_lock); 1107792d376bSWei Song switch (nr) { 1108792d376bSWei Song case TEMP_PWM_TTTI: 1109792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1110792d376bSWei Song w83795_write(client, W83795_REG_TTTI(index), val); 1111792d376bSWei Song break; 1112792d376bSWei Song case TEMP_PWM_CTFS: 1113792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1114792d376bSWei Song w83795_write(client, W83795_REG_CTFS(index), val); 1115792d376bSWei Song break; 1116792d376bSWei Song case TEMP_PWM_HCT: 1117792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1118792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1119792d376bSWei Song tmp &= 0x0f; 1120792d376bSWei Song tmp |= (val << 4) & 0xf0; 1121792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1122792d376bSWei Song break; 1123792d376bSWei Song case TEMP_PWM_HOT: 1124792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1125792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1126792d376bSWei Song tmp &= 0xf0; 1127792d376bSWei Song tmp |= val & 0x0f; 1128792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1129792d376bSWei Song break; 1130792d376bSWei Song } 1131792d376bSWei Song data->pwm_temp[index][nr] = val; 1132792d376bSWei Song mutex_unlock(&data->update_lock); 1133792d376bSWei Song 1134792d376bSWei Song return count; 1135792d376bSWei Song } 1136792d376bSWei Song 1137792d376bSWei Song static ssize_t 1138792d376bSWei Song show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1139792d376bSWei Song { 1140792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1141792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 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 1147792d376bSWei Song return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 1148792d376bSWei Song } 1149792d376bSWei Song 1150792d376bSWei Song static ssize_t 1151792d376bSWei Song store_sf4_pwm(struct device *dev, struct device_attribute *attr, 1152792d376bSWei Song const char *buf, size_t count) 1153792d376bSWei Song { 1154792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1155792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1156792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1157792d376bSWei Song to_sensor_dev_attr_2(attr); 1158792d376bSWei Song int nr = sensor_attr->nr; 1159792d376bSWei Song int index = sensor_attr->index; 1160792d376bSWei Song unsigned long val; 1161792d376bSWei Song 1162792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1163792d376bSWei Song return -EINVAL; 1164792d376bSWei Song 1165792d376bSWei Song mutex_lock(&data->update_lock); 1166792d376bSWei Song w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 1167792d376bSWei Song data->sf4_reg[index][SF4_PWM][nr] = val; 1168792d376bSWei Song mutex_unlock(&data->update_lock); 1169792d376bSWei Song 1170792d376bSWei Song return count; 1171792d376bSWei Song } 1172792d376bSWei Song 1173792d376bSWei Song static ssize_t 1174792d376bSWei Song show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 1175792d376bSWei Song { 1176792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1177792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1178792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1179792d376bSWei Song to_sensor_dev_attr_2(attr); 1180792d376bSWei Song int nr = sensor_attr->nr; 1181792d376bSWei Song int index = sensor_attr->index; 1182792d376bSWei Song 1183792d376bSWei Song return sprintf(buf, "%u\n", 1184792d376bSWei Song (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 1185792d376bSWei Song } 1186792d376bSWei Song 1187792d376bSWei Song static ssize_t 1188792d376bSWei Song store_sf4_temp(struct device *dev, struct device_attribute *attr, 1189792d376bSWei Song const char *buf, size_t count) 1190792d376bSWei Song { 1191792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1192792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1193792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1194792d376bSWei Song to_sensor_dev_attr_2(attr); 1195792d376bSWei Song int nr = sensor_attr->nr; 1196792d376bSWei Song int index = sensor_attr->index; 1197792d376bSWei Song unsigned long val; 1198792d376bSWei Song 1199792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1200792d376bSWei Song return -EINVAL; 1201792d376bSWei Song val /= 1000; 1202792d376bSWei Song 1203792d376bSWei Song mutex_lock(&data->update_lock); 1204792d376bSWei Song w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 1205792d376bSWei Song data->sf4_reg[index][SF4_TEMP][nr] = val; 1206792d376bSWei Song mutex_unlock(&data->update_lock); 1207792d376bSWei Song 1208792d376bSWei Song return count; 1209792d376bSWei Song } 1210792d376bSWei Song 1211792d376bSWei Song 1212792d376bSWei Song static ssize_t 1213792d376bSWei Song show_temp(struct device *dev, struct device_attribute *attr, char *buf) 1214792d376bSWei Song { 1215792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1216792d376bSWei Song to_sensor_dev_attr_2(attr); 1217792d376bSWei Song int nr = sensor_attr->nr; 1218792d376bSWei Song int index = sensor_attr->index; 1219792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1220dd127f5cSJean Delvare long temp = temp_from_reg(data->temp[index][nr]); 1221792d376bSWei Song 1222792d376bSWei Song if (TEMP_READ == nr) 1223a654b9d4SJean Delvare temp += (data->temp_read_vrlsb[index] >> 6) * 250; 1224792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1225792d376bSWei Song } 1226792d376bSWei Song 1227792d376bSWei Song static ssize_t 1228792d376bSWei Song store_temp(struct device *dev, struct device_attribute *attr, 1229792d376bSWei Song const char *buf, size_t count) 1230792d376bSWei Song { 1231792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1232792d376bSWei Song to_sensor_dev_attr_2(attr); 1233792d376bSWei Song int nr = sensor_attr->nr; 1234792d376bSWei Song int index = sensor_attr->index; 1235792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1236792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1237792d376bSWei Song long tmp; 1238792d376bSWei Song 1239792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1240792d376bSWei Song return -EINVAL; 1241792d376bSWei Song 1242792d376bSWei Song mutex_lock(&data->update_lock); 1243792d376bSWei Song data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 1244792d376bSWei Song w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 1245792d376bSWei Song mutex_unlock(&data->update_lock); 1246792d376bSWei Song return count; 1247792d376bSWei Song } 1248792d376bSWei Song 1249792d376bSWei Song 1250792d376bSWei Song static ssize_t 1251792d376bSWei Song show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) 1252792d376bSWei Song { 1253792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1254792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 125539deb699SJean Delvare int tmp; 1256792d376bSWei Song 1257792d376bSWei Song if (data->enable_dts & 2) 1258792d376bSWei Song tmp = 5; 1259792d376bSWei Song else 1260792d376bSWei Song tmp = 6; 1261792d376bSWei Song 1262792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1263792d376bSWei Song } 1264792d376bSWei Song 1265792d376bSWei Song static ssize_t 1266792d376bSWei Song show_dts(struct device *dev, struct device_attribute *attr, char *buf) 1267792d376bSWei Song { 1268792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1269792d376bSWei Song to_sensor_dev_attr_2(attr); 1270792d376bSWei Song int index = sensor_attr->index; 1271792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1272dd127f5cSJean Delvare long temp = temp_from_reg(data->dts[index]); 1273792d376bSWei Song 1274a654b9d4SJean Delvare temp += (data->dts_read_vrlsb[index] >> 6) * 250; 1275792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1276792d376bSWei Song } 1277792d376bSWei Song 1278792d376bSWei Song static ssize_t 1279792d376bSWei Song show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 1280792d376bSWei Song { 1281792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1282792d376bSWei Song to_sensor_dev_attr_2(attr); 1283792d376bSWei Song int nr = sensor_attr->nr; 1284792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1285792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1286dd127f5cSJean Delvare long temp = temp_from_reg(data->dts_ext[nr]); 1287792d376bSWei Song 1288792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1289792d376bSWei Song } 1290792d376bSWei Song 1291792d376bSWei Song static ssize_t 1292792d376bSWei Song store_dts_ext(struct device *dev, struct device_attribute *attr, 1293792d376bSWei Song const char *buf, size_t count) 1294792d376bSWei Song { 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 struct i2c_client *client = to_i2c_client(dev); 1299792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1300792d376bSWei Song long tmp; 1301792d376bSWei Song 1302792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1303792d376bSWei Song return -EINVAL; 1304792d376bSWei Song 1305792d376bSWei Song mutex_lock(&data->update_lock); 1306792d376bSWei Song data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 1307792d376bSWei Song w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 1308792d376bSWei Song mutex_unlock(&data->update_lock); 1309792d376bSWei Song return count; 1310792d376bSWei Song } 1311792d376bSWei Song 1312792d376bSWei Song 1313792d376bSWei Song static ssize_t 1314792d376bSWei Song show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 1315792d376bSWei Song { 1316792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1317792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1318792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1319792d376bSWei Song to_sensor_dev_attr_2(attr); 1320792d376bSWei Song int index = sensor_attr->index; 132139deb699SJean Delvare int tmp; 1322792d376bSWei Song 132339deb699SJean Delvare if (data->temp_mode & (1 << index)) 132439deb699SJean Delvare tmp = 3; /* Thermal diode */ 1325792d376bSWei Song else 132639deb699SJean Delvare tmp = 4; /* Thermistor */ 1327792d376bSWei Song 1328792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1329792d376bSWei Song } 1330792d376bSWei Song 133139deb699SJean Delvare /* Only for temp1-4 (temp5-6 can only be thermistor) */ 1332792d376bSWei Song static ssize_t 1333792d376bSWei Song store_temp_mode(struct device *dev, struct device_attribute *attr, 1334792d376bSWei Song const char *buf, size_t count) 1335792d376bSWei Song { 1336792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1337792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1338792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1339792d376bSWei Song to_sensor_dev_attr_2(attr); 1340792d376bSWei Song int index = sensor_attr->index; 134139deb699SJean Delvare int reg_shift; 1342792d376bSWei Song unsigned long val; 1343792d376bSWei Song u8 tmp; 1344792d376bSWei Song 1345792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1346792d376bSWei Song return -EINVAL; 1347792d376bSWei Song if ((val != 4) && (val != 3)) 1348792d376bSWei Song return -EINVAL; 1349792d376bSWei Song 1350792d376bSWei Song mutex_lock(&data->update_lock); 1351792d376bSWei Song if (val == 3) { 135239deb699SJean Delvare /* Thermal diode */ 135339deb699SJean Delvare val = 0x01; 1354792d376bSWei Song data->temp_mode |= 1 << index; 1355792d376bSWei Song } else if (val == 4) { 135639deb699SJean Delvare /* Thermistor */ 135739deb699SJean Delvare val = 0x03; 135839deb699SJean Delvare data->temp_mode &= ~(1 << index); 1359792d376bSWei Song } 1360792d376bSWei Song 136139deb699SJean Delvare reg_shift = 2 * index; 1362792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 136339deb699SJean Delvare tmp &= ~(0x03 << reg_shift); 136439deb699SJean Delvare tmp |= val << reg_shift; 1365792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 1366792d376bSWei Song 1367792d376bSWei Song mutex_unlock(&data->update_lock); 1368792d376bSWei Song return count; 1369792d376bSWei Song } 1370792d376bSWei Song 1371792d376bSWei Song 1372792d376bSWei Song /* show/store VIN */ 1373792d376bSWei Song static ssize_t 1374792d376bSWei Song show_in(struct device *dev, struct device_attribute *attr, char *buf) 1375792d376bSWei Song { 1376792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1377792d376bSWei Song to_sensor_dev_attr_2(attr); 1378792d376bSWei Song int nr = sensor_attr->nr; 1379792d376bSWei Song int index = sensor_attr->index; 1380792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1381792d376bSWei Song u16 val = data->in[index][nr]; 1382792d376bSWei Song u8 lsb_idx; 1383792d376bSWei Song 1384792d376bSWei Song switch (nr) { 1385792d376bSWei Song case IN_READ: 1386792d376bSWei Song /* calculate this value again by sensors as sensors3.conf */ 1387792d376bSWei Song if ((index >= 17) && 13886f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1389792d376bSWei Song val *= 8; 1390792d376bSWei Song break; 1391792d376bSWei Song case IN_MAX: 1392792d376bSWei Song case IN_LOW: 1393792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1394792d376bSWei Song val <<= 2; 1395792d376bSWei Song val |= (data->in_lsb[lsb_idx][nr] >> 1396792d376bSWei Song IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; 1397792d376bSWei Song if ((index >= 17) && 13986f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1399792d376bSWei Song val *= 8; 1400792d376bSWei Song break; 1401792d376bSWei Song } 1402792d376bSWei Song val = in_from_reg(index, val); 1403792d376bSWei Song 1404792d376bSWei Song return sprintf(buf, "%d\n", val); 1405792d376bSWei Song } 1406792d376bSWei Song 1407792d376bSWei Song static ssize_t 1408792d376bSWei Song store_in(struct device *dev, struct device_attribute *attr, 1409792d376bSWei Song const char *buf, size_t count) 1410792d376bSWei Song { 1411792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1412792d376bSWei Song to_sensor_dev_attr_2(attr); 1413792d376bSWei Song int nr = sensor_attr->nr; 1414792d376bSWei Song int index = sensor_attr->index; 1415792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1416792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1417792d376bSWei Song unsigned long val; 1418792d376bSWei Song u8 tmp; 1419792d376bSWei Song u8 lsb_idx; 1420792d376bSWei Song 1421792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1422792d376bSWei Song return -EINVAL; 1423792d376bSWei Song val = in_to_reg(index, val); 1424792d376bSWei Song 1425792d376bSWei Song if ((index >= 17) && 14266f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1427792d376bSWei Song val /= 8; 1428792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3FF); 1429792d376bSWei Song mutex_lock(&data->update_lock); 1430792d376bSWei Song 1431792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1432792d376bSWei Song tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 1433792d376bSWei Song tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 1434792d376bSWei Song tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 1435792d376bSWei Song w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 1436792d376bSWei Song data->in_lsb[lsb_idx][nr] = tmp; 1437792d376bSWei Song 1438792d376bSWei Song tmp = (val >> 2) & 0xff; 1439792d376bSWei Song w83795_write(client, W83795_REG_IN[index][nr], tmp); 1440792d376bSWei Song data->in[index][nr] = tmp; 1441792d376bSWei Song 1442792d376bSWei Song mutex_unlock(&data->update_lock); 1443792d376bSWei Song return count; 1444792d376bSWei Song } 1445792d376bSWei Song 1446792d376bSWei Song 1447792d376bSWei Song static ssize_t 1448792d376bSWei Song show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 1449792d376bSWei Song { 1450792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1451792d376bSWei Song to_sensor_dev_attr_2(attr); 1452792d376bSWei Song int nr = sensor_attr->nr; 1453792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1454792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1455792d376bSWei Song u16 val = data->setup_pwm[nr]; 1456792d376bSWei Song 1457792d376bSWei Song switch (nr) { 1458792d376bSWei Song case SETUP_PWM_UPTIME: 1459792d376bSWei Song case SETUP_PWM_DOWNTIME: 1460792d376bSWei Song val = time_from_reg(val); 1461792d376bSWei Song break; 1462792d376bSWei Song } 1463792d376bSWei Song 1464792d376bSWei Song return sprintf(buf, "%d\n", val); 1465792d376bSWei Song } 1466792d376bSWei Song 1467792d376bSWei Song static ssize_t 1468792d376bSWei Song store_sf_setup(struct device *dev, struct device_attribute *attr, 1469792d376bSWei Song const char *buf, size_t count) 1470792d376bSWei Song { 1471792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1472792d376bSWei Song to_sensor_dev_attr_2(attr); 1473792d376bSWei Song int nr = sensor_attr->nr; 1474792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1475792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1476792d376bSWei Song unsigned long val; 1477792d376bSWei Song 1478792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1479792d376bSWei Song return -EINVAL; 1480792d376bSWei Song 1481792d376bSWei Song switch (nr) { 1482792d376bSWei Song case SETUP_PWM_DEFAULT: 1483792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 1484792d376bSWei Song break; 1485792d376bSWei Song case SETUP_PWM_UPTIME: 1486792d376bSWei Song case SETUP_PWM_DOWNTIME: 1487792d376bSWei Song val = time_to_reg(val); 1488792d376bSWei Song if (val == 0) 1489792d376bSWei Song return -EINVAL; 1490792d376bSWei Song break; 1491792d376bSWei Song } 1492792d376bSWei Song 1493792d376bSWei Song mutex_lock(&data->update_lock); 1494792d376bSWei Song data->setup_pwm[nr] = val; 1495792d376bSWei Song w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 1496792d376bSWei Song mutex_unlock(&data->update_lock); 1497792d376bSWei Song return count; 1498792d376bSWei Song } 1499792d376bSWei Song 1500792d376bSWei Song 1501792d376bSWei Song #define NOT_USED -1 1502792d376bSWei Song 15030e256018SJean Delvare /* Don't change the attribute order, _max and _min are accessed by index 15040e256018SJean Delvare * somewhere else in the code */ 150587df0dadSJean Delvare #define SENSOR_ATTR_IN(index) { \ 1506792d376bSWei Song SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 1507792d376bSWei Song IN_READ, index), \ 1508792d376bSWei Song SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 1509792d376bSWei Song store_in, IN_MAX, index), \ 1510792d376bSWei Song SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 1511792d376bSWei Song store_in, IN_LOW, index), \ 1512792d376bSWei Song SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 1513792d376bSWei Song NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 1514792d376bSWei Song SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 1515792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 151687df0dadSJean Delvare index + ((index > 14) ? 1 : 0)) } 1517792d376bSWei Song 151887df0dadSJean Delvare #define SENSOR_ATTR_FAN(index) { \ 1519792d376bSWei Song SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 1520792d376bSWei Song NULL, FAN_INPUT, index - 1), \ 1521792d376bSWei Song SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 1522792d376bSWei Song show_fan, store_fan_min, FAN_MIN, index - 1), \ 1523792d376bSWei Song SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 1524792d376bSWei Song NULL, ALARM_STATUS, index + 31), \ 1525792d376bSWei Song SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 152687df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 1527792d376bSWei Song 1528b5f6a90aSJean Delvare #define SENSOR_ATTR_PWM(index) { \ 1529792d376bSWei Song SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 1530792d376bSWei Song store_pwm, PWM_OUTPUT, index - 1), \ 1531792d376bSWei Song SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 1532792d376bSWei Song show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 1533792d376bSWei Song SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 1534792d376bSWei Song show_pwm, store_pwm, PWM_START, index - 1), \ 1535792d376bSWei Song SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 1536792d376bSWei Song show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 153701879a85SJean Delvare SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ 153801879a85SJean Delvare show_pwm, store_pwm, PWM_FREQ, index - 1), \ 1539792d376bSWei Song SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 1540b2cc528eSJean Delvare show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 1541b2cc528eSJean Delvare SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 1542b2cc528eSJean Delvare show_fanin, store_fanin, FANIN_TARGET, index - 1) } 1543792d376bSWei Song 154487df0dadSJean Delvare #define SENSOR_ATTR_DTS(index) { \ 1545792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 1546792d376bSWei Song show_dts_mode, NULL, NOT_USED, index - 7), \ 1547792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 1548792d376bSWei Song NULL, NOT_USED, index - 7), \ 1549a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ 1550792d376bSWei Song store_dts_ext, DTS_CRIT, NOT_USED), \ 1551a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1552792d376bSWei Song show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 1553a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 1554792d376bSWei Song store_dts_ext, DTS_WARN, NOT_USED), \ 1555a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1556792d376bSWei Song show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 1557792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1558792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 1559792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 156087df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 1561792d376bSWei Song 156287df0dadSJean Delvare #define SENSOR_ATTR_TEMP(index) { \ 156339deb699SJean Delvare SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \ 1564792d376bSWei Song show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 1565792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 1566792d376bSWei Song NULL, TEMP_READ, index - 1), \ 1567a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ 1568792d376bSWei Song store_temp, TEMP_CRIT, index - 1), \ 1569a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1570792d376bSWei Song show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 1571a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 1572792d376bSWei Song store_temp, TEMP_WARN, index - 1), \ 1573a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1574792d376bSWei Song show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 1575792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1576792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, \ 1577792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1578792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 1579792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 1580792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1581792d376bSWei Song SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \ 1582792d376bSWei Song show_temp_src, store_temp_src, NOT_USED, index - 1), \ 1583792d376bSWei Song SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 1584792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1585792d376bSWei Song TEMP_PWM_ENABLE, index - 1), \ 1586792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 1587792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1588792d376bSWei Song TEMP_PWM_FAN_MAP, index - 1), \ 1589792d376bSWei Song SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 1590792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 1591a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ 1592792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 1593a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ 1594792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 1595792d376bSWei Song SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 1596792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 1597792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 1598792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 1599792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 1600792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 1601792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 1602792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 1603792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 1604792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 1605792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 1606792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 1607792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 1608792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 1609792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 1610792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 1611792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 1612792d376bSWei Song show_sf4_temp, store_sf4_temp, 0, index - 1), \ 1613792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 1614792d376bSWei Song show_sf4_temp, store_sf4_temp, 1, index - 1), \ 1615792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 1616792d376bSWei Song show_sf4_temp, store_sf4_temp, 2, index - 1), \ 1617792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 1618792d376bSWei Song show_sf4_temp, store_sf4_temp, 3, index - 1), \ 1619792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 1620792d376bSWei Song show_sf4_temp, store_sf4_temp, 4, index - 1), \ 1621792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 1622792d376bSWei Song show_sf4_temp, store_sf4_temp, 5, index - 1), \ 1623792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 162487df0dadSJean Delvare show_sf4_temp, store_sf4_temp, 6, index - 1) } 1625792d376bSWei Song 1626792d376bSWei Song 162787df0dadSJean Delvare static struct sensor_device_attribute_2 w83795_in[][5] = { 1628792d376bSWei Song SENSOR_ATTR_IN(0), 1629792d376bSWei Song SENSOR_ATTR_IN(1), 1630792d376bSWei Song SENSOR_ATTR_IN(2), 1631792d376bSWei Song SENSOR_ATTR_IN(3), 1632792d376bSWei Song SENSOR_ATTR_IN(4), 1633792d376bSWei Song SENSOR_ATTR_IN(5), 1634792d376bSWei Song SENSOR_ATTR_IN(6), 1635792d376bSWei Song SENSOR_ATTR_IN(7), 1636792d376bSWei Song SENSOR_ATTR_IN(8), 1637792d376bSWei Song SENSOR_ATTR_IN(9), 1638792d376bSWei Song SENSOR_ATTR_IN(10), 1639792d376bSWei Song SENSOR_ATTR_IN(11), 1640792d376bSWei Song SENSOR_ATTR_IN(12), 1641792d376bSWei Song SENSOR_ATTR_IN(13), 1642792d376bSWei Song SENSOR_ATTR_IN(14), 1643792d376bSWei Song SENSOR_ATTR_IN(15), 1644792d376bSWei Song SENSOR_ATTR_IN(16), 1645792d376bSWei Song SENSOR_ATTR_IN(17), 1646792d376bSWei Song SENSOR_ATTR_IN(18), 1647792d376bSWei Song SENSOR_ATTR_IN(19), 1648792d376bSWei Song SENSOR_ATTR_IN(20), 1649792d376bSWei Song }; 1650792d376bSWei Song 165186ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_fan[][4] = { 1652792d376bSWei Song SENSOR_ATTR_FAN(1), 1653792d376bSWei Song SENSOR_ATTR_FAN(2), 1654792d376bSWei Song SENSOR_ATTR_FAN(3), 1655792d376bSWei Song SENSOR_ATTR_FAN(4), 1656792d376bSWei Song SENSOR_ATTR_FAN(5), 1657792d376bSWei Song SENSOR_ATTR_FAN(6), 1658792d376bSWei Song SENSOR_ATTR_FAN(7), 1659792d376bSWei Song SENSOR_ATTR_FAN(8), 1660792d376bSWei Song SENSOR_ATTR_FAN(9), 1661792d376bSWei Song SENSOR_ATTR_FAN(10), 1662792d376bSWei Song SENSOR_ATTR_FAN(11), 1663792d376bSWei Song SENSOR_ATTR_FAN(12), 1664792d376bSWei Song SENSOR_ATTR_FAN(13), 1665792d376bSWei Song SENSOR_ATTR_FAN(14), 1666792d376bSWei Song }; 1667792d376bSWei Song 166886ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_temp[][29] = { 1669792d376bSWei Song SENSOR_ATTR_TEMP(1), 1670792d376bSWei Song SENSOR_ATTR_TEMP(2), 1671792d376bSWei Song SENSOR_ATTR_TEMP(3), 1672792d376bSWei Song SENSOR_ATTR_TEMP(4), 1673792d376bSWei Song SENSOR_ATTR_TEMP(5), 1674792d376bSWei Song SENSOR_ATTR_TEMP(6), 1675792d376bSWei Song }; 1676792d376bSWei Song 167786ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_dts[][8] = { 1678792d376bSWei Song SENSOR_ATTR_DTS(7), 1679792d376bSWei Song SENSOR_ATTR_DTS(8), 1680792d376bSWei Song SENSOR_ATTR_DTS(9), 1681792d376bSWei Song SENSOR_ATTR_DTS(10), 1682792d376bSWei Song SENSOR_ATTR_DTS(11), 1683792d376bSWei Song SENSOR_ATTR_DTS(12), 1684792d376bSWei Song SENSOR_ATTR_DTS(13), 1685792d376bSWei Song SENSOR_ATTR_DTS(14), 1686792d376bSWei Song }; 1687792d376bSWei Song 168886ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_pwm[][7] = { 1689b5f6a90aSJean Delvare SENSOR_ATTR_PWM(1), 1690b5f6a90aSJean Delvare SENSOR_ATTR_PWM(2), 1691792d376bSWei Song SENSOR_ATTR_PWM(3), 1692792d376bSWei Song SENSOR_ATTR_PWM(4), 1693792d376bSWei Song SENSOR_ATTR_PWM(5), 1694792d376bSWei Song SENSOR_ATTR_PWM(6), 1695792d376bSWei Song SENSOR_ATTR_PWM(7), 1696792d376bSWei Song SENSOR_ATTR_PWM(8), 1697792d376bSWei Song }; 1698792d376bSWei Song 169986ef4d2fSJean Delvare static const struct sensor_device_attribute_2 sda_single_files[] = { 1700792d376bSWei Song SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, 1701792d376bSWei Song store_chassis_clear, ALARM_STATUS, 46), 170202728ffeSJean Delvare SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, 170302728ffeSJean Delvare store_beep, BEEP_ENABLE, 47), 1704792d376bSWei Song SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 1705792d376bSWei Song store_fanin, FANIN_TOL, NOT_USED), 1706792d376bSWei Song SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 1707792d376bSWei Song store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 1708792d376bSWei Song SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 1709792d376bSWei Song store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 1710792d376bSWei Song SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 1711792d376bSWei Song store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 1712792d376bSWei Song }; 1713792d376bSWei Song 1714792d376bSWei Song /* 1715792d376bSWei Song * Driver interface 1716792d376bSWei Song */ 1717792d376bSWei Song 1718792d376bSWei Song static void w83795_init_client(struct i2c_client *client) 1719792d376bSWei Song { 172001879a85SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 172101879a85SJean Delvare static const u16 clkin[4] = { /* in kHz */ 172201879a85SJean Delvare 14318, 24000, 33333, 48000 172301879a85SJean Delvare }; 172480646b95SJean Delvare u8 config; 172580646b95SJean Delvare 1726792d376bSWei Song if (reset) 1727792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 0x80); 1728792d376bSWei Song 172980646b95SJean Delvare /* Start monitoring if needed */ 173080646b95SJean Delvare config = w83795_read(client, W83795_REG_CONFIG); 173180646b95SJean Delvare if (!(config & W83795_REG_CONFIG_START)) { 173280646b95SJean Delvare dev_info(&client->dev, "Enabling monitoring operations\n"); 1733792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 173480646b95SJean Delvare config | W83795_REG_CONFIG_START); 173580646b95SJean Delvare } 173601879a85SJean Delvare 173701879a85SJean Delvare data->clkin = clkin[(config >> 3) & 0x3]; 173801879a85SJean Delvare dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); 1739792d376bSWei Song } 1740792d376bSWei Song 17412be381deSJean Delvare static int w83795_get_device_id(struct i2c_client *client) 17422be381deSJean Delvare { 17432be381deSJean Delvare int device_id; 17442be381deSJean Delvare 17452be381deSJean Delvare device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 17462be381deSJean Delvare 17472be381deSJean Delvare /* Special case for rev. A chips; can't be checked first because later 17482be381deSJean Delvare revisions emulate this for compatibility */ 17492be381deSJean Delvare if (device_id < 0 || (device_id & 0xf0) != 0x50) { 17502be381deSJean Delvare int alt_id; 17512be381deSJean Delvare 17522be381deSJean Delvare alt_id = i2c_smbus_read_byte_data(client, 17532be381deSJean Delvare W83795_REG_DEVICEID_A); 17542be381deSJean Delvare if (alt_id == 0x50) 17552be381deSJean Delvare device_id = alt_id; 17562be381deSJean Delvare } 17572be381deSJean Delvare 17582be381deSJean Delvare return device_id; 17592be381deSJean Delvare } 17602be381deSJean Delvare 1761792d376bSWei Song /* Return 0 if detection is successful, -ENODEV otherwise */ 1762792d376bSWei Song static int w83795_detect(struct i2c_client *client, 1763792d376bSWei Song struct i2c_board_info *info) 1764792d376bSWei Song { 17652be381deSJean Delvare int bank, vendor_id, device_id, expected, i2c_addr, config; 1766792d376bSWei Song struct i2c_adapter *adapter = client->adapter; 1767792d376bSWei Song unsigned short address = client->addr; 1768093d1a47SJean Delvare const char *chip_name; 1769792d376bSWei Song 1770792d376bSWei Song if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1771792d376bSWei Song return -ENODEV; 1772792d376bSWei Song bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 17732be381deSJean Delvare if (bank < 0 || (bank & 0x7c)) { 17742be381deSJean Delvare dev_dbg(&adapter->dev, 17752be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17762be381deSJean Delvare address, "bank"); 17772be381deSJean Delvare return -ENODEV; 17782be381deSJean Delvare } 1779792d376bSWei Song 1780792d376bSWei Song /* Check Nuvoton vendor ID */ 17812be381deSJean Delvare vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 17822be381deSJean Delvare expected = bank & 0x80 ? 0x5c : 0xa3; 17832be381deSJean Delvare if (vendor_id != expected) { 17842be381deSJean Delvare dev_dbg(&adapter->dev, 17852be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17862be381deSJean Delvare address, "vendor id"); 17872be381deSJean Delvare return -ENODEV; 17882be381deSJean Delvare } 17892be381deSJean Delvare 17902be381deSJean Delvare /* Check device ID */ 17912be381deSJean Delvare device_id = w83795_get_device_id(client) | 17922be381deSJean Delvare (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 17932be381deSJean Delvare if ((device_id >> 4) != 0x795) { 17942be381deSJean Delvare dev_dbg(&adapter->dev, 17952be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17962be381deSJean Delvare address, "device id\n"); 1797792d376bSWei Song return -ENODEV; 1798792d376bSWei Song } 1799792d376bSWei Song 1800792d376bSWei Song /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 1801792d376bSWei Song should match */ 18022be381deSJean Delvare if ((bank & 0x07) == 0) { 18032be381deSJean Delvare i2c_addr = i2c_smbus_read_byte_data(client, 18042be381deSJean Delvare W83795_REG_I2C_ADDR); 18052be381deSJean Delvare if ((i2c_addr & 0x7f) != address) { 18062be381deSJean Delvare dev_dbg(&adapter->dev, 18072be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, " 18082be381deSJean Delvare "check %s\n", address, "i2c addr"); 1809792d376bSWei Song return -ENODEV; 1810792d376bSWei Song } 1811792d376bSWei Song } 1812792d376bSWei Song 1813093d1a47SJean Delvare /* Check 795 chip type: 795G or 795ADG 1814093d1a47SJean Delvare Usually we don't write to chips during detection, but here we don't 1815093d1a47SJean Delvare quite have the choice; hopefully it's OK, we are about to return 1816093d1a47SJean Delvare success anyway */ 1817093d1a47SJean Delvare if ((bank & 0x07) != 0) 1818093d1a47SJean Delvare i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 1819093d1a47SJean Delvare bank & ~0x07); 18202be381deSJean Delvare config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 18212be381deSJean Delvare if (config & W83795_REG_CONFIG_CONFIG48) 1822093d1a47SJean Delvare chip_name = "w83795adg"; 18232be381deSJean Delvare else 1824093d1a47SJean Delvare chip_name = "w83795g"; 1825792d376bSWei Song 1826093d1a47SJean Delvare strlcpy(info->type, chip_name, I2C_NAME_SIZE); 18272be381deSJean Delvare dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 18282be381deSJean Delvare 'A' + (device_id & 0xf), address); 1829792d376bSWei Song 1830792d376bSWei Song return 0; 1831792d376bSWei Song } 1832792d376bSWei Song 18336f3dcde9SJean Delvare static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 18346f3dcde9SJean Delvare const struct device_attribute *)) 1835892514a6SJean Delvare { 1836892514a6SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 183787df0dadSJean Delvare int err, i, j; 1838892514a6SJean Delvare 1839892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 184087df0dadSJean Delvare if (!(data->has_in & (1 << i))) 1841892514a6SJean Delvare continue; 184287df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 184387df0dadSJean Delvare err = fn(dev, &w83795_in[i][j].dev_attr); 1844892514a6SJean Delvare if (err) 1845892514a6SJean Delvare return err; 1846892514a6SJean Delvare } 184787df0dadSJean Delvare } 1848892514a6SJean Delvare 1849892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 185087df0dadSJean Delvare if (!(data->has_fan & (1 << i))) 1851892514a6SJean Delvare continue; 185287df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 185387df0dadSJean Delvare err = fn(dev, &w83795_fan[i][j].dev_attr); 1854892514a6SJean Delvare if (err) 1855892514a6SJean Delvare return err; 1856892514a6SJean Delvare } 185787df0dadSJean Delvare } 1858892514a6SJean Delvare 1859892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 18606f3dcde9SJean Delvare err = fn(dev, &sda_single_files[i].dev_attr); 1861892514a6SJean Delvare if (err) 1862892514a6SJean Delvare return err; 1863892514a6SJean Delvare } 1864892514a6SJean Delvare 1865b5f6a90aSJean Delvare for (i = 0; i < data->has_pwm; i++) { 1866b5f6a90aSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { 1867b5f6a90aSJean Delvare err = fn(dev, &w83795_pwm[i][j].dev_attr); 1868892514a6SJean Delvare if (err) 1869892514a6SJean Delvare return err; 1870892514a6SJean Delvare } 1871892514a6SJean Delvare } 1872892514a6SJean Delvare 1873892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 187487df0dadSJean Delvare if (!(data->has_temp & (1 << i))) 1875892514a6SJean Delvare continue; 187687df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { 187787df0dadSJean Delvare err = fn(dev, &w83795_temp[i][j].dev_attr); 1878892514a6SJean Delvare if (err) 1879892514a6SJean Delvare return err; 1880892514a6SJean Delvare } 188187df0dadSJean Delvare } 1882892514a6SJean Delvare 1883892514a6SJean Delvare if (data->enable_dts != 0) { 1884892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 188587df0dadSJean Delvare if (!(data->has_dts & (1 << i))) 1886892514a6SJean Delvare continue; 188787df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 188887df0dadSJean Delvare err = fn(dev, &w83795_dts[i][j].dev_attr); 1889892514a6SJean Delvare if (err) 1890892514a6SJean Delvare return err; 1891892514a6SJean Delvare } 1892892514a6SJean Delvare } 189387df0dadSJean Delvare } 1894892514a6SJean Delvare 1895892514a6SJean Delvare return 0; 1896892514a6SJean Delvare } 1897892514a6SJean Delvare 18986f3dcde9SJean Delvare /* We need a wrapper that fits in w83795_handle_files */ 18996f3dcde9SJean Delvare static int device_remove_file_wrapper(struct device *dev, 19006f3dcde9SJean Delvare const struct device_attribute *attr) 19012fa09878SJean Delvare { 19026f3dcde9SJean Delvare device_remove_file(dev, attr); 19036f3dcde9SJean Delvare return 0; 19042fa09878SJean Delvare } 19052fa09878SJean Delvare 19060e256018SJean Delvare static void w83795_check_dynamic_in_limits(struct i2c_client *client) 19070e256018SJean Delvare { 19080e256018SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 19090e256018SJean Delvare u8 vid_ctl; 19100e256018SJean Delvare int i, err_max, err_min; 19110e256018SJean Delvare 19120e256018SJean Delvare vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); 19130e256018SJean Delvare 19140e256018SJean Delvare /* Return immediately if VRM isn't configured */ 19150e256018SJean Delvare if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) 19160e256018SJean Delvare return; 19170e256018SJean Delvare 19180e256018SJean Delvare data->has_dyn_in = (vid_ctl >> 3) & 0x07; 19190e256018SJean Delvare for (i = 0; i < 2; i++) { 19200e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 19210e256018SJean Delvare continue; 19220e256018SJean Delvare 19230e256018SJean Delvare /* Voltage limits in dynamic mode, switch to read-only */ 19240e256018SJean Delvare err_max = sysfs_chmod_file(&client->dev.kobj, 19250e256018SJean Delvare &w83795_in[i][2].dev_attr.attr, 19260e256018SJean Delvare S_IRUGO); 19270e256018SJean Delvare err_min = sysfs_chmod_file(&client->dev.kobj, 19280e256018SJean Delvare &w83795_in[i][3].dev_attr.attr, 19290e256018SJean Delvare S_IRUGO); 19300e256018SJean Delvare if (err_max || err_min) 19310e256018SJean Delvare dev_warn(&client->dev, "Failed to set in%d limits " 19320e256018SJean Delvare "read-only (%d, %d)\n", i, err_max, err_min); 19330e256018SJean Delvare else 19340e256018SJean Delvare dev_info(&client->dev, "in%d limits set dynamically " 19350e256018SJean Delvare "from VID\n", i); 19360e256018SJean Delvare } 19370e256018SJean Delvare } 19380e256018SJean Delvare 193971caf46fSJean Delvare /* Check pins that can be used for either temperature or voltage monitoring */ 194071caf46fSJean Delvare static void w83795_apply_temp_config(struct w83795_data *data, u8 config, 194171caf46fSJean Delvare int temp_chan, int in_chan) 194271caf46fSJean Delvare { 194371caf46fSJean Delvare /* config is a 2-bit value */ 194471caf46fSJean Delvare switch (config) { 194571caf46fSJean Delvare case 0x2: /* Voltage monitoring */ 194671caf46fSJean Delvare data->has_in |= 1 << in_chan; 194771caf46fSJean Delvare break; 194871caf46fSJean Delvare case 0x1: /* Thermal diode */ 194971caf46fSJean Delvare if (temp_chan >= 4) 195071caf46fSJean Delvare break; 195171caf46fSJean Delvare data->temp_mode |= 1 << temp_chan; 195271caf46fSJean Delvare /* fall through */ 195371caf46fSJean Delvare case 0x3: /* Thermistor */ 195471caf46fSJean Delvare data->has_temp |= 1 << temp_chan; 195571caf46fSJean Delvare break; 195671caf46fSJean Delvare } 195771caf46fSJean Delvare } 195871caf46fSJean Delvare 1959792d376bSWei Song static int w83795_probe(struct i2c_client *client, 1960792d376bSWei Song const struct i2c_device_id *id) 1961792d376bSWei Song { 1962792d376bSWei Song int i; 1963792d376bSWei Song u8 tmp; 1964792d376bSWei Song struct device *dev = &client->dev; 1965792d376bSWei Song struct w83795_data *data; 196671caf46fSJean Delvare int err; 1967792d376bSWei Song 1968792d376bSWei Song data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); 1969792d376bSWei Song if (!data) { 1970792d376bSWei Song err = -ENOMEM; 1971792d376bSWei Song goto exit; 1972792d376bSWei Song } 1973792d376bSWei Song 1974792d376bSWei Song i2c_set_clientdata(client, data); 1975093d1a47SJean Delvare data->chip_type = id->driver_data; 1976792d376bSWei Song data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 1977792d376bSWei Song mutex_init(&data->update_lock); 1978792d376bSWei Song 1979792d376bSWei Song /* Initialize the chip */ 1980792d376bSWei Song w83795_init_client(client); 1981792d376bSWei Song 198271caf46fSJean Delvare /* Check which voltages and fans are present */ 198371caf46fSJean Delvare data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) 198471caf46fSJean Delvare | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); 198571caf46fSJean Delvare data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) 198671caf46fSJean Delvare | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); 1987792d376bSWei Song 198871caf46fSJean Delvare /* Check which analog temperatures and extra voltages are present */ 1989792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 1990792d376bSWei Song if (tmp & 0x20) 1991792d376bSWei Song data->enable_dts = 1; 199271caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); 199371caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 4, 15); 1994792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 199571caf46fSJean Delvare w83795_apply_temp_config(data, tmp >> 6, 3, 20); 199671caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); 199771caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); 199871caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 0, 17); 1999792d376bSWei Song 2000792d376bSWei Song /* Check DTS enable status */ 200171caf46fSJean Delvare if (data->enable_dts) { 2002792d376bSWei Song if (1 & w83795_read(client, W83795_REG_DTSC)) 2003792d376bSWei Song data->enable_dts |= 2; 2004792d376bSWei Song data->has_dts = w83795_read(client, W83795_REG_DTSE); 2005792d376bSWei Song } 2006792d376bSWei Song 200754891a3cSJean Delvare /* Report PECI Tbase values */ 200854891a3cSJean Delvare if (data->enable_dts == 1) { 200954891a3cSJean Delvare for (i = 0; i < 8; i++) { 201054891a3cSJean Delvare if (!(data->has_dts & (1 << i))) 201154891a3cSJean Delvare continue; 201254891a3cSJean Delvare tmp = w83795_read(client, W83795_REG_PECI_TBASE(i)); 201354891a3cSJean Delvare dev_info(&client->dev, 201454891a3cSJean Delvare "PECI agent %d Tbase temperature: %u\n", 201554891a3cSJean Delvare i + 1, (unsigned int)tmp & 0x7f); 201654891a3cSJean Delvare } 201754891a3cSJean Delvare } 201854891a3cSJean Delvare 2019792d376bSWei Song data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 20200d7237bfSJean Delvare w83795_update_limits(client); 2021792d376bSWei Song 2022792d376bSWei Song /* pwm and smart fan */ 2023792d376bSWei Song if (data->chip_type == w83795g) 2024792d376bSWei Song data->has_pwm = 8; 2025792d376bSWei Song else 2026792d376bSWei Song data->has_pwm = 2; 20270d7237bfSJean Delvare w83795_update_pwm_config(client); 2028792d376bSWei Song 20296f3dcde9SJean Delvare err = w83795_handle_files(dev, device_create_file); 2030792d376bSWei Song if (err) 2031792d376bSWei Song goto exit_remove; 2032792d376bSWei Song 20330e256018SJean Delvare if (data->chip_type == w83795g) 20340e256018SJean Delvare w83795_check_dynamic_in_limits(client); 20350e256018SJean Delvare 2036792d376bSWei Song data->hwmon_dev = hwmon_device_register(dev); 2037792d376bSWei Song if (IS_ERR(data->hwmon_dev)) { 2038792d376bSWei Song err = PTR_ERR(data->hwmon_dev); 2039792d376bSWei Song goto exit_remove; 2040792d376bSWei Song } 2041792d376bSWei Song 2042792d376bSWei Song return 0; 2043792d376bSWei Song 2044792d376bSWei Song exit_remove: 20456f3dcde9SJean Delvare w83795_handle_files(dev, device_remove_file_wrapper); 2046792d376bSWei Song kfree(data); 2047792d376bSWei Song exit: 2048792d376bSWei Song return err; 2049792d376bSWei Song } 2050792d376bSWei Song 2051792d376bSWei Song static int w83795_remove(struct i2c_client *client) 2052792d376bSWei Song { 2053792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 2054792d376bSWei Song 2055792d376bSWei Song hwmon_device_unregister(data->hwmon_dev); 20566f3dcde9SJean Delvare w83795_handle_files(&client->dev, device_remove_file_wrapper); 2057792d376bSWei Song kfree(data); 2058792d376bSWei Song 2059792d376bSWei Song return 0; 2060792d376bSWei Song } 2061792d376bSWei Song 2062792d376bSWei Song 2063792d376bSWei Song static const struct i2c_device_id w83795_id[] = { 2064093d1a47SJean Delvare { "w83795g", w83795g }, 2065093d1a47SJean Delvare { "w83795adg", w83795adg }, 2066792d376bSWei Song { } 2067792d376bSWei Song }; 2068792d376bSWei Song MODULE_DEVICE_TABLE(i2c, w83795_id); 2069792d376bSWei Song 2070792d376bSWei Song static struct i2c_driver w83795_driver = { 2071792d376bSWei Song .driver = { 2072792d376bSWei Song .name = "w83795", 2073792d376bSWei Song }, 2074792d376bSWei Song .probe = w83795_probe, 2075792d376bSWei Song .remove = w83795_remove, 2076792d376bSWei Song .id_table = w83795_id, 2077792d376bSWei Song 2078792d376bSWei Song .class = I2C_CLASS_HWMON, 2079792d376bSWei Song .detect = w83795_detect, 2080792d376bSWei Song .address_list = normal_i2c, 2081792d376bSWei Song }; 2082792d376bSWei Song 2083792d376bSWei Song static int __init sensors_w83795_init(void) 2084792d376bSWei Song { 2085792d376bSWei Song return i2c_add_driver(&w83795_driver); 2086792d376bSWei Song } 2087792d376bSWei Song 2088792d376bSWei Song static void __exit sensors_w83795_exit(void) 2089792d376bSWei Song { 2090792d376bSWei Song i2c_del_driver(&w83795_driver); 2091792d376bSWei Song } 2092792d376bSWei Song 2093792d376bSWei Song MODULE_AUTHOR("Wei Song"); 2094315bacfdSJean Delvare MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 2095792d376bSWei Song MODULE_LICENSE("GPL"); 2096792d376bSWei Song 2097792d376bSWei Song module_init(sensors_w83795_init); 2098792d376bSWei Song module_exit(sensors_w83795_exit); 2099