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 181792d376bSWei Song #define PWM_START 1 182792d376bSWei Song #define PWM_NONSTOP 2 183792d376bSWei Song #define PWM_STOP_TIME 3 18401879a85SJean Delvare #define PWM_FREQ 4 185792d376bSWei Song #define W83795_REG_PWM(index, nr) \ 186792d376bSWei Song (((nr) == 0 ? 0x210 : \ 187792d376bSWei Song (nr) == 1 ? 0x220 : \ 188792d376bSWei Song (nr) == 2 ? 0x228 : \ 189792d376bSWei Song (nr) == 3 ? 0x230 : 0x218) + (index)) 190792d376bSWei Song 191792d376bSWei Song #define W83795_REG_FTSH(index) (0x240 + (index) * 2) 192792d376bSWei Song #define W83795_REG_FTSL(index) (0x241 + (index) * 2) 193792d376bSWei Song #define W83795_REG_TFTS 0x250 194792d376bSWei Song 195792d376bSWei Song #define TEMP_PWM_TTTI 0 196792d376bSWei Song #define TEMP_PWM_CTFS 1 197792d376bSWei Song #define TEMP_PWM_HCT 2 198792d376bSWei Song #define TEMP_PWM_HOT 3 199792d376bSWei Song #define W83795_REG_TTTI(index) (0x260 + (index)) 200792d376bSWei Song #define W83795_REG_CTFS(index) (0x268 + (index)) 201792d376bSWei Song #define W83795_REG_HT(index) (0x270 + (index)) 202792d376bSWei Song 203792d376bSWei Song #define SF4_TEMP 0 204792d376bSWei Song #define SF4_PWM 1 205792d376bSWei Song #define W83795_REG_SF4_TEMP(temp_num, index) \ 206792d376bSWei Song (0x280 + 0x10 * (temp_num) + (index)) 207792d376bSWei Song #define W83795_REG_SF4_PWM(temp_num, index) \ 208792d376bSWei Song (0x288 + 0x10 * (temp_num) + (index)) 209792d376bSWei Song 210792d376bSWei Song #define W83795_REG_DTSC 0x301 211792d376bSWei Song #define W83795_REG_DTSE 0x302 212792d376bSWei Song #define W83795_REG_DTS(index) (0x26 + (index)) 21354891a3cSJean Delvare #define W83795_REG_PECI_TBASE(index) (0x320 + (index)) 214792d376bSWei Song 215792d376bSWei Song #define DTS_CRIT 0 216792d376bSWei Song #define DTS_CRIT_HYST 1 217792d376bSWei Song #define DTS_WARN 2 218792d376bSWei Song #define DTS_WARN_HYST 3 219792d376bSWei Song #define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 220792d376bSWei Song 221792d376bSWei Song #define SETUP_PWM_DEFAULT 0 222792d376bSWei Song #define SETUP_PWM_UPTIME 1 223792d376bSWei Song #define SETUP_PWM_DOWNTIME 2 224792d376bSWei Song #define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 225792d376bSWei Song 226792d376bSWei Song static inline u16 in_from_reg(u8 index, u16 val) 227792d376bSWei Song { 22849c7347aSJean Delvare /* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */ 22949c7347aSJean Delvare if (index >= 12 && index <= 14) 230792d376bSWei Song return val * 6; 231792d376bSWei Song else 232792d376bSWei Song return val * 2; 233792d376bSWei Song } 234792d376bSWei Song 235792d376bSWei Song static inline u16 in_to_reg(u8 index, u16 val) 236792d376bSWei Song { 23749c7347aSJean Delvare if (index >= 12 && index <= 14) 238792d376bSWei Song return val / 6; 239792d376bSWei Song else 240792d376bSWei Song return val / 2; 241792d376bSWei Song } 242792d376bSWei Song 243792d376bSWei Song static inline unsigned long fan_from_reg(u16 val) 244792d376bSWei Song { 2456c82b2f3SJean Delvare if ((val == 0xfff) || (val == 0)) 246792d376bSWei Song return 0; 247792d376bSWei Song return 1350000UL / val; 248792d376bSWei Song } 249792d376bSWei Song 250792d376bSWei Song static inline u16 fan_to_reg(long rpm) 251792d376bSWei Song { 252792d376bSWei Song if (rpm <= 0) 253792d376bSWei Song return 0x0fff; 254792d376bSWei Song return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 255792d376bSWei Song } 256792d376bSWei Song 257792d376bSWei Song static inline unsigned long time_from_reg(u8 reg) 258792d376bSWei Song { 259792d376bSWei Song return reg * 100; 260792d376bSWei Song } 261792d376bSWei Song 262792d376bSWei Song static inline u8 time_to_reg(unsigned long val) 263792d376bSWei Song { 264792d376bSWei Song return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); 265792d376bSWei Song } 266792d376bSWei Song 267792d376bSWei Song static inline long temp_from_reg(s8 reg) 268792d376bSWei Song { 269792d376bSWei Song return reg * 1000; 270792d376bSWei Song } 271792d376bSWei Song 272792d376bSWei Song static inline s8 temp_to_reg(long val, s8 min, s8 max) 273792d376bSWei Song { 274dd127f5cSJean Delvare return SENSORS_LIMIT(val / 1000, min, max); 275792d376bSWei Song } 276792d376bSWei Song 27701879a85SJean Delvare static const u16 pwm_freq_cksel0[16] = { 27801879a85SJean Delvare 1024, 512, 341, 256, 205, 171, 146, 128, 27901879a85SJean Delvare 85, 64, 32, 16, 8, 4, 2, 1 28001879a85SJean Delvare }; 28101879a85SJean Delvare 28201879a85SJean Delvare static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) 28301879a85SJean Delvare { 28401879a85SJean Delvare unsigned long base_clock; 28501879a85SJean Delvare 28601879a85SJean Delvare if (reg & 0x80) { 28701879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 28801879a85SJean Delvare return base_clock / ((reg & 0x7f) + 1); 28901879a85SJean Delvare } else 29001879a85SJean Delvare return pwm_freq_cksel0[reg & 0x0f]; 29101879a85SJean Delvare } 29201879a85SJean Delvare 29301879a85SJean Delvare static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) 29401879a85SJean Delvare { 29501879a85SJean Delvare unsigned long base_clock; 29601879a85SJean Delvare u8 reg0, reg1; 29701879a85SJean Delvare unsigned long best0, best1; 29801879a85SJean Delvare 29901879a85SJean Delvare /* Best fit for cksel = 0 */ 30001879a85SJean Delvare for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { 30101879a85SJean Delvare if (val > (pwm_freq_cksel0[reg0] + 30201879a85SJean Delvare pwm_freq_cksel0[reg0 + 1]) / 2) 30301879a85SJean Delvare break; 30401879a85SJean Delvare } 30501879a85SJean Delvare if (val < 375) /* cksel = 1 can't beat this */ 30601879a85SJean Delvare return reg0; 30701879a85SJean Delvare best0 = pwm_freq_cksel0[reg0]; 30801879a85SJean Delvare 30901879a85SJean Delvare /* Best fit for cksel = 1 */ 31001879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 31101879a85SJean Delvare reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); 31201879a85SJean Delvare best1 = base_clock / reg1; 31301879a85SJean Delvare reg1 = 0x80 | (reg1 - 1); 31401879a85SJean Delvare 31501879a85SJean Delvare /* Choose the closest one */ 31601879a85SJean Delvare if (abs(val - best0) > abs(val - best1)) 31701879a85SJean Delvare return reg1; 31801879a85SJean Delvare else 31901879a85SJean Delvare return reg0; 32001879a85SJean Delvare } 321792d376bSWei Song 322792d376bSWei Song enum chip_types {w83795g, w83795adg}; 323792d376bSWei Song 324792d376bSWei Song struct w83795_data { 325792d376bSWei Song struct device *hwmon_dev; 326792d376bSWei Song struct mutex update_lock; 327792d376bSWei Song unsigned long last_updated; /* In jiffies */ 328792d376bSWei Song enum chip_types chip_type; 329792d376bSWei Song 330792d376bSWei Song u8 bank; 331792d376bSWei Song 332792d376bSWei Song u32 has_in; /* Enable monitor VIN or not */ 3330e256018SJean Delvare u8 has_dyn_in; /* Only in2-0 can have this */ 334792d376bSWei Song u16 in[21][3]; /* Register value, read/high/low */ 335792d376bSWei Song u8 in_lsb[10][3]; /* LSB Register value, high/low */ 336792d376bSWei Song u8 has_gain; /* has gain: in17-20 * 8 */ 337792d376bSWei Song 338792d376bSWei Song u16 has_fan; /* Enable fan14-1 or not */ 339792d376bSWei Song u16 fan[14]; /* Register value combine */ 340792d376bSWei Song u16 fan_min[14]; /* Register value combine */ 341792d376bSWei Song 342792d376bSWei Song u8 has_temp; /* Enable monitor temp6-1 or not */ 343dd127f5cSJean Delvare s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 344792d376bSWei Song u8 temp_read_vrlsb[6]; 34539deb699SJean Delvare u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */ 346792d376bSWei Song u8 temp_src[3]; /* Register value */ 347792d376bSWei Song 348792d376bSWei Song u8 enable_dts; /* Enable PECI and SB-TSI, 349792d376bSWei Song * bit 0: =1 enable, =0 disable, 350792d376bSWei Song * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ 351792d376bSWei Song u8 has_dts; /* Enable monitor DTS temp */ 352dd127f5cSJean Delvare s8 dts[8]; /* Register value */ 353792d376bSWei Song u8 dts_read_vrlsb[8]; /* Register value */ 354dd127f5cSJean Delvare s8 dts_ext[4]; /* Register value */ 355792d376bSWei Song 356792d376bSWei Song u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, 357792d376bSWei Song * no config register, only affected by chip 358792d376bSWei Song * type */ 359792d376bSWei Song u8 pwm[8][5]; /* Register value, output, start, non stop, stop 36001879a85SJean Delvare * time, freq */ 36101879a85SJean Delvare u16 clkin; /* CLKIN frequency in kHz */ 362792d376bSWei Song u8 pwm_fcms[2]; /* Register value */ 363792d376bSWei Song u8 pwm_tfmr[6]; /* Register value */ 364792d376bSWei Song u8 pwm_fomc; /* Register value */ 365792d376bSWei Song 366792d376bSWei Song u16 target_speed[8]; /* Register value, target speed for speed 367792d376bSWei Song * cruise */ 368792d376bSWei Song u8 tol_speed; /* tolerance of target speed */ 369792d376bSWei Song u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 370792d376bSWei Song u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 371792d376bSWei Song 372792d376bSWei Song u8 setup_pwm[3]; /* Register value */ 373792d376bSWei Song 374792d376bSWei Song u8 alarms[6]; /* Register value */ 375792d376bSWei Song u8 beeps[6]; /* Register value */ 376792d376bSWei Song 377792d376bSWei Song char valid; 378792d376bSWei Song }; 379792d376bSWei Song 380792d376bSWei Song /* 381792d376bSWei Song * Hardware access 382b2469f42SJean Delvare * We assume that nobdody can change the bank outside the driver. 383792d376bSWei Song */ 384792d376bSWei Song 385b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 386b2469f42SJean Delvare static int w83795_set_bank(struct i2c_client *client, u8 bank) 387792d376bSWei Song { 388792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 389b2469f42SJean Delvare int err; 390792d376bSWei Song 391b2469f42SJean Delvare /* If the same bank is already set, nothing to do */ 392b2469f42SJean Delvare if ((data->bank & 0x07) == bank) 393b2469f42SJean Delvare return 0; 394b2469f42SJean Delvare 395b2469f42SJean Delvare /* Change to new bank, preserve all other bits */ 396b2469f42SJean Delvare bank |= data->bank & ~0x07; 397b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 398b2469f42SJean Delvare if (err < 0) { 399792d376bSWei Song dev_err(&client->dev, 400b2469f42SJean Delvare "Failed to set bank to %d, err %d\n", 401b2469f42SJean Delvare (int)bank, err); 402b2469f42SJean Delvare return err; 403792d376bSWei Song } 404b2469f42SJean Delvare data->bank = bank; 405b2469f42SJean Delvare 406b2469f42SJean Delvare return 0; 407792d376bSWei Song } 408b2469f42SJean Delvare 409b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 410b2469f42SJean Delvare static u8 w83795_read(struct i2c_client *client, u16 reg) 411b2469f42SJean Delvare { 412b2469f42SJean Delvare int err; 413b2469f42SJean Delvare 414b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 415b2469f42SJean Delvare if (err < 0) 416b2469f42SJean Delvare return 0x00; /* Arbitrary */ 417b2469f42SJean Delvare 418b2469f42SJean Delvare err = i2c_smbus_read_byte_data(client, reg & 0xff); 419b2469f42SJean Delvare if (err < 0) { 420b2469f42SJean Delvare dev_err(&client->dev, 421b2469f42SJean Delvare "Failed to read from register 0x%03x, err %d\n", 422b2469f42SJean Delvare (int)reg, err); 423b2469f42SJean Delvare return 0x00; /* Arbitrary */ 424b2469f42SJean Delvare } 425b2469f42SJean Delvare return err; 426792d376bSWei Song } 427792d376bSWei Song 428792d376bSWei Song /* Must be called with data->update_lock held, except during initialization */ 429792d376bSWei Song static int w83795_write(struct i2c_client *client, u16 reg, u8 value) 430792d376bSWei Song { 431b2469f42SJean Delvare int err; 432792d376bSWei Song 433b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 434b2469f42SJean Delvare if (err < 0) 435b2469f42SJean Delvare return err; 436b2469f42SJean Delvare 437b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 438b2469f42SJean Delvare if (err < 0) 439792d376bSWei Song dev_err(&client->dev, 440b2469f42SJean Delvare "Failed to write to register 0x%03x, err %d\n", 441b2469f42SJean Delvare (int)reg, err); 442b2469f42SJean Delvare return err; 443792d376bSWei Song } 444792d376bSWei Song 445792d376bSWei Song static struct w83795_data *w83795_update_device(struct device *dev) 446792d376bSWei Song { 447792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 448792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 449792d376bSWei Song u16 tmp; 450792d376bSWei Song int i; 451792d376bSWei Song 452792d376bSWei Song mutex_lock(&data->update_lock); 453792d376bSWei Song 454792d376bSWei Song if (!(time_after(jiffies, data->last_updated + HZ * 2) 455792d376bSWei Song || !data->valid)) 456792d376bSWei Song goto END; 457792d376bSWei Song 458792d376bSWei Song /* Update the voltages value */ 459792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 460792d376bSWei Song if (!(data->has_in & (1 << i))) 461792d376bSWei Song continue; 462792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 463a654b9d4SJean Delvare tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; 464792d376bSWei Song data->in[i][IN_READ] = tmp; 465792d376bSWei Song } 466792d376bSWei Song 4670e256018SJean Delvare /* in0-2 can have dynamic limits (W83795G only) */ 4680e256018SJean Delvare if (data->has_dyn_in) { 4690e256018SJean Delvare u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); 4700e256018SJean Delvare u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); 4710e256018SJean Delvare 4720e256018SJean Delvare for (i = 0; i < 3; i++) { 4730e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 4740e256018SJean Delvare continue; 4750e256018SJean Delvare data->in[i][IN_MAX] = 4760e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 4770e256018SJean Delvare data->in[i][IN_LOW] = 4780e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 4790e256018SJean Delvare data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; 4800e256018SJean Delvare data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; 4810e256018SJean Delvare } 4820e256018SJean Delvare } 4830e256018SJean Delvare 484792d376bSWei Song /* Update fan */ 485792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 486792d376bSWei Song if (!(data->has_fan & (1 << i))) 487792d376bSWei Song continue; 488792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 489792d376bSWei Song data->fan[i] |= 4906c82b2f3SJean Delvare (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; 491792d376bSWei Song } 492792d376bSWei Song 493792d376bSWei Song /* Update temperature */ 494792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 495792d376bSWei Song data->temp[i][TEMP_READ] = 496792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 497792d376bSWei Song data->temp_read_vrlsb[i] = 498792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 499792d376bSWei Song } 500792d376bSWei Song 501792d376bSWei Song /* Update dts temperature */ 502792d376bSWei Song if (data->enable_dts != 0) { 503792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 504792d376bSWei Song if (!(data->has_dts & (1 << i))) 505792d376bSWei Song continue; 506792d376bSWei Song data->dts[i] = 507792d376bSWei Song w83795_read(client, W83795_REG_DTS(i)); 508792d376bSWei Song data->dts_read_vrlsb[i] = 509792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 510792d376bSWei Song } 511792d376bSWei Song } 512792d376bSWei Song 513792d376bSWei Song /* Update pwm output */ 514792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 515792d376bSWei Song data->pwm[i][PWM_OUTPUT] = 516792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 517792d376bSWei Song } 518792d376bSWei Song 519792d376bSWei Song /* update alarm */ 520cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->alarms); i++) 521792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 522792d376bSWei Song 523792d376bSWei Song data->last_updated = jiffies; 524792d376bSWei Song data->valid = 1; 525792d376bSWei Song 526792d376bSWei Song END: 527792d376bSWei Song mutex_unlock(&data->update_lock); 528792d376bSWei Song return data; 529792d376bSWei Song } 530792d376bSWei Song 531792d376bSWei Song /* 532792d376bSWei Song * Sysfs attributes 533792d376bSWei Song */ 534792d376bSWei Song 535792d376bSWei Song #define ALARM_STATUS 0 536792d376bSWei Song #define BEEP_ENABLE 1 537792d376bSWei Song static ssize_t 538792d376bSWei Song show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 539792d376bSWei Song { 540792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 541792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 542792d376bSWei Song to_sensor_dev_attr_2(attr); 543792d376bSWei Song int nr = sensor_attr->nr; 544792d376bSWei Song int index = sensor_attr->index >> 3; 545792d376bSWei Song int bit = sensor_attr->index & 0x07; 546792d376bSWei Song u8 val; 547792d376bSWei Song 548792d376bSWei Song if (ALARM_STATUS == nr) { 549792d376bSWei Song val = (data->alarms[index] >> (bit)) & 1; 550792d376bSWei Song } else { /* BEEP_ENABLE */ 551792d376bSWei Song val = (data->beeps[index] >> (bit)) & 1; 552792d376bSWei Song } 553792d376bSWei Song 554792d376bSWei Song return sprintf(buf, "%u\n", val); 555792d376bSWei Song } 556792d376bSWei Song 557792d376bSWei Song static ssize_t 558792d376bSWei Song store_beep(struct device *dev, struct device_attribute *attr, 559792d376bSWei Song const char *buf, size_t count) 560792d376bSWei Song { 561792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 562792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 563792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 564792d376bSWei Song to_sensor_dev_attr_2(attr); 565792d376bSWei Song int index = sensor_attr->index >> 3; 566792d376bSWei Song int shift = sensor_attr->index & 0x07; 567792d376bSWei Song u8 beep_bit = 1 << shift; 568792d376bSWei Song unsigned long val; 569792d376bSWei Song 570792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 571792d376bSWei Song return -EINVAL; 572792d376bSWei Song if (val != 0 && val != 1) 573792d376bSWei Song return -EINVAL; 574792d376bSWei Song 575792d376bSWei Song mutex_lock(&data->update_lock); 576792d376bSWei Song data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 577792d376bSWei Song data->beeps[index] &= ~beep_bit; 578792d376bSWei Song data->beeps[index] |= val << shift; 579792d376bSWei Song w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 580792d376bSWei Song mutex_unlock(&data->update_lock); 581792d376bSWei Song 582792d376bSWei Song return count; 583792d376bSWei Song } 584792d376bSWei Song 585792d376bSWei Song /* Write any value to clear chassis alarm */ 586792d376bSWei Song static ssize_t 587792d376bSWei Song store_chassis_clear(struct device *dev, 588792d376bSWei Song struct device_attribute *attr, const char *buf, 589792d376bSWei Song size_t count) 590792d376bSWei Song { 591792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 592792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 593792d376bSWei Song u8 val; 594792d376bSWei Song 595792d376bSWei Song mutex_lock(&data->update_lock); 596792d376bSWei Song val = w83795_read(client, W83795_REG_CLR_CHASSIS); 597792d376bSWei Song val |= 0x80; 598792d376bSWei Song w83795_write(client, W83795_REG_CLR_CHASSIS, val); 599792d376bSWei Song mutex_unlock(&data->update_lock); 600792d376bSWei Song return count; 601792d376bSWei Song } 602792d376bSWei Song 603792d376bSWei Song #define FAN_INPUT 0 604792d376bSWei Song #define FAN_MIN 1 605792d376bSWei Song static ssize_t 606792d376bSWei Song show_fan(struct device *dev, struct device_attribute *attr, char *buf) 607792d376bSWei Song { 608792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 609792d376bSWei Song to_sensor_dev_attr_2(attr); 610792d376bSWei Song int nr = sensor_attr->nr; 611792d376bSWei Song int index = sensor_attr->index; 612792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 613792d376bSWei Song u16 val; 614792d376bSWei Song 615792d376bSWei Song if (FAN_INPUT == nr) 616792d376bSWei Song val = data->fan[index] & 0x0fff; 617792d376bSWei Song else 618792d376bSWei Song val = data->fan_min[index] & 0x0fff; 619792d376bSWei Song 620792d376bSWei Song return sprintf(buf, "%lu\n", fan_from_reg(val)); 621792d376bSWei Song } 622792d376bSWei Song 623792d376bSWei Song static ssize_t 624792d376bSWei Song store_fan_min(struct device *dev, struct device_attribute *attr, 625792d376bSWei Song const char *buf, size_t count) 626792d376bSWei Song { 627792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 628792d376bSWei Song to_sensor_dev_attr_2(attr); 629792d376bSWei Song int index = sensor_attr->index; 630792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 631792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 632792d376bSWei Song unsigned long val; 633792d376bSWei Song 634792d376bSWei Song if (strict_strtoul(buf, 10, &val)) 635792d376bSWei Song return -EINVAL; 636792d376bSWei Song val = fan_to_reg(val); 637792d376bSWei Song 638792d376bSWei Song mutex_lock(&data->update_lock); 639792d376bSWei Song data->fan_min[index] = val; 640792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 641792d376bSWei Song val &= 0x0f; 6427eb8d508SJean Delvare if (index & 1) { 643792d376bSWei Song val <<= 4; 644792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 645792d376bSWei Song & 0x0f; 646792d376bSWei Song } else { 647792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 648792d376bSWei Song & 0xf0; 649792d376bSWei Song } 650792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 651792d376bSWei Song mutex_unlock(&data->update_lock); 652792d376bSWei Song 653792d376bSWei Song return count; 654792d376bSWei Song } 655792d376bSWei Song 656792d376bSWei Song static ssize_t 657792d376bSWei Song show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 658792d376bSWei Song { 659792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 660792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 661792d376bSWei Song to_sensor_dev_attr_2(attr); 662792d376bSWei Song int nr = sensor_attr->nr; 663792d376bSWei Song int index = sensor_attr->index; 66401879a85SJean Delvare unsigned int val; 665792d376bSWei Song 666792d376bSWei Song switch (nr) { 667792d376bSWei Song case PWM_STOP_TIME: 668792d376bSWei Song val = time_from_reg(data->pwm[index][nr]); 669792d376bSWei Song break; 67001879a85SJean Delvare case PWM_FREQ: 67101879a85SJean Delvare val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); 672792d376bSWei Song break; 673792d376bSWei Song default: 674792d376bSWei Song val = data->pwm[index][nr]; 675792d376bSWei Song break; 676792d376bSWei Song } 677792d376bSWei Song 678792d376bSWei Song return sprintf(buf, "%u\n", val); 679792d376bSWei Song } 680792d376bSWei Song 681792d376bSWei Song static ssize_t 682792d376bSWei Song store_pwm(struct device *dev, struct device_attribute *attr, 683792d376bSWei Song const char *buf, size_t count) 684792d376bSWei Song { 685792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 686792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 687792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 688792d376bSWei Song to_sensor_dev_attr_2(attr); 689792d376bSWei Song int nr = sensor_attr->nr; 690792d376bSWei Song int index = sensor_attr->index; 691792d376bSWei Song unsigned long val; 692792d376bSWei Song 693792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 694792d376bSWei Song return -EINVAL; 695792d376bSWei Song 696792d376bSWei Song mutex_lock(&data->update_lock); 697792d376bSWei Song switch (nr) { 698792d376bSWei Song case PWM_STOP_TIME: 699792d376bSWei Song val = time_to_reg(val); 700792d376bSWei Song break; 70101879a85SJean Delvare case PWM_FREQ: 70201879a85SJean Delvare val = pwm_freq_to_reg(val, data->clkin); 703792d376bSWei Song break; 704792d376bSWei Song default: 705792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 706792d376bSWei Song break; 707792d376bSWei Song } 708792d376bSWei Song w83795_write(client, W83795_REG_PWM(index, nr), val); 70901879a85SJean Delvare data->pwm[index][nr] = val; 710792d376bSWei Song mutex_unlock(&data->update_lock); 711792d376bSWei Song return count; 712792d376bSWei Song } 713792d376bSWei Song 714792d376bSWei Song static ssize_t 715792d376bSWei Song show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 716792d376bSWei Song { 717792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 718792d376bSWei Song to_sensor_dev_attr_2(attr); 719792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 720792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 721792d376bSWei Song int index = sensor_attr->index; 722792d376bSWei Song u8 tmp; 723792d376bSWei Song 724792d376bSWei Song if (1 == (data->pwm_fcms[0] & (1 << index))) { 725792d376bSWei Song tmp = 2; 726792d376bSWei Song goto out; 727792d376bSWei Song } 728792d376bSWei Song for (tmp = 0; tmp < 6; tmp++) { 729792d376bSWei Song if (data->pwm_tfmr[tmp] & (1 << index)) { 730792d376bSWei Song tmp = 3; 731792d376bSWei Song goto out; 732792d376bSWei Song } 733792d376bSWei Song } 734792d376bSWei Song if (data->pwm_fomc & (1 << index)) 735792d376bSWei Song tmp = 0; 736792d376bSWei Song else 737792d376bSWei Song tmp = 1; 738792d376bSWei Song 739792d376bSWei Song out: 740792d376bSWei Song return sprintf(buf, "%u\n", tmp); 741792d376bSWei Song } 742792d376bSWei Song 743792d376bSWei Song static ssize_t 744792d376bSWei Song store_pwm_enable(struct device *dev, struct device_attribute *attr, 745792d376bSWei Song const char *buf, size_t count) 746792d376bSWei Song { 747792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 748792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 749792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 750792d376bSWei Song to_sensor_dev_attr_2(attr); 751792d376bSWei Song int index = sensor_attr->index; 752792d376bSWei Song unsigned long val; 753792d376bSWei Song int i; 754792d376bSWei Song 755792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 756792d376bSWei Song return -EINVAL; 757792d376bSWei Song if (val > 2) 758792d376bSWei Song return -EINVAL; 759792d376bSWei Song 760792d376bSWei Song mutex_lock(&data->update_lock); 761792d376bSWei Song switch (val) { 762792d376bSWei Song case 0: 763792d376bSWei Song case 1: 764792d376bSWei Song data->pwm_fcms[0] &= ~(1 << index); 765792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 766792d376bSWei Song for (i = 0; i < 6; i++) { 767792d376bSWei Song data->pwm_tfmr[i] &= ~(1 << index); 768792d376bSWei Song w83795_write(client, W83795_REG_TFMR(i), 769792d376bSWei Song data->pwm_tfmr[i]); 770792d376bSWei Song } 771792d376bSWei Song data->pwm_fomc |= 1 << index; 772792d376bSWei Song data->pwm_fomc ^= val << index; 773792d376bSWei Song w83795_write(client, W83795_REG_FOMC, data->pwm_fomc); 774792d376bSWei Song break; 775792d376bSWei Song case 2: 776792d376bSWei Song data->pwm_fcms[0] |= (1 << index); 777792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 778792d376bSWei Song break; 779792d376bSWei Song } 780792d376bSWei Song mutex_unlock(&data->update_lock); 781792d376bSWei Song return count; 782792d376bSWei Song } 783792d376bSWei Song 784792d376bSWei Song static ssize_t 785792d376bSWei Song show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 786792d376bSWei Song { 787792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 788792d376bSWei Song to_sensor_dev_attr_2(attr); 789792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 790792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 791792d376bSWei Song int index = sensor_attr->index; 792792d376bSWei Song u8 val = index / 2; 793792d376bSWei Song u8 tmp = data->temp_src[val]; 794792d376bSWei Song 7957eb8d508SJean Delvare if (index & 1) 796792d376bSWei Song val = 4; 797792d376bSWei Song else 798792d376bSWei Song val = 0; 799792d376bSWei Song tmp >>= val; 800792d376bSWei Song tmp &= 0x0f; 801792d376bSWei Song 802792d376bSWei Song return sprintf(buf, "%u\n", tmp); 803792d376bSWei Song } 804792d376bSWei Song 805792d376bSWei Song static ssize_t 806792d376bSWei Song store_temp_src(struct device *dev, struct device_attribute *attr, 807792d376bSWei Song const char *buf, size_t count) 808792d376bSWei Song { 809792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 810792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 811792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 812792d376bSWei Song to_sensor_dev_attr_2(attr); 813792d376bSWei Song int index = sensor_attr->index; 814792d376bSWei Song unsigned long tmp; 815792d376bSWei Song u8 val = index / 2; 816792d376bSWei Song 817792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 818792d376bSWei Song return -EINVAL; 819792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 15); 820792d376bSWei Song 821792d376bSWei Song mutex_lock(&data->update_lock); 8227eb8d508SJean Delvare if (index & 1) { 823792d376bSWei Song tmp <<= 4; 824792d376bSWei Song data->temp_src[val] &= 0x0f; 825792d376bSWei Song } else { 826792d376bSWei Song data->temp_src[val] &= 0xf0; 827792d376bSWei Song } 828792d376bSWei Song data->temp_src[val] |= tmp; 829792d376bSWei Song w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 830792d376bSWei Song mutex_unlock(&data->update_lock); 831792d376bSWei Song 832792d376bSWei Song return count; 833792d376bSWei Song } 834792d376bSWei Song 835792d376bSWei Song #define TEMP_PWM_ENABLE 0 836792d376bSWei Song #define TEMP_PWM_FAN_MAP 1 837792d376bSWei Song static ssize_t 838792d376bSWei Song show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 839792d376bSWei Song char *buf) 840792d376bSWei Song { 841792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 842792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 843792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 844792d376bSWei Song to_sensor_dev_attr_2(attr); 845792d376bSWei Song int nr = sensor_attr->nr; 846792d376bSWei Song int index = sensor_attr->index; 847792d376bSWei Song u8 tmp = 0xff; 848792d376bSWei Song 849792d376bSWei Song switch (nr) { 850792d376bSWei Song case TEMP_PWM_ENABLE: 851792d376bSWei Song tmp = (data->pwm_fcms[1] >> index) & 1; 852792d376bSWei Song if (tmp) 853792d376bSWei Song tmp = 4; 854792d376bSWei Song else 855792d376bSWei Song tmp = 3; 856792d376bSWei Song break; 857792d376bSWei Song case TEMP_PWM_FAN_MAP: 858792d376bSWei Song tmp = data->pwm_tfmr[index]; 859792d376bSWei Song break; 860792d376bSWei Song } 861792d376bSWei Song 862792d376bSWei Song return sprintf(buf, "%u\n", tmp); 863792d376bSWei Song } 864792d376bSWei Song 865792d376bSWei Song static ssize_t 866792d376bSWei Song store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 867792d376bSWei Song const char *buf, size_t count) 868792d376bSWei Song { 869792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 870792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 871792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 872792d376bSWei Song to_sensor_dev_attr_2(attr); 873792d376bSWei Song int nr = sensor_attr->nr; 874792d376bSWei Song int index = sensor_attr->index; 875792d376bSWei Song unsigned long tmp; 876792d376bSWei Song 877792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 878792d376bSWei Song return -EINVAL; 879792d376bSWei Song 880792d376bSWei Song switch (nr) { 881792d376bSWei Song case TEMP_PWM_ENABLE: 882792d376bSWei Song if ((tmp != 3) && (tmp != 4)) 883792d376bSWei Song return -EINVAL; 884792d376bSWei Song tmp -= 3; 885792d376bSWei Song mutex_lock(&data->update_lock); 886792d376bSWei Song data->pwm_fcms[1] &= ~(1 << index); 887792d376bSWei Song data->pwm_fcms[1] |= tmp << index; 888792d376bSWei Song w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 889792d376bSWei Song mutex_unlock(&data->update_lock); 890792d376bSWei Song break; 891792d376bSWei Song case TEMP_PWM_FAN_MAP: 892792d376bSWei Song mutex_lock(&data->update_lock); 893792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 0xff); 894792d376bSWei Song w83795_write(client, W83795_REG_TFMR(index), tmp); 895792d376bSWei Song data->pwm_tfmr[index] = tmp; 896792d376bSWei Song mutex_unlock(&data->update_lock); 897792d376bSWei Song break; 898792d376bSWei Song } 899792d376bSWei Song return count; 900792d376bSWei Song } 901792d376bSWei Song 902792d376bSWei Song #define FANIN_TARGET 0 903792d376bSWei Song #define FANIN_TOL 1 904792d376bSWei Song static ssize_t 905792d376bSWei Song show_fanin(struct device *dev, struct device_attribute *attr, char *buf) 906792d376bSWei Song { 907792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 908792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 909792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 910792d376bSWei Song to_sensor_dev_attr_2(attr); 911792d376bSWei Song int nr = sensor_attr->nr; 912792d376bSWei Song int index = sensor_attr->index; 913792d376bSWei Song u16 tmp = 0; 914792d376bSWei Song 915792d376bSWei Song switch (nr) { 916792d376bSWei Song case FANIN_TARGET: 917792d376bSWei Song tmp = fan_from_reg(data->target_speed[index]); 918792d376bSWei Song break; 919792d376bSWei Song case FANIN_TOL: 920792d376bSWei Song tmp = data->tol_speed; 921792d376bSWei Song break; 922792d376bSWei Song } 923792d376bSWei Song 924792d376bSWei Song return sprintf(buf, "%u\n", tmp); 925792d376bSWei Song } 926792d376bSWei Song 927792d376bSWei Song static ssize_t 928792d376bSWei Song store_fanin(struct device *dev, struct device_attribute *attr, 929792d376bSWei Song const char *buf, size_t count) 930792d376bSWei Song { 931792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 932792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 933792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 934792d376bSWei Song to_sensor_dev_attr_2(attr); 935792d376bSWei Song int nr = sensor_attr->nr; 936792d376bSWei Song int index = sensor_attr->index; 937792d376bSWei Song unsigned long val; 938792d376bSWei Song 939792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 940792d376bSWei Song return -EINVAL; 941792d376bSWei Song 942792d376bSWei Song mutex_lock(&data->update_lock); 943792d376bSWei Song switch (nr) { 944792d376bSWei Song case FANIN_TARGET: 945792d376bSWei Song val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); 946792d376bSWei Song w83795_write(client, W83795_REG_FTSH(index), (val >> 4) & 0xff); 947792d376bSWei Song w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 948792d376bSWei Song data->target_speed[index] = val; 949792d376bSWei Song break; 950792d376bSWei Song case FANIN_TOL: 951792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3f); 952792d376bSWei Song w83795_write(client, W83795_REG_TFTS, val); 953792d376bSWei Song data->tol_speed = val; 954792d376bSWei Song break; 955792d376bSWei Song } 956792d376bSWei Song mutex_unlock(&data->update_lock); 957792d376bSWei Song 958792d376bSWei Song return count; 959792d376bSWei Song } 960792d376bSWei Song 961792d376bSWei Song 962792d376bSWei Song static ssize_t 963792d376bSWei Song show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 964792d376bSWei Song { 965792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 966792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 967792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 968792d376bSWei Song to_sensor_dev_attr_2(attr); 969792d376bSWei Song int nr = sensor_attr->nr; 970792d376bSWei Song int index = sensor_attr->index; 971792d376bSWei Song long tmp = temp_from_reg(data->pwm_temp[index][nr]); 972792d376bSWei Song 973792d376bSWei Song return sprintf(buf, "%ld\n", tmp); 974792d376bSWei Song } 975792d376bSWei Song 976792d376bSWei Song static ssize_t 977792d376bSWei Song store_temp_pwm(struct device *dev, struct device_attribute *attr, 978792d376bSWei Song const char *buf, size_t count) 979792d376bSWei Song { 980792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 981792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 982792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 983792d376bSWei Song to_sensor_dev_attr_2(attr); 984792d376bSWei Song int nr = sensor_attr->nr; 985792d376bSWei Song int index = sensor_attr->index; 986792d376bSWei Song unsigned long val; 987792d376bSWei Song u8 tmp; 988792d376bSWei Song 989792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 990792d376bSWei Song return -EINVAL; 991792d376bSWei Song val /= 1000; 992792d376bSWei Song 993792d376bSWei Song mutex_lock(&data->update_lock); 994792d376bSWei Song switch (nr) { 995792d376bSWei Song case TEMP_PWM_TTTI: 996792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 997792d376bSWei Song w83795_write(client, W83795_REG_TTTI(index), val); 998792d376bSWei Song break; 999792d376bSWei Song case TEMP_PWM_CTFS: 1000792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1001792d376bSWei Song w83795_write(client, W83795_REG_CTFS(index), val); 1002792d376bSWei Song break; 1003792d376bSWei Song case TEMP_PWM_HCT: 1004792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1005792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1006792d376bSWei Song tmp &= 0x0f; 1007792d376bSWei Song tmp |= (val << 4) & 0xf0; 1008792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1009792d376bSWei Song break; 1010792d376bSWei Song case TEMP_PWM_HOT: 1011792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1012792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1013792d376bSWei Song tmp &= 0xf0; 1014792d376bSWei Song tmp |= val & 0x0f; 1015792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1016792d376bSWei Song break; 1017792d376bSWei Song } 1018792d376bSWei Song data->pwm_temp[index][nr] = val; 1019792d376bSWei Song mutex_unlock(&data->update_lock); 1020792d376bSWei Song 1021792d376bSWei Song return count; 1022792d376bSWei Song } 1023792d376bSWei Song 1024792d376bSWei Song static ssize_t 1025792d376bSWei Song show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1026792d376bSWei Song { 1027792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1028792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1029792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1030792d376bSWei Song to_sensor_dev_attr_2(attr); 1031792d376bSWei Song int nr = sensor_attr->nr; 1032792d376bSWei Song int index = sensor_attr->index; 1033792d376bSWei Song 1034792d376bSWei Song return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 1035792d376bSWei Song } 1036792d376bSWei Song 1037792d376bSWei Song static ssize_t 1038792d376bSWei Song store_sf4_pwm(struct device *dev, struct device_attribute *attr, 1039792d376bSWei Song const char *buf, size_t count) 1040792d376bSWei Song { 1041792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1042792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1043792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1044792d376bSWei Song to_sensor_dev_attr_2(attr); 1045792d376bSWei Song int nr = sensor_attr->nr; 1046792d376bSWei Song int index = sensor_attr->index; 1047792d376bSWei Song unsigned long val; 1048792d376bSWei Song 1049792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1050792d376bSWei Song return -EINVAL; 1051792d376bSWei Song 1052792d376bSWei Song mutex_lock(&data->update_lock); 1053792d376bSWei Song w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 1054792d376bSWei Song data->sf4_reg[index][SF4_PWM][nr] = val; 1055792d376bSWei Song mutex_unlock(&data->update_lock); 1056792d376bSWei Song 1057792d376bSWei Song return count; 1058792d376bSWei Song } 1059792d376bSWei Song 1060792d376bSWei Song static ssize_t 1061792d376bSWei Song show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 1062792d376bSWei Song { 1063792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1064792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1065792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1066792d376bSWei Song to_sensor_dev_attr_2(attr); 1067792d376bSWei Song int nr = sensor_attr->nr; 1068792d376bSWei Song int index = sensor_attr->index; 1069792d376bSWei Song 1070792d376bSWei Song return sprintf(buf, "%u\n", 1071792d376bSWei Song (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 1072792d376bSWei Song } 1073792d376bSWei Song 1074792d376bSWei Song static ssize_t 1075792d376bSWei Song store_sf4_temp(struct device *dev, struct device_attribute *attr, 1076792d376bSWei Song const char *buf, size_t count) 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 unsigned long val; 1085792d376bSWei Song 1086792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1087792d376bSWei Song return -EINVAL; 1088792d376bSWei Song val /= 1000; 1089792d376bSWei Song 1090792d376bSWei Song mutex_lock(&data->update_lock); 1091792d376bSWei Song w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 1092792d376bSWei Song data->sf4_reg[index][SF4_TEMP][nr] = val; 1093792d376bSWei Song mutex_unlock(&data->update_lock); 1094792d376bSWei Song 1095792d376bSWei Song return count; 1096792d376bSWei Song } 1097792d376bSWei Song 1098792d376bSWei Song 1099792d376bSWei Song static ssize_t 1100792d376bSWei Song show_temp(struct device *dev, struct device_attribute *attr, char *buf) 1101792d376bSWei Song { 1102792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1103792d376bSWei Song to_sensor_dev_attr_2(attr); 1104792d376bSWei Song int nr = sensor_attr->nr; 1105792d376bSWei Song int index = sensor_attr->index; 1106792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1107dd127f5cSJean Delvare long temp = temp_from_reg(data->temp[index][nr]); 1108792d376bSWei Song 1109792d376bSWei Song if (TEMP_READ == nr) 1110a654b9d4SJean Delvare temp += (data->temp_read_vrlsb[index] >> 6) * 250; 1111792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1112792d376bSWei Song } 1113792d376bSWei Song 1114792d376bSWei Song static ssize_t 1115792d376bSWei Song store_temp(struct device *dev, struct device_attribute *attr, 1116792d376bSWei Song const char *buf, size_t count) 1117792d376bSWei Song { 1118792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1119792d376bSWei Song to_sensor_dev_attr_2(attr); 1120792d376bSWei Song int nr = sensor_attr->nr; 1121792d376bSWei Song int index = sensor_attr->index; 1122792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1123792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1124792d376bSWei Song long tmp; 1125792d376bSWei Song 1126792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1127792d376bSWei Song return -EINVAL; 1128792d376bSWei Song 1129792d376bSWei Song mutex_lock(&data->update_lock); 1130792d376bSWei Song data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 1131792d376bSWei Song w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 1132792d376bSWei Song mutex_unlock(&data->update_lock); 1133792d376bSWei Song return count; 1134792d376bSWei Song } 1135792d376bSWei Song 1136792d376bSWei Song 1137792d376bSWei Song static ssize_t 1138792d376bSWei Song show_dts_mode(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); 114239deb699SJean Delvare int tmp; 1143792d376bSWei Song 1144792d376bSWei Song if (data->enable_dts & 2) 1145792d376bSWei Song tmp = 5; 1146792d376bSWei Song else 1147792d376bSWei Song tmp = 6; 1148792d376bSWei Song 1149792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1150792d376bSWei Song } 1151792d376bSWei Song 1152792d376bSWei Song static ssize_t 1153792d376bSWei Song show_dts(struct device *dev, struct device_attribute *attr, char *buf) 1154792d376bSWei Song { 1155792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1156792d376bSWei Song to_sensor_dev_attr_2(attr); 1157792d376bSWei Song int index = sensor_attr->index; 1158792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1159dd127f5cSJean Delvare long temp = temp_from_reg(data->dts[index]); 1160792d376bSWei Song 1161a654b9d4SJean Delvare temp += (data->dts_read_vrlsb[index] >> 6) * 250; 1162792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1163792d376bSWei Song } 1164792d376bSWei Song 1165792d376bSWei Song static ssize_t 1166792d376bSWei Song show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 1167792d376bSWei Song { 1168792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1169792d376bSWei Song to_sensor_dev_attr_2(attr); 1170792d376bSWei Song int nr = sensor_attr->nr; 1171792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1172792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1173dd127f5cSJean Delvare long temp = temp_from_reg(data->dts_ext[nr]); 1174792d376bSWei Song 1175792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1176792d376bSWei Song } 1177792d376bSWei Song 1178792d376bSWei Song static ssize_t 1179792d376bSWei Song store_dts_ext(struct device *dev, struct device_attribute *attr, 1180792d376bSWei Song const char *buf, size_t count) 1181792d376bSWei Song { 1182792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1183792d376bSWei Song to_sensor_dev_attr_2(attr); 1184792d376bSWei Song int nr = sensor_attr->nr; 1185792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1186792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1187792d376bSWei Song long tmp; 1188792d376bSWei Song 1189792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1190792d376bSWei Song return -EINVAL; 1191792d376bSWei Song 1192792d376bSWei Song mutex_lock(&data->update_lock); 1193792d376bSWei Song data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 1194792d376bSWei Song w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 1195792d376bSWei Song mutex_unlock(&data->update_lock); 1196792d376bSWei Song return count; 1197792d376bSWei Song } 1198792d376bSWei Song 1199792d376bSWei Song 1200792d376bSWei Song static ssize_t 1201792d376bSWei Song show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 1202792d376bSWei Song { 1203792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1204792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1205792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1206792d376bSWei Song to_sensor_dev_attr_2(attr); 1207792d376bSWei Song int index = sensor_attr->index; 120839deb699SJean Delvare int tmp; 1209792d376bSWei Song 121039deb699SJean Delvare if (data->temp_mode & (1 << index)) 121139deb699SJean Delvare tmp = 3; /* Thermal diode */ 1212792d376bSWei Song else 121339deb699SJean Delvare tmp = 4; /* Thermistor */ 1214792d376bSWei Song 1215792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1216792d376bSWei Song } 1217792d376bSWei Song 121839deb699SJean Delvare /* Only for temp1-4 (temp5-6 can only be thermistor) */ 1219792d376bSWei Song static ssize_t 1220792d376bSWei Song store_temp_mode(struct device *dev, struct device_attribute *attr, 1221792d376bSWei Song const char *buf, size_t count) 1222792d376bSWei Song { 1223792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1224792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1225792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1226792d376bSWei Song to_sensor_dev_attr_2(attr); 1227792d376bSWei Song int index = sensor_attr->index; 122839deb699SJean Delvare int reg_shift; 1229792d376bSWei Song unsigned long val; 1230792d376bSWei Song u8 tmp; 1231792d376bSWei Song 1232792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1233792d376bSWei Song return -EINVAL; 1234792d376bSWei Song if ((val != 4) && (val != 3)) 1235792d376bSWei Song return -EINVAL; 1236792d376bSWei Song 1237792d376bSWei Song mutex_lock(&data->update_lock); 1238792d376bSWei Song if (val == 3) { 123939deb699SJean Delvare /* Thermal diode */ 124039deb699SJean Delvare val = 0x01; 1241792d376bSWei Song data->temp_mode |= 1 << index; 1242792d376bSWei Song } else if (val == 4) { 124339deb699SJean Delvare /* Thermistor */ 124439deb699SJean Delvare val = 0x03; 124539deb699SJean Delvare data->temp_mode &= ~(1 << index); 1246792d376bSWei Song } 1247792d376bSWei Song 124839deb699SJean Delvare reg_shift = 2 * index; 1249792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 125039deb699SJean Delvare tmp &= ~(0x03 << reg_shift); 125139deb699SJean Delvare tmp |= val << reg_shift; 1252792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 1253792d376bSWei Song 1254792d376bSWei Song mutex_unlock(&data->update_lock); 1255792d376bSWei Song return count; 1256792d376bSWei Song } 1257792d376bSWei Song 1258792d376bSWei Song 1259792d376bSWei Song /* show/store VIN */ 1260792d376bSWei Song static ssize_t 1261792d376bSWei Song show_in(struct device *dev, struct device_attribute *attr, char *buf) 1262792d376bSWei Song { 1263792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1264792d376bSWei Song to_sensor_dev_attr_2(attr); 1265792d376bSWei Song int nr = sensor_attr->nr; 1266792d376bSWei Song int index = sensor_attr->index; 1267792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1268792d376bSWei Song u16 val = data->in[index][nr]; 1269792d376bSWei Song u8 lsb_idx; 1270792d376bSWei Song 1271792d376bSWei Song switch (nr) { 1272792d376bSWei Song case IN_READ: 1273792d376bSWei Song /* calculate this value again by sensors as sensors3.conf */ 1274792d376bSWei Song if ((index >= 17) && 12756f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1276792d376bSWei Song val *= 8; 1277792d376bSWei Song break; 1278792d376bSWei Song case IN_MAX: 1279792d376bSWei Song case IN_LOW: 1280792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1281792d376bSWei Song val <<= 2; 1282792d376bSWei Song val |= (data->in_lsb[lsb_idx][nr] >> 1283792d376bSWei Song IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; 1284792d376bSWei Song if ((index >= 17) && 12856f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1286792d376bSWei Song val *= 8; 1287792d376bSWei Song break; 1288792d376bSWei Song } 1289792d376bSWei Song val = in_from_reg(index, val); 1290792d376bSWei Song 1291792d376bSWei Song return sprintf(buf, "%d\n", val); 1292792d376bSWei Song } 1293792d376bSWei Song 1294792d376bSWei Song static ssize_t 1295792d376bSWei Song store_in(struct device *dev, struct device_attribute *attr, 1296792d376bSWei Song const char *buf, size_t count) 1297792d376bSWei Song { 1298792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1299792d376bSWei Song to_sensor_dev_attr_2(attr); 1300792d376bSWei Song int nr = sensor_attr->nr; 1301792d376bSWei Song int index = sensor_attr->index; 1302792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1303792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1304792d376bSWei Song unsigned long val; 1305792d376bSWei Song u8 tmp; 1306792d376bSWei Song u8 lsb_idx; 1307792d376bSWei Song 1308792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1309792d376bSWei Song return -EINVAL; 1310792d376bSWei Song val = in_to_reg(index, val); 1311792d376bSWei Song 1312792d376bSWei Song if ((index >= 17) && 13136f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1314792d376bSWei Song val /= 8; 1315792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3FF); 1316792d376bSWei Song mutex_lock(&data->update_lock); 1317792d376bSWei Song 1318792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1319792d376bSWei Song tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 1320792d376bSWei Song tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 1321792d376bSWei Song tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 1322792d376bSWei Song w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 1323792d376bSWei Song data->in_lsb[lsb_idx][nr] = tmp; 1324792d376bSWei Song 1325792d376bSWei Song tmp = (val >> 2) & 0xff; 1326792d376bSWei Song w83795_write(client, W83795_REG_IN[index][nr], tmp); 1327792d376bSWei Song data->in[index][nr] = tmp; 1328792d376bSWei Song 1329792d376bSWei Song mutex_unlock(&data->update_lock); 1330792d376bSWei Song return count; 1331792d376bSWei Song } 1332792d376bSWei Song 1333792d376bSWei Song 1334792d376bSWei Song static ssize_t 1335792d376bSWei Song show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 1336792d376bSWei Song { 1337792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1338792d376bSWei Song to_sensor_dev_attr_2(attr); 1339792d376bSWei Song int nr = sensor_attr->nr; 1340792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1341792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1342792d376bSWei Song u16 val = data->setup_pwm[nr]; 1343792d376bSWei Song 1344792d376bSWei Song switch (nr) { 1345792d376bSWei Song case SETUP_PWM_UPTIME: 1346792d376bSWei Song case SETUP_PWM_DOWNTIME: 1347792d376bSWei Song val = time_from_reg(val); 1348792d376bSWei Song break; 1349792d376bSWei Song } 1350792d376bSWei Song 1351792d376bSWei Song return sprintf(buf, "%d\n", val); 1352792d376bSWei Song } 1353792d376bSWei Song 1354792d376bSWei Song static ssize_t 1355792d376bSWei Song store_sf_setup(struct device *dev, struct device_attribute *attr, 1356792d376bSWei Song const char *buf, size_t count) 1357792d376bSWei Song { 1358792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1359792d376bSWei Song to_sensor_dev_attr_2(attr); 1360792d376bSWei Song int nr = sensor_attr->nr; 1361792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1362792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1363792d376bSWei Song unsigned long val; 1364792d376bSWei Song 1365792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1366792d376bSWei Song return -EINVAL; 1367792d376bSWei Song 1368792d376bSWei Song switch (nr) { 1369792d376bSWei Song case SETUP_PWM_DEFAULT: 1370792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 1371792d376bSWei Song break; 1372792d376bSWei Song case SETUP_PWM_UPTIME: 1373792d376bSWei Song case SETUP_PWM_DOWNTIME: 1374792d376bSWei Song val = time_to_reg(val); 1375792d376bSWei Song if (val == 0) 1376792d376bSWei Song return -EINVAL; 1377792d376bSWei Song break; 1378792d376bSWei Song } 1379792d376bSWei Song 1380792d376bSWei Song mutex_lock(&data->update_lock); 1381792d376bSWei Song data->setup_pwm[nr] = val; 1382792d376bSWei Song w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 1383792d376bSWei Song mutex_unlock(&data->update_lock); 1384792d376bSWei Song return count; 1385792d376bSWei Song } 1386792d376bSWei Song 1387792d376bSWei Song 1388792d376bSWei Song #define NOT_USED -1 1389792d376bSWei Song 13900e256018SJean Delvare /* Don't change the attribute order, _max and _min are accessed by index 13910e256018SJean Delvare * somewhere else in the code */ 139287df0dadSJean Delvare #define SENSOR_ATTR_IN(index) { \ 1393792d376bSWei Song SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 1394792d376bSWei Song IN_READ, index), \ 1395792d376bSWei Song SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 1396792d376bSWei Song store_in, IN_MAX, index), \ 1397792d376bSWei Song SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 1398792d376bSWei Song store_in, IN_LOW, index), \ 1399792d376bSWei Song SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 1400792d376bSWei Song NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 1401792d376bSWei Song SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 1402792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 140387df0dadSJean Delvare index + ((index > 14) ? 1 : 0)) } 1404792d376bSWei Song 140587df0dadSJean Delvare #define SENSOR_ATTR_FAN(index) { \ 1406792d376bSWei Song SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 1407792d376bSWei Song NULL, FAN_INPUT, index - 1), \ 1408792d376bSWei Song SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 1409792d376bSWei Song show_fan, store_fan_min, FAN_MIN, index - 1), \ 1410792d376bSWei Song SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 1411792d376bSWei Song NULL, ALARM_STATUS, index + 31), \ 1412792d376bSWei Song SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 141387df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 1414792d376bSWei Song 1415b5f6a90aSJean Delvare #define SENSOR_ATTR_PWM(index) { \ 1416792d376bSWei Song SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 1417792d376bSWei Song store_pwm, PWM_OUTPUT, index - 1), \ 1418792d376bSWei Song SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 1419792d376bSWei Song show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 1420792d376bSWei Song SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 1421792d376bSWei Song show_pwm, store_pwm, PWM_START, index - 1), \ 1422792d376bSWei Song SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 1423792d376bSWei Song show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 142401879a85SJean Delvare SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ 142501879a85SJean Delvare show_pwm, store_pwm, PWM_FREQ, index - 1), \ 1426792d376bSWei Song SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 1427b2cc528eSJean Delvare show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 1428b2cc528eSJean Delvare SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 1429b2cc528eSJean Delvare show_fanin, store_fanin, FANIN_TARGET, index - 1) } 1430792d376bSWei Song 143187df0dadSJean Delvare #define SENSOR_ATTR_DTS(index) { \ 1432792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 1433792d376bSWei Song show_dts_mode, NULL, NOT_USED, index - 7), \ 1434792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 1435792d376bSWei Song NULL, NOT_USED, index - 7), \ 1436a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ 1437792d376bSWei Song store_dts_ext, DTS_CRIT, NOT_USED), \ 1438a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1439792d376bSWei Song show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 1440a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 1441792d376bSWei Song store_dts_ext, DTS_WARN, NOT_USED), \ 1442a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1443792d376bSWei Song show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 1444792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1445792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 1446792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 144787df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 1448792d376bSWei Song 144987df0dadSJean Delvare #define SENSOR_ATTR_TEMP(index) { \ 145039deb699SJean Delvare SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \ 1451792d376bSWei Song show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 1452792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 1453792d376bSWei Song NULL, TEMP_READ, index - 1), \ 1454a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ 1455792d376bSWei Song store_temp, TEMP_CRIT, index - 1), \ 1456a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1457792d376bSWei Song show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 1458a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 1459792d376bSWei Song store_temp, TEMP_WARN, index - 1), \ 1460a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1461792d376bSWei Song show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 1462792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1463792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, \ 1464792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1465792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 1466792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 1467792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1468792d376bSWei Song SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \ 1469792d376bSWei Song show_temp_src, store_temp_src, NOT_USED, index - 1), \ 1470792d376bSWei Song SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 1471792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1472792d376bSWei Song TEMP_PWM_ENABLE, index - 1), \ 1473792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 1474792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1475792d376bSWei Song TEMP_PWM_FAN_MAP, index - 1), \ 1476792d376bSWei Song SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 1477792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 1478a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ 1479792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 1480a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ 1481792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 1482792d376bSWei Song SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 1483792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 1484792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 1485792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 1486792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 1487792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 1488792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 1489792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 1490792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 1491792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 1492792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 1493792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 1494792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 1495792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 1496792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 1497792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 1498792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 1499792d376bSWei Song show_sf4_temp, store_sf4_temp, 0, index - 1), \ 1500792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 1501792d376bSWei Song show_sf4_temp, store_sf4_temp, 1, index - 1), \ 1502792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 1503792d376bSWei Song show_sf4_temp, store_sf4_temp, 2, index - 1), \ 1504792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 1505792d376bSWei Song show_sf4_temp, store_sf4_temp, 3, index - 1), \ 1506792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 1507792d376bSWei Song show_sf4_temp, store_sf4_temp, 4, index - 1), \ 1508792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 1509792d376bSWei Song show_sf4_temp, store_sf4_temp, 5, index - 1), \ 1510792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 151187df0dadSJean Delvare show_sf4_temp, store_sf4_temp, 6, index - 1) } 1512792d376bSWei Song 1513792d376bSWei Song 151487df0dadSJean Delvare static struct sensor_device_attribute_2 w83795_in[][5] = { 1515792d376bSWei Song SENSOR_ATTR_IN(0), 1516792d376bSWei Song SENSOR_ATTR_IN(1), 1517792d376bSWei Song SENSOR_ATTR_IN(2), 1518792d376bSWei Song SENSOR_ATTR_IN(3), 1519792d376bSWei Song SENSOR_ATTR_IN(4), 1520792d376bSWei Song SENSOR_ATTR_IN(5), 1521792d376bSWei Song SENSOR_ATTR_IN(6), 1522792d376bSWei Song SENSOR_ATTR_IN(7), 1523792d376bSWei Song SENSOR_ATTR_IN(8), 1524792d376bSWei Song SENSOR_ATTR_IN(9), 1525792d376bSWei Song SENSOR_ATTR_IN(10), 1526792d376bSWei Song SENSOR_ATTR_IN(11), 1527792d376bSWei Song SENSOR_ATTR_IN(12), 1528792d376bSWei Song SENSOR_ATTR_IN(13), 1529792d376bSWei Song SENSOR_ATTR_IN(14), 1530792d376bSWei Song SENSOR_ATTR_IN(15), 1531792d376bSWei Song SENSOR_ATTR_IN(16), 1532792d376bSWei Song SENSOR_ATTR_IN(17), 1533792d376bSWei Song SENSOR_ATTR_IN(18), 1534792d376bSWei Song SENSOR_ATTR_IN(19), 1535792d376bSWei Song SENSOR_ATTR_IN(20), 1536792d376bSWei Song }; 1537792d376bSWei Song 153886ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_fan[][4] = { 1539792d376bSWei Song SENSOR_ATTR_FAN(1), 1540792d376bSWei Song SENSOR_ATTR_FAN(2), 1541792d376bSWei Song SENSOR_ATTR_FAN(3), 1542792d376bSWei Song SENSOR_ATTR_FAN(4), 1543792d376bSWei Song SENSOR_ATTR_FAN(5), 1544792d376bSWei Song SENSOR_ATTR_FAN(6), 1545792d376bSWei Song SENSOR_ATTR_FAN(7), 1546792d376bSWei Song SENSOR_ATTR_FAN(8), 1547792d376bSWei Song SENSOR_ATTR_FAN(9), 1548792d376bSWei Song SENSOR_ATTR_FAN(10), 1549792d376bSWei Song SENSOR_ATTR_FAN(11), 1550792d376bSWei Song SENSOR_ATTR_FAN(12), 1551792d376bSWei Song SENSOR_ATTR_FAN(13), 1552792d376bSWei Song SENSOR_ATTR_FAN(14), 1553792d376bSWei Song }; 1554792d376bSWei Song 155586ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_temp[][29] = { 1556792d376bSWei Song SENSOR_ATTR_TEMP(1), 1557792d376bSWei Song SENSOR_ATTR_TEMP(2), 1558792d376bSWei Song SENSOR_ATTR_TEMP(3), 1559792d376bSWei Song SENSOR_ATTR_TEMP(4), 1560792d376bSWei Song SENSOR_ATTR_TEMP(5), 1561792d376bSWei Song SENSOR_ATTR_TEMP(6), 1562792d376bSWei Song }; 1563792d376bSWei Song 156486ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_dts[][8] = { 1565792d376bSWei Song SENSOR_ATTR_DTS(7), 1566792d376bSWei Song SENSOR_ATTR_DTS(8), 1567792d376bSWei Song SENSOR_ATTR_DTS(9), 1568792d376bSWei Song SENSOR_ATTR_DTS(10), 1569792d376bSWei Song SENSOR_ATTR_DTS(11), 1570792d376bSWei Song SENSOR_ATTR_DTS(12), 1571792d376bSWei Song SENSOR_ATTR_DTS(13), 1572792d376bSWei Song SENSOR_ATTR_DTS(14), 1573792d376bSWei Song }; 1574792d376bSWei Song 157586ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_pwm[][7] = { 1576b5f6a90aSJean Delvare SENSOR_ATTR_PWM(1), 1577b5f6a90aSJean Delvare SENSOR_ATTR_PWM(2), 1578792d376bSWei Song SENSOR_ATTR_PWM(3), 1579792d376bSWei Song SENSOR_ATTR_PWM(4), 1580792d376bSWei Song SENSOR_ATTR_PWM(5), 1581792d376bSWei Song SENSOR_ATTR_PWM(6), 1582792d376bSWei Song SENSOR_ATTR_PWM(7), 1583792d376bSWei Song SENSOR_ATTR_PWM(8), 1584792d376bSWei Song }; 1585792d376bSWei Song 158686ef4d2fSJean Delvare static const struct sensor_device_attribute_2 sda_single_files[] = { 1587792d376bSWei Song SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, 1588792d376bSWei Song store_chassis_clear, ALARM_STATUS, 46), 158902728ffeSJean Delvare SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, 159002728ffeSJean Delvare store_beep, BEEP_ENABLE, 47), 1591792d376bSWei Song SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 1592792d376bSWei Song store_fanin, FANIN_TOL, NOT_USED), 1593792d376bSWei Song SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 1594792d376bSWei Song store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 1595792d376bSWei Song SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 1596792d376bSWei Song store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 1597792d376bSWei Song SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 1598792d376bSWei Song store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 1599792d376bSWei Song }; 1600792d376bSWei Song 1601792d376bSWei Song /* 1602792d376bSWei Song * Driver interface 1603792d376bSWei Song */ 1604792d376bSWei Song 1605792d376bSWei Song static void w83795_init_client(struct i2c_client *client) 1606792d376bSWei Song { 160701879a85SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 160801879a85SJean Delvare static const u16 clkin[4] = { /* in kHz */ 160901879a85SJean Delvare 14318, 24000, 33333, 48000 161001879a85SJean Delvare }; 161180646b95SJean Delvare u8 config; 161280646b95SJean Delvare 1613792d376bSWei Song if (reset) 1614792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 0x80); 1615792d376bSWei Song 161680646b95SJean Delvare /* Start monitoring if needed */ 161780646b95SJean Delvare config = w83795_read(client, W83795_REG_CONFIG); 161880646b95SJean Delvare if (!(config & W83795_REG_CONFIG_START)) { 161980646b95SJean Delvare dev_info(&client->dev, "Enabling monitoring operations\n"); 1620792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 162180646b95SJean Delvare config | W83795_REG_CONFIG_START); 162280646b95SJean Delvare } 162301879a85SJean Delvare 162401879a85SJean Delvare data->clkin = clkin[(config >> 3) & 0x3]; 162501879a85SJean Delvare dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); 1626792d376bSWei Song } 1627792d376bSWei Song 16282be381deSJean Delvare static int w83795_get_device_id(struct i2c_client *client) 16292be381deSJean Delvare { 16302be381deSJean Delvare int device_id; 16312be381deSJean Delvare 16322be381deSJean Delvare device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 16332be381deSJean Delvare 16342be381deSJean Delvare /* Special case for rev. A chips; can't be checked first because later 16352be381deSJean Delvare revisions emulate this for compatibility */ 16362be381deSJean Delvare if (device_id < 0 || (device_id & 0xf0) != 0x50) { 16372be381deSJean Delvare int alt_id; 16382be381deSJean Delvare 16392be381deSJean Delvare alt_id = i2c_smbus_read_byte_data(client, 16402be381deSJean Delvare W83795_REG_DEVICEID_A); 16412be381deSJean Delvare if (alt_id == 0x50) 16422be381deSJean Delvare device_id = alt_id; 16432be381deSJean Delvare } 16442be381deSJean Delvare 16452be381deSJean Delvare return device_id; 16462be381deSJean Delvare } 16472be381deSJean Delvare 1648792d376bSWei Song /* Return 0 if detection is successful, -ENODEV otherwise */ 1649792d376bSWei Song static int w83795_detect(struct i2c_client *client, 1650792d376bSWei Song struct i2c_board_info *info) 1651792d376bSWei Song { 16522be381deSJean Delvare int bank, vendor_id, device_id, expected, i2c_addr, config; 1653792d376bSWei Song struct i2c_adapter *adapter = client->adapter; 1654792d376bSWei Song unsigned short address = client->addr; 1655093d1a47SJean Delvare const char *chip_name; 1656792d376bSWei Song 1657792d376bSWei Song if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1658792d376bSWei Song return -ENODEV; 1659792d376bSWei Song bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 16602be381deSJean Delvare if (bank < 0 || (bank & 0x7c)) { 16612be381deSJean Delvare dev_dbg(&adapter->dev, 16622be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 16632be381deSJean Delvare address, "bank"); 16642be381deSJean Delvare return -ENODEV; 16652be381deSJean Delvare } 1666792d376bSWei Song 1667792d376bSWei Song /* Check Nuvoton vendor ID */ 16682be381deSJean Delvare vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 16692be381deSJean Delvare expected = bank & 0x80 ? 0x5c : 0xa3; 16702be381deSJean Delvare if (vendor_id != expected) { 16712be381deSJean Delvare dev_dbg(&adapter->dev, 16722be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 16732be381deSJean Delvare address, "vendor id"); 16742be381deSJean Delvare return -ENODEV; 16752be381deSJean Delvare } 16762be381deSJean Delvare 16772be381deSJean Delvare /* Check device ID */ 16782be381deSJean Delvare device_id = w83795_get_device_id(client) | 16792be381deSJean Delvare (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 16802be381deSJean Delvare if ((device_id >> 4) != 0x795) { 16812be381deSJean Delvare dev_dbg(&adapter->dev, 16822be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 16832be381deSJean Delvare address, "device id\n"); 1684792d376bSWei Song return -ENODEV; 1685792d376bSWei Song } 1686792d376bSWei Song 1687792d376bSWei Song /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 1688792d376bSWei Song should match */ 16892be381deSJean Delvare if ((bank & 0x07) == 0) { 16902be381deSJean Delvare i2c_addr = i2c_smbus_read_byte_data(client, 16912be381deSJean Delvare W83795_REG_I2C_ADDR); 16922be381deSJean Delvare if ((i2c_addr & 0x7f) != address) { 16932be381deSJean Delvare dev_dbg(&adapter->dev, 16942be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, " 16952be381deSJean Delvare "check %s\n", address, "i2c addr"); 1696792d376bSWei Song return -ENODEV; 1697792d376bSWei Song } 1698792d376bSWei Song } 1699792d376bSWei Song 1700093d1a47SJean Delvare /* Check 795 chip type: 795G or 795ADG 1701093d1a47SJean Delvare Usually we don't write to chips during detection, but here we don't 1702093d1a47SJean Delvare quite have the choice; hopefully it's OK, we are about to return 1703093d1a47SJean Delvare success anyway */ 1704093d1a47SJean Delvare if ((bank & 0x07) != 0) 1705093d1a47SJean Delvare i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 1706093d1a47SJean Delvare bank & ~0x07); 17072be381deSJean Delvare config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 17082be381deSJean Delvare if (config & W83795_REG_CONFIG_CONFIG48) 1709093d1a47SJean Delvare chip_name = "w83795adg"; 17102be381deSJean Delvare else 1711093d1a47SJean Delvare chip_name = "w83795g"; 1712792d376bSWei Song 1713093d1a47SJean Delvare strlcpy(info->type, chip_name, I2C_NAME_SIZE); 17142be381deSJean Delvare dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 17152be381deSJean Delvare 'A' + (device_id & 0xf), address); 1716792d376bSWei Song 1717792d376bSWei Song return 0; 1718792d376bSWei Song } 1719792d376bSWei Song 17206f3dcde9SJean Delvare static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 17216f3dcde9SJean Delvare const struct device_attribute *)) 1722892514a6SJean Delvare { 1723892514a6SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 172487df0dadSJean Delvare int err, i, j; 1725892514a6SJean Delvare 1726892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 172787df0dadSJean Delvare if (!(data->has_in & (1 << i))) 1728892514a6SJean Delvare continue; 172987df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 173087df0dadSJean Delvare err = fn(dev, &w83795_in[i][j].dev_attr); 1731892514a6SJean Delvare if (err) 1732892514a6SJean Delvare return err; 1733892514a6SJean Delvare } 173487df0dadSJean Delvare } 1735892514a6SJean Delvare 1736892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 173787df0dadSJean Delvare if (!(data->has_fan & (1 << i))) 1738892514a6SJean Delvare continue; 173987df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 174087df0dadSJean Delvare err = fn(dev, &w83795_fan[i][j].dev_attr); 1741892514a6SJean Delvare if (err) 1742892514a6SJean Delvare return err; 1743892514a6SJean Delvare } 174487df0dadSJean Delvare } 1745892514a6SJean Delvare 1746892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 17476f3dcde9SJean Delvare err = fn(dev, &sda_single_files[i].dev_attr); 1748892514a6SJean Delvare if (err) 1749892514a6SJean Delvare return err; 1750892514a6SJean Delvare } 1751892514a6SJean Delvare 1752b5f6a90aSJean Delvare for (i = 0; i < data->has_pwm; i++) { 1753b5f6a90aSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { 1754b5f6a90aSJean Delvare err = fn(dev, &w83795_pwm[i][j].dev_attr); 1755892514a6SJean Delvare if (err) 1756892514a6SJean Delvare return err; 1757892514a6SJean Delvare } 1758892514a6SJean Delvare } 1759892514a6SJean Delvare 1760892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 176187df0dadSJean Delvare if (!(data->has_temp & (1 << i))) 1762892514a6SJean Delvare continue; 176387df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { 176487df0dadSJean Delvare err = fn(dev, &w83795_temp[i][j].dev_attr); 1765892514a6SJean Delvare if (err) 1766892514a6SJean Delvare return err; 1767892514a6SJean Delvare } 176887df0dadSJean Delvare } 1769892514a6SJean Delvare 1770892514a6SJean Delvare if (data->enable_dts != 0) { 1771892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 177287df0dadSJean Delvare if (!(data->has_dts & (1 << i))) 1773892514a6SJean Delvare continue; 177487df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 177587df0dadSJean Delvare err = fn(dev, &w83795_dts[i][j].dev_attr); 1776892514a6SJean Delvare if (err) 1777892514a6SJean Delvare return err; 1778892514a6SJean Delvare } 1779892514a6SJean Delvare } 178087df0dadSJean Delvare } 1781892514a6SJean Delvare 1782892514a6SJean Delvare return 0; 1783892514a6SJean Delvare } 1784892514a6SJean Delvare 17856f3dcde9SJean Delvare /* We need a wrapper that fits in w83795_handle_files */ 17866f3dcde9SJean Delvare static int device_remove_file_wrapper(struct device *dev, 17876f3dcde9SJean Delvare const struct device_attribute *attr) 17882fa09878SJean Delvare { 17896f3dcde9SJean Delvare device_remove_file(dev, attr); 17906f3dcde9SJean Delvare return 0; 17912fa09878SJean Delvare } 17922fa09878SJean Delvare 17930e256018SJean Delvare static void w83795_check_dynamic_in_limits(struct i2c_client *client) 17940e256018SJean Delvare { 17950e256018SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 17960e256018SJean Delvare u8 vid_ctl; 17970e256018SJean Delvare int i, err_max, err_min; 17980e256018SJean Delvare 17990e256018SJean Delvare vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); 18000e256018SJean Delvare 18010e256018SJean Delvare /* Return immediately if VRM isn't configured */ 18020e256018SJean Delvare if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) 18030e256018SJean Delvare return; 18040e256018SJean Delvare 18050e256018SJean Delvare data->has_dyn_in = (vid_ctl >> 3) & 0x07; 18060e256018SJean Delvare for (i = 0; i < 2; i++) { 18070e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 18080e256018SJean Delvare continue; 18090e256018SJean Delvare 18100e256018SJean Delvare /* Voltage limits in dynamic mode, switch to read-only */ 18110e256018SJean Delvare err_max = sysfs_chmod_file(&client->dev.kobj, 18120e256018SJean Delvare &w83795_in[i][2].dev_attr.attr, 18130e256018SJean Delvare S_IRUGO); 18140e256018SJean Delvare err_min = sysfs_chmod_file(&client->dev.kobj, 18150e256018SJean Delvare &w83795_in[i][3].dev_attr.attr, 18160e256018SJean Delvare S_IRUGO); 18170e256018SJean Delvare if (err_max || err_min) 18180e256018SJean Delvare dev_warn(&client->dev, "Failed to set in%d limits " 18190e256018SJean Delvare "read-only (%d, %d)\n", i, err_max, err_min); 18200e256018SJean Delvare else 18210e256018SJean Delvare dev_info(&client->dev, "in%d limits set dynamically " 18220e256018SJean Delvare "from VID\n", i); 18230e256018SJean Delvare } 18240e256018SJean Delvare } 18250e256018SJean Delvare 182671caf46fSJean Delvare /* Check pins that can be used for either temperature or voltage monitoring */ 182771caf46fSJean Delvare static void w83795_apply_temp_config(struct w83795_data *data, u8 config, 182871caf46fSJean Delvare int temp_chan, int in_chan) 182971caf46fSJean Delvare { 183071caf46fSJean Delvare /* config is a 2-bit value */ 183171caf46fSJean Delvare switch (config) { 183271caf46fSJean Delvare case 0x2: /* Voltage monitoring */ 183371caf46fSJean Delvare data->has_in |= 1 << in_chan; 183471caf46fSJean Delvare break; 183571caf46fSJean Delvare case 0x1: /* Thermal diode */ 183671caf46fSJean Delvare if (temp_chan >= 4) 183771caf46fSJean Delvare break; 183871caf46fSJean Delvare data->temp_mode |= 1 << temp_chan; 183971caf46fSJean Delvare /* fall through */ 184071caf46fSJean Delvare case 0x3: /* Thermistor */ 184171caf46fSJean Delvare data->has_temp |= 1 << temp_chan; 184271caf46fSJean Delvare break; 184371caf46fSJean Delvare } 184471caf46fSJean Delvare } 184571caf46fSJean Delvare 1846792d376bSWei Song static int w83795_probe(struct i2c_client *client, 1847792d376bSWei Song const struct i2c_device_id *id) 1848792d376bSWei Song { 1849792d376bSWei Song int i; 1850792d376bSWei Song u8 tmp; 1851792d376bSWei Song struct device *dev = &client->dev; 1852792d376bSWei Song struct w83795_data *data; 185371caf46fSJean Delvare int err; 1854792d376bSWei Song 1855792d376bSWei Song data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); 1856792d376bSWei Song if (!data) { 1857792d376bSWei Song err = -ENOMEM; 1858792d376bSWei Song goto exit; 1859792d376bSWei Song } 1860792d376bSWei Song 1861792d376bSWei Song i2c_set_clientdata(client, data); 1862093d1a47SJean Delvare data->chip_type = id->driver_data; 1863792d376bSWei Song data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 1864792d376bSWei Song mutex_init(&data->update_lock); 1865792d376bSWei Song 1866792d376bSWei Song /* Initialize the chip */ 1867792d376bSWei Song w83795_init_client(client); 1868792d376bSWei Song 186971caf46fSJean Delvare /* Check which voltages and fans are present */ 187071caf46fSJean Delvare data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) 187171caf46fSJean Delvare | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); 187271caf46fSJean Delvare data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) 187371caf46fSJean Delvare | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); 1874792d376bSWei Song 187571caf46fSJean Delvare /* Check which analog temperatures and extra voltages are present */ 1876792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 1877792d376bSWei Song if (tmp & 0x20) 1878792d376bSWei Song data->enable_dts = 1; 187971caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); 188071caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 4, 15); 1881792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 188271caf46fSJean Delvare w83795_apply_temp_config(data, tmp >> 6, 3, 20); 188371caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); 188471caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); 188571caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 0, 17); 1886792d376bSWei Song 1887792d376bSWei Song /* Check DTS enable status */ 188871caf46fSJean Delvare if (data->enable_dts) { 1889792d376bSWei Song if (1 & w83795_read(client, W83795_REG_DTSC)) 1890792d376bSWei Song data->enable_dts |= 2; 1891792d376bSWei Song data->has_dts = w83795_read(client, W83795_REG_DTSE); 1892792d376bSWei Song } 1893792d376bSWei Song 189454891a3cSJean Delvare /* Report PECI Tbase values */ 189554891a3cSJean Delvare if (data->enable_dts == 1) { 189654891a3cSJean Delvare for (i = 0; i < 8; i++) { 189754891a3cSJean Delvare if (!(data->has_dts & (1 << i))) 189854891a3cSJean Delvare continue; 189954891a3cSJean Delvare tmp = w83795_read(client, W83795_REG_PECI_TBASE(i)); 190054891a3cSJean Delvare dev_info(&client->dev, 190154891a3cSJean Delvare "PECI agent %d Tbase temperature: %u\n", 190254891a3cSJean Delvare i + 1, (unsigned int)tmp & 0x7f); 190354891a3cSJean Delvare } 190454891a3cSJean Delvare } 190554891a3cSJean Delvare 1906792d376bSWei Song /* First update the voltages measured value and limits */ 1907792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 1908792d376bSWei Song if (!(data->has_in & (1 << i))) 1909792d376bSWei Song continue; 1910792d376bSWei Song data->in[i][IN_MAX] = 1911792d376bSWei Song w83795_read(client, W83795_REG_IN[i][IN_MAX]); 1912792d376bSWei Song data->in[i][IN_LOW] = 1913792d376bSWei Song w83795_read(client, W83795_REG_IN[i][IN_LOW]); 1914792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 1915a654b9d4SJean Delvare tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; 1916792d376bSWei Song data->in[i][IN_READ] = tmp; 1917792d376bSWei Song } 1918cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { 1919c1a792a6SJean Delvare if ((i == 2 && data->chip_type == w83795adg) || 1920c1a792a6SJean Delvare (i >= 4 && !(data->has_in & (1 << (i + 11))))) 1921c1a792a6SJean Delvare continue; 1922792d376bSWei Song data->in_lsb[i][IN_MAX] = 1923792d376bSWei Song w83795_read(client, IN_LSB_REG(i, IN_MAX)); 1924792d376bSWei Song data->in_lsb[i][IN_LOW] = 1925792d376bSWei Song w83795_read(client, IN_LSB_REG(i, IN_LOW)); 1926792d376bSWei Song } 1927792d376bSWei Song data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 1928792d376bSWei Song 1929792d376bSWei Song /* First update fan and limits */ 1930792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 1931c1a792a6SJean Delvare /* Each register contains LSB for 2 fans, but we want to 1932c1a792a6SJean Delvare * read it only once to save time */ 1933c1a792a6SJean Delvare if ((i & 1) == 0 && (data->has_fan & (3 << i))) 1934c1a792a6SJean Delvare tmp = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); 1935c1a792a6SJean Delvare 1936792d376bSWei Song if (!(data->has_fan & (1 << i))) 1937792d376bSWei Song continue; 1938792d376bSWei Song data->fan_min[i] = 1939792d376bSWei Song w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 1940792d376bSWei Song data->fan_min[i] |= 1941c1a792a6SJean Delvare (tmp >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; 1942792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 1943a654b9d4SJean Delvare data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; 1944792d376bSWei Song } 1945792d376bSWei Song 1946792d376bSWei Song /* temperature and limits */ 1947792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 1948792d376bSWei Song if (!(data->has_temp & (1 << i))) 1949792d376bSWei Song continue; 1950792d376bSWei Song data->temp[i][TEMP_CRIT] = 1951792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT]); 1952792d376bSWei Song data->temp[i][TEMP_CRIT_HYST] = 1953792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT_HYST]); 1954792d376bSWei Song data->temp[i][TEMP_WARN] = 1955792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN]); 1956792d376bSWei Song data->temp[i][TEMP_WARN_HYST] = 1957792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]); 1958792d376bSWei Song data->temp[i][TEMP_READ] = 1959792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 1960792d376bSWei Song data->temp_read_vrlsb[i] = 1961792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 1962792d376bSWei Song } 1963792d376bSWei Song 1964792d376bSWei Song /* dts temperature and limits */ 1965792d376bSWei Song if (data->enable_dts != 0) { 1966792d376bSWei Song data->dts_ext[DTS_CRIT] = 1967792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT)); 1968792d376bSWei Song data->dts_ext[DTS_CRIT_HYST] = 1969792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT_HYST)); 1970792d376bSWei Song data->dts_ext[DTS_WARN] = 1971792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN)); 1972792d376bSWei Song data->dts_ext[DTS_WARN_HYST] = 1973792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN_HYST)); 1974792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 1975792d376bSWei Song if (!(data->has_dts & (1 << i))) 1976792d376bSWei Song continue; 1977792d376bSWei Song data->dts[i] = w83795_read(client, W83795_REG_DTS(i)); 1978792d376bSWei Song data->dts_read_vrlsb[i] = 1979792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 1980792d376bSWei Song } 1981792d376bSWei Song } 1982792d376bSWei Song 1983792d376bSWei Song /* First update temp source selction */ 1984792d376bSWei Song for (i = 0; i < 3; i++) 1985792d376bSWei Song data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 1986792d376bSWei Song 1987792d376bSWei Song /* pwm and smart fan */ 1988792d376bSWei Song if (data->chip_type == w83795g) 1989792d376bSWei Song data->has_pwm = 8; 1990792d376bSWei Song else 1991792d376bSWei Song data->has_pwm = 2; 1992792d376bSWei Song data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 1993792d376bSWei Song data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 1994cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) 1995792d376bSWei Song data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 1996792d376bSWei Song data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 1997792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 1998792d376bSWei Song for (tmp = 0; tmp < 5; tmp++) { 1999792d376bSWei Song data->pwm[i][tmp] = 2000792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, tmp)); 2001792d376bSWei Song } 2002792d376bSWei Song } 2003792d376bSWei Song for (i = 0; i < 8; i++) { 2004792d376bSWei Song data->target_speed[i] = 2005792d376bSWei Song w83795_read(client, W83795_REG_FTSH(i)) << 4; 2006792d376bSWei Song data->target_speed[i] |= 2007792d376bSWei Song w83795_read(client, W83795_REG_FTSL(i)) >> 4; 2008792d376bSWei Song } 2009792d376bSWei Song data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 2010792d376bSWei Song 2011cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { 2012792d376bSWei Song data->pwm_temp[i][TEMP_PWM_TTTI] = 2013792d376bSWei Song w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 2014792d376bSWei Song data->pwm_temp[i][TEMP_PWM_CTFS] = 2015792d376bSWei Song w83795_read(client, W83795_REG_CTFS(i)); 2016792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(i)); 2017792d376bSWei Song data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; 2018792d376bSWei Song data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 2019792d376bSWei Song } 2020cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { 2021792d376bSWei Song for (tmp = 0; tmp < 7; tmp++) { 2022792d376bSWei Song data->sf4_reg[i][SF4_TEMP][tmp] = 2023792d376bSWei Song w83795_read(client, 2024792d376bSWei Song W83795_REG_SF4_TEMP(i, tmp)); 2025792d376bSWei Song data->sf4_reg[i][SF4_PWM][tmp] = 2026792d376bSWei Song w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 2027792d376bSWei Song } 2028792d376bSWei Song } 2029792d376bSWei Song 2030792d376bSWei Song /* Setup PWM Register */ 2031792d376bSWei Song for (i = 0; i < 3; i++) { 2032792d376bSWei Song data->setup_pwm[i] = 2033792d376bSWei Song w83795_read(client, W83795_REG_SETUP_PWM(i)); 2034792d376bSWei Song } 2035792d376bSWei Song 2036792d376bSWei Song /* alarm and beep */ 2037cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->alarms); i++) { 2038792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 2039792d376bSWei Song data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); 2040792d376bSWei Song } 2041792d376bSWei Song 20426f3dcde9SJean Delvare err = w83795_handle_files(dev, device_create_file); 2043792d376bSWei Song if (err) 2044792d376bSWei Song goto exit_remove; 2045792d376bSWei Song 20460e256018SJean Delvare if (data->chip_type == w83795g) 20470e256018SJean Delvare w83795_check_dynamic_in_limits(client); 20480e256018SJean Delvare 2049792d376bSWei Song data->hwmon_dev = hwmon_device_register(dev); 2050792d376bSWei Song if (IS_ERR(data->hwmon_dev)) { 2051792d376bSWei Song err = PTR_ERR(data->hwmon_dev); 2052792d376bSWei Song goto exit_remove; 2053792d376bSWei Song } 2054792d376bSWei Song 2055792d376bSWei Song return 0; 2056792d376bSWei Song 2057792d376bSWei Song exit_remove: 20586f3dcde9SJean Delvare w83795_handle_files(dev, device_remove_file_wrapper); 2059792d376bSWei Song kfree(data); 2060792d376bSWei Song exit: 2061792d376bSWei Song return err; 2062792d376bSWei Song } 2063792d376bSWei Song 2064792d376bSWei Song static int w83795_remove(struct i2c_client *client) 2065792d376bSWei Song { 2066792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 2067792d376bSWei Song 2068792d376bSWei Song hwmon_device_unregister(data->hwmon_dev); 20696f3dcde9SJean Delvare w83795_handle_files(&client->dev, device_remove_file_wrapper); 2070792d376bSWei Song kfree(data); 2071792d376bSWei Song 2072792d376bSWei Song return 0; 2073792d376bSWei Song } 2074792d376bSWei Song 2075792d376bSWei Song 2076792d376bSWei Song static const struct i2c_device_id w83795_id[] = { 2077093d1a47SJean Delvare { "w83795g", w83795g }, 2078093d1a47SJean Delvare { "w83795adg", w83795adg }, 2079792d376bSWei Song { } 2080792d376bSWei Song }; 2081792d376bSWei Song MODULE_DEVICE_TABLE(i2c, w83795_id); 2082792d376bSWei Song 2083792d376bSWei Song static struct i2c_driver w83795_driver = { 2084792d376bSWei Song .driver = { 2085792d376bSWei Song .name = "w83795", 2086792d376bSWei Song }, 2087792d376bSWei Song .probe = w83795_probe, 2088792d376bSWei Song .remove = w83795_remove, 2089792d376bSWei Song .id_table = w83795_id, 2090792d376bSWei Song 2091792d376bSWei Song .class = I2C_CLASS_HWMON, 2092792d376bSWei Song .detect = w83795_detect, 2093792d376bSWei Song .address_list = normal_i2c, 2094792d376bSWei Song }; 2095792d376bSWei Song 2096792d376bSWei Song static int __init sensors_w83795_init(void) 2097792d376bSWei Song { 2098792d376bSWei Song return i2c_add_driver(&w83795_driver); 2099792d376bSWei Song } 2100792d376bSWei Song 2101792d376bSWei Song static void __exit sensors_w83795_exit(void) 2102792d376bSWei Song { 2103792d376bSWei Song i2c_del_driver(&w83795_driver); 2104792d376bSWei Song } 2105792d376bSWei Song 2106792d376bSWei Song MODULE_AUTHOR("Wei Song"); 2107315bacfdSJean Delvare MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 2108792d376bSWei Song MODULE_LICENSE("GPL"); 2109792d376bSWei Song 2110792d376bSWei Song module_init(sensors_w83795_init); 2111792d376bSWei Song module_exit(sensors_w83795_exit); 2112