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_CTRL_DISABLE 0 70792d376bSWei Song #define TEMP_CTRL_TD 1 71792d376bSWei Song #define TEMP_CTRL_VSEN 2 72792d376bSWei Song #define TEMP_CTRL_TR 3 73792d376bSWei Song #define TEMP_CTRL_SHIFT 4 74792d376bSWei Song #define TEMP_CTRL_HASIN_SHIFT 5 75792d376bSWei Song /* temp mode may effect VSEN17-12 (in20-15) */ 7686ef4d2fSJean Delvare static const u16 W83795_REG_TEMP_CTRL[][6] = { 77792d376bSWei Song /* Disable, TD, VSEN, TR, register shift value, has_in shift num */ 78792d376bSWei Song {0x00, 0x01, 0x02, 0x03, 0, 17}, /* TR1 */ 79792d376bSWei Song {0x00, 0x04, 0x08, 0x0C, 2, 18}, /* TR2 */ 80792d376bSWei Song {0x00, 0x10, 0x20, 0x30, 4, 19}, /* TR3 */ 81792d376bSWei Song {0x00, 0x40, 0x80, 0xC0, 6, 20}, /* TR4 */ 82792d376bSWei Song {0x00, 0x00, 0x02, 0x03, 0, 15}, /* TR5 */ 83792d376bSWei Song {0x00, 0x00, 0x08, 0x0C, 2, 16}, /* TR6 */ 84792d376bSWei Song }; 85792d376bSWei Song 86792d376bSWei Song #define TEMP_READ 0 87792d376bSWei Song #define TEMP_CRIT 1 88792d376bSWei Song #define TEMP_CRIT_HYST 2 89792d376bSWei Song #define TEMP_WARN 3 90792d376bSWei Song #define TEMP_WARN_HYST 4 91792d376bSWei Song /* only crit and crit_hyst affect real-time alarm status 92792d376bSWei Song * current crit crit_hyst warn warn_hyst */ 9386ef4d2fSJean Delvare static const u16 W83795_REG_TEMP[][5] = { 94792d376bSWei Song {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ 95792d376bSWei Song {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ 96792d376bSWei Song {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ 97792d376bSWei Song {0x24, 0xa2, 0xa3, 0xa4, 0xa5}, /* TD4/TR4 */ 98792d376bSWei Song {0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, /* TR5 */ 99792d376bSWei Song {0x20, 0xaa, 0xab, 0xac, 0xad}, /* TR6 */ 100792d376bSWei Song }; 101792d376bSWei Song 102792d376bSWei Song #define IN_READ 0 103792d376bSWei Song #define IN_MAX 1 104792d376bSWei Song #define IN_LOW 2 105792d376bSWei Song static const u16 W83795_REG_IN[][3] = { 106792d376bSWei Song /* Current, HL, LL */ 107792d376bSWei Song {0x10, 0x70, 0x71}, /* VSEN1 */ 108792d376bSWei Song {0x11, 0x72, 0x73}, /* VSEN2 */ 109792d376bSWei Song {0x12, 0x74, 0x75}, /* VSEN3 */ 110792d376bSWei Song {0x13, 0x76, 0x77}, /* VSEN4 */ 111792d376bSWei Song {0x14, 0x78, 0x79}, /* VSEN5 */ 112792d376bSWei Song {0x15, 0x7a, 0x7b}, /* VSEN6 */ 113792d376bSWei Song {0x16, 0x7c, 0x7d}, /* VSEN7 */ 114792d376bSWei Song {0x17, 0x7e, 0x7f}, /* VSEN8 */ 115792d376bSWei Song {0x18, 0x80, 0x81}, /* VSEN9 */ 116792d376bSWei Song {0x19, 0x82, 0x83}, /* VSEN10 */ 117792d376bSWei Song {0x1A, 0x84, 0x85}, /* VSEN11 */ 118792d376bSWei Song {0x1B, 0x86, 0x87}, /* VTT */ 119792d376bSWei Song {0x1C, 0x88, 0x89}, /* 3VDD */ 120792d376bSWei Song {0x1D, 0x8a, 0x8b}, /* 3VSB */ 121792d376bSWei Song {0x1E, 0x8c, 0x8d}, /* VBAT */ 122792d376bSWei Song {0x1F, 0xa6, 0xa7}, /* VSEN12 */ 123792d376bSWei Song {0x20, 0xaa, 0xab}, /* VSEN13 */ 124792d376bSWei Song {0x21, 0x96, 0x97}, /* VSEN14 */ 125792d376bSWei Song {0x22, 0x9a, 0x9b}, /* VSEN15 */ 126792d376bSWei Song {0x23, 0x9e, 0x9f}, /* VSEN16 */ 127792d376bSWei Song {0x24, 0xa2, 0xa3}, /* VSEN17 */ 128792d376bSWei Song }; 129792d376bSWei Song #define W83795_REG_VRLSB 0x3C 130792d376bSWei Song #define VRLSB_SHIFT 6 131792d376bSWei Song 132792d376bSWei Song static const u8 W83795_REG_IN_HL_LSB[] = { 133792d376bSWei Song 0x8e, /* VSEN1-4 */ 134792d376bSWei Song 0x90, /* VSEN5-8 */ 135792d376bSWei Song 0x92, /* VSEN9-11 */ 136792d376bSWei Song 0x94, /* VTT, 3VDD, 3VSB, 3VBAT */ 137792d376bSWei Song 0xa8, /* VSEN12 */ 138792d376bSWei Song 0xac, /* VSEN13 */ 139792d376bSWei Song 0x98, /* VSEN14 */ 140792d376bSWei Song 0x9c, /* VSEN15 */ 141792d376bSWei Song 0xa0, /* VSEN16 */ 142792d376bSWei Song 0xa4, /* VSEN17 */ 143792d376bSWei Song }; 144792d376bSWei Song 145792d376bSWei Song #define IN_LSB_REG(index, type) \ 146792d376bSWei Song (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ 147792d376bSWei Song : (W83795_REG_IN_HL_LSB[(index)] + 1)) 148792d376bSWei Song 149792d376bSWei Song #define IN_LSB_REG_NUM 10 150792d376bSWei Song 151792d376bSWei Song #define IN_LSB_SHIFT 0 152792d376bSWei Song #define IN_LSB_IDX 1 153792d376bSWei Song static const u8 IN_LSB_SHIFT_IDX[][2] = { 154792d376bSWei Song /* High/Low LSB shift, LSB No. */ 155792d376bSWei Song {0x00, 0x00}, /* VSEN1 */ 156792d376bSWei Song {0x02, 0x00}, /* VSEN2 */ 157792d376bSWei Song {0x04, 0x00}, /* VSEN3 */ 158792d376bSWei Song {0x06, 0x00}, /* VSEN4 */ 159792d376bSWei Song {0x00, 0x01}, /* VSEN5 */ 160792d376bSWei Song {0x02, 0x01}, /* VSEN6 */ 161792d376bSWei Song {0x04, 0x01}, /* VSEN7 */ 162792d376bSWei Song {0x06, 0x01}, /* VSEN8 */ 163792d376bSWei Song {0x00, 0x02}, /* VSEN9 */ 164792d376bSWei Song {0x02, 0x02}, /* VSEN10 */ 165792d376bSWei Song {0x04, 0x02}, /* VSEN11 */ 166792d376bSWei Song {0x00, 0x03}, /* VTT */ 167792d376bSWei Song {0x02, 0x03}, /* 3VDD */ 168792d376bSWei Song {0x04, 0x03}, /* 3VSB */ 169792d376bSWei Song {0x06, 0x03}, /* VBAT */ 170792d376bSWei Song {0x06, 0x04}, /* VSEN12 */ 171792d376bSWei Song {0x06, 0x05}, /* VSEN13 */ 172792d376bSWei Song {0x06, 0x06}, /* VSEN14 */ 173792d376bSWei Song {0x06, 0x07}, /* VSEN15 */ 174792d376bSWei Song {0x06, 0x08}, /* VSEN16 */ 175792d376bSWei Song {0x06, 0x09}, /* VSEN17 */ 176792d376bSWei Song }; 177792d376bSWei Song 178792d376bSWei Song 179792d376bSWei Song /* 3VDD, 3VSB, VBAT * 0.006 */ 180792d376bSWei Song #define REST_VLT_BEGIN 12 /* the 13th volt to 15th */ 181792d376bSWei Song #define REST_VLT_END 14 /* the 13th volt to 15th */ 182792d376bSWei Song 183792d376bSWei Song #define W83795_REG_FAN(index) (0x2E + (index)) 184792d376bSWei Song #define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) 185792d376bSWei Song #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) 186792d376bSWei Song #define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ 187792d376bSWei Song (((index) % 1) ? 4 : 0) 188792d376bSWei Song 189792d376bSWei Song #define W83795_REG_VID_CTRL 0x6A 190792d376bSWei Song 191792d376bSWei Song #define ALARM_BEEP_REG_NUM 6 192792d376bSWei Song #define W83795_REG_ALARM(index) (0x41 + (index)) 193792d376bSWei Song #define W83795_REG_BEEP(index) (0x50 + (index)) 194792d376bSWei Song 195792d376bSWei Song #define W83795_REG_CLR_CHASSIS 0x4D 196792d376bSWei Song 197792d376bSWei Song 198792d376bSWei Song #define W83795_REG_TEMP_NUM 6 199792d376bSWei Song #define W83795_REG_FCMS1 0x201 200792d376bSWei Song #define W83795_REG_FCMS2 0x208 201792d376bSWei Song #define W83795_REG_TFMR(index) (0x202 + (index)) 202792d376bSWei Song #define W83795_REG_FOMC 0x20F 203792d376bSWei Song #define W83795_REG_FOPFP(index) (0x218 + (index)) 204792d376bSWei Song 205792d376bSWei Song #define W83795_REG_TSS(index) (0x209 + (index)) 206792d376bSWei Song 207792d376bSWei Song #define PWM_OUTPUT 0 208792d376bSWei Song #define PWM_START 1 209792d376bSWei Song #define PWM_NONSTOP 2 210792d376bSWei Song #define PWM_STOP_TIME 3 211792d376bSWei Song #define PWM_DIV 4 212792d376bSWei Song #define W83795_REG_PWM(index, nr) \ 213792d376bSWei Song (((nr) == 0 ? 0x210 : \ 214792d376bSWei Song (nr) == 1 ? 0x220 : \ 215792d376bSWei Song (nr) == 2 ? 0x228 : \ 216792d376bSWei Song (nr) == 3 ? 0x230 : 0x218) + (index)) 217792d376bSWei Song 218792d376bSWei Song #define W83795_REG_FOPFP_DIV(index) \ 219792d376bSWei Song (((index) < 8) ? ((index) + 1) : \ 220792d376bSWei Song ((index) == 8) ? 12 : \ 221792d376bSWei Song (16 << ((index) - 9))) 222792d376bSWei Song 223792d376bSWei Song #define W83795_REG_FTSH(index) (0x240 + (index) * 2) 224792d376bSWei Song #define W83795_REG_FTSL(index) (0x241 + (index) * 2) 225792d376bSWei Song #define W83795_REG_TFTS 0x250 226792d376bSWei Song 227792d376bSWei Song #define TEMP_PWM_TTTI 0 228792d376bSWei Song #define TEMP_PWM_CTFS 1 229792d376bSWei Song #define TEMP_PWM_HCT 2 230792d376bSWei Song #define TEMP_PWM_HOT 3 231792d376bSWei Song #define W83795_REG_TTTI(index) (0x260 + (index)) 232792d376bSWei Song #define W83795_REG_CTFS(index) (0x268 + (index)) 233792d376bSWei Song #define W83795_REG_HT(index) (0x270 + (index)) 234792d376bSWei Song 235792d376bSWei Song #define SF4_TEMP 0 236792d376bSWei Song #define SF4_PWM 1 237792d376bSWei Song #define W83795_REG_SF4_TEMP(temp_num, index) \ 238792d376bSWei Song (0x280 + 0x10 * (temp_num) + (index)) 239792d376bSWei Song #define W83795_REG_SF4_PWM(temp_num, index) \ 240792d376bSWei Song (0x288 + 0x10 * (temp_num) + (index)) 241792d376bSWei Song 242792d376bSWei Song #define W83795_REG_DTSC 0x301 243792d376bSWei Song #define W83795_REG_DTSE 0x302 244792d376bSWei Song #define W83795_REG_DTS(index) (0x26 + (index)) 245792d376bSWei Song 246792d376bSWei Song #define DTS_CRIT 0 247792d376bSWei Song #define DTS_CRIT_HYST 1 248792d376bSWei Song #define DTS_WARN 2 249792d376bSWei Song #define DTS_WARN_HYST 3 250792d376bSWei Song #define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 251792d376bSWei Song 252792d376bSWei Song #define SETUP_PWM_DEFAULT 0 253792d376bSWei Song #define SETUP_PWM_UPTIME 1 254792d376bSWei Song #define SETUP_PWM_DOWNTIME 2 255792d376bSWei Song #define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 256792d376bSWei Song 257792d376bSWei Song static inline u16 in_from_reg(u8 index, u16 val) 258792d376bSWei Song { 259792d376bSWei Song if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) 260792d376bSWei Song return val * 6; 261792d376bSWei Song else 262792d376bSWei Song return val * 2; 263792d376bSWei Song } 264792d376bSWei Song 265792d376bSWei Song static inline u16 in_to_reg(u8 index, u16 val) 266792d376bSWei Song { 267792d376bSWei Song if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) 268792d376bSWei Song return val / 6; 269792d376bSWei Song else 270792d376bSWei Song return val / 2; 271792d376bSWei Song } 272792d376bSWei Song 273792d376bSWei Song static inline unsigned long fan_from_reg(u16 val) 274792d376bSWei Song { 275792d376bSWei Song if ((val >= 0xff0) || (val == 0)) 276792d376bSWei Song return 0; 277792d376bSWei Song return 1350000UL / val; 278792d376bSWei Song } 279792d376bSWei Song 280792d376bSWei Song static inline u16 fan_to_reg(long rpm) 281792d376bSWei Song { 282792d376bSWei Song if (rpm <= 0) 283792d376bSWei Song return 0x0fff; 284792d376bSWei Song return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 285792d376bSWei Song } 286792d376bSWei Song 287792d376bSWei Song static inline unsigned long time_from_reg(u8 reg) 288792d376bSWei Song { 289792d376bSWei Song return reg * 100; 290792d376bSWei Song } 291792d376bSWei Song 292792d376bSWei Song static inline u8 time_to_reg(unsigned long val) 293792d376bSWei Song { 294792d376bSWei Song return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); 295792d376bSWei Song } 296792d376bSWei Song 297792d376bSWei Song static inline long temp_from_reg(s8 reg) 298792d376bSWei Song { 299792d376bSWei Song return reg * 1000; 300792d376bSWei Song } 301792d376bSWei Song 302792d376bSWei Song static inline s8 temp_to_reg(long val, s8 min, s8 max) 303792d376bSWei Song { 304792d376bSWei Song return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); 305792d376bSWei Song } 306792d376bSWei Song 307792d376bSWei Song 308792d376bSWei Song enum chip_types {w83795g, w83795adg}; 309792d376bSWei Song 310792d376bSWei Song struct w83795_data { 311792d376bSWei Song struct device *hwmon_dev; 312792d376bSWei Song struct mutex update_lock; 313792d376bSWei Song unsigned long last_updated; /* In jiffies */ 314792d376bSWei Song enum chip_types chip_type; 315792d376bSWei Song 316792d376bSWei Song u8 bank; 317792d376bSWei Song 318792d376bSWei Song u32 has_in; /* Enable monitor VIN or not */ 319792d376bSWei Song u16 in[21][3]; /* Register value, read/high/low */ 320792d376bSWei Song u8 in_lsb[10][3]; /* LSB Register value, high/low */ 321792d376bSWei Song u8 has_gain; /* has gain: in17-20 * 8 */ 322792d376bSWei Song 323792d376bSWei Song u16 has_fan; /* Enable fan14-1 or not */ 324792d376bSWei Song u16 fan[14]; /* Register value combine */ 325792d376bSWei Song u16 fan_min[14]; /* Register value combine */ 326792d376bSWei Song 327792d376bSWei Song u8 has_temp; /* Enable monitor temp6-1 or not */ 328792d376bSWei Song u8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 329792d376bSWei Song u8 temp_read_vrlsb[6]; 330792d376bSWei Song u8 temp_mode; /* bit 0: TR mode, bit 1: TD mode */ 331792d376bSWei Song u8 temp_src[3]; /* Register value */ 332792d376bSWei Song 333792d376bSWei Song u8 enable_dts; /* Enable PECI and SB-TSI, 334792d376bSWei Song * bit 0: =1 enable, =0 disable, 335792d376bSWei Song * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ 336792d376bSWei Song u8 has_dts; /* Enable monitor DTS temp */ 337792d376bSWei Song u8 dts[8]; /* Register value */ 338792d376bSWei Song u8 dts_read_vrlsb[8]; /* Register value */ 339792d376bSWei Song u8 dts_ext[4]; /* Register value */ 340792d376bSWei Song 341792d376bSWei Song u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, 342792d376bSWei Song * no config register, only affected by chip 343792d376bSWei Song * type */ 344792d376bSWei Song u8 pwm[8][5]; /* Register value, output, start, non stop, stop 345792d376bSWei Song * time, div */ 346792d376bSWei Song u8 pwm_fcms[2]; /* Register value */ 347792d376bSWei Song u8 pwm_tfmr[6]; /* Register value */ 348792d376bSWei Song u8 pwm_fomc; /* Register value */ 349792d376bSWei Song 350792d376bSWei Song u16 target_speed[8]; /* Register value, target speed for speed 351792d376bSWei Song * cruise */ 352792d376bSWei Song u8 tol_speed; /* tolerance of target speed */ 353792d376bSWei Song u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 354792d376bSWei Song u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 355792d376bSWei Song 356792d376bSWei Song u8 setup_pwm[3]; /* Register value */ 357792d376bSWei Song 358792d376bSWei Song u8 alarms[6]; /* Register value */ 359792d376bSWei Song u8 beeps[6]; /* Register value */ 360792d376bSWei Song u8 beep_enable; 361792d376bSWei Song 362792d376bSWei Song char valid; 363792d376bSWei Song }; 364792d376bSWei Song 365792d376bSWei Song /* 366792d376bSWei Song * Hardware access 367b2469f42SJean Delvare * We assume that nobdody can change the bank outside the driver. 368792d376bSWei Song */ 369792d376bSWei Song 370b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 371b2469f42SJean Delvare static int w83795_set_bank(struct i2c_client *client, u8 bank) 372792d376bSWei Song { 373792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 374b2469f42SJean Delvare int err; 375792d376bSWei Song 376b2469f42SJean Delvare /* If the same bank is already set, nothing to do */ 377b2469f42SJean Delvare if ((data->bank & 0x07) == bank) 378b2469f42SJean Delvare return 0; 379b2469f42SJean Delvare 380b2469f42SJean Delvare /* Change to new bank, preserve all other bits */ 381b2469f42SJean Delvare bank |= data->bank & ~0x07; 382b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 383b2469f42SJean Delvare if (err < 0) { 384792d376bSWei Song dev_err(&client->dev, 385b2469f42SJean Delvare "Failed to set bank to %d, err %d\n", 386b2469f42SJean Delvare (int)bank, err); 387b2469f42SJean Delvare return err; 388792d376bSWei Song } 389b2469f42SJean Delvare data->bank = bank; 390b2469f42SJean Delvare 391b2469f42SJean Delvare return 0; 392792d376bSWei Song } 393b2469f42SJean Delvare 394b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 395b2469f42SJean Delvare static u8 w83795_read(struct i2c_client *client, u16 reg) 396b2469f42SJean Delvare { 397b2469f42SJean Delvare int err; 398b2469f42SJean Delvare 399b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 400b2469f42SJean Delvare if (err < 0) 401b2469f42SJean Delvare return 0x00; /* Arbitrary */ 402b2469f42SJean Delvare 403b2469f42SJean Delvare err = i2c_smbus_read_byte_data(client, reg & 0xff); 404b2469f42SJean Delvare if (err < 0) { 405b2469f42SJean Delvare dev_err(&client->dev, 406b2469f42SJean Delvare "Failed to read from register 0x%03x, err %d\n", 407b2469f42SJean Delvare (int)reg, err); 408b2469f42SJean Delvare return 0x00; /* Arbitrary */ 409b2469f42SJean Delvare } 410b2469f42SJean Delvare return err; 411792d376bSWei Song } 412792d376bSWei Song 413792d376bSWei Song /* Must be called with data->update_lock held, except during initialization */ 414792d376bSWei Song static int w83795_write(struct i2c_client *client, u16 reg, u8 value) 415792d376bSWei Song { 416b2469f42SJean Delvare int err; 417792d376bSWei Song 418b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 419b2469f42SJean Delvare if (err < 0) 420b2469f42SJean Delvare return err; 421b2469f42SJean Delvare 422b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 423b2469f42SJean Delvare if (err < 0) 424792d376bSWei Song dev_err(&client->dev, 425b2469f42SJean Delvare "Failed to write to register 0x%03x, err %d\n", 426b2469f42SJean Delvare (int)reg, err); 427b2469f42SJean Delvare return err; 428792d376bSWei Song } 429792d376bSWei Song 430792d376bSWei Song static struct w83795_data *w83795_update_device(struct device *dev) 431792d376bSWei Song { 432792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 433792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 434792d376bSWei Song u16 tmp; 435792d376bSWei Song int i; 436792d376bSWei Song 437792d376bSWei Song mutex_lock(&data->update_lock); 438792d376bSWei Song 439792d376bSWei Song if (!(time_after(jiffies, data->last_updated + HZ * 2) 440792d376bSWei Song || !data->valid)) 441792d376bSWei Song goto END; 442792d376bSWei Song 443792d376bSWei Song /* Update the voltages value */ 444792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 445792d376bSWei Song if (!(data->has_in & (1 << i))) 446792d376bSWei Song continue; 447792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 448792d376bSWei Song tmp |= (w83795_read(client, W83795_REG_VRLSB) 449792d376bSWei Song >> VRLSB_SHIFT) & 0x03; 450792d376bSWei Song data->in[i][IN_READ] = tmp; 451792d376bSWei Song } 452792d376bSWei Song 453792d376bSWei Song /* Update fan */ 454792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 455792d376bSWei Song if (!(data->has_fan & (1 << i))) 456792d376bSWei Song continue; 457792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 458792d376bSWei Song data->fan[i] |= 459792d376bSWei Song (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F; 460792d376bSWei Song } 461792d376bSWei Song 462792d376bSWei Song /* Update temperature */ 463792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 464792d376bSWei Song /* even stop monitor, register still keep value, just read out 465792d376bSWei Song * it */ 466792d376bSWei Song if (!(data->has_temp & (1 << i))) { 467792d376bSWei Song data->temp[i][TEMP_READ] = 0; 468792d376bSWei Song data->temp_read_vrlsb[i] = 0; 469792d376bSWei Song continue; 470792d376bSWei Song } 471792d376bSWei Song data->temp[i][TEMP_READ] = 472792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 473792d376bSWei Song data->temp_read_vrlsb[i] = 474792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 475792d376bSWei Song } 476792d376bSWei Song 477792d376bSWei Song /* Update dts temperature */ 478792d376bSWei Song if (data->enable_dts != 0) { 479792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 480792d376bSWei Song if (!(data->has_dts & (1 << i))) 481792d376bSWei Song continue; 482792d376bSWei Song data->dts[i] = 483792d376bSWei Song w83795_read(client, W83795_REG_DTS(i)); 484792d376bSWei Song data->dts_read_vrlsb[i] = 485792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 486792d376bSWei Song } 487792d376bSWei Song } 488792d376bSWei Song 489792d376bSWei Song /* Update pwm output */ 490792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 491792d376bSWei Song data->pwm[i][PWM_OUTPUT] = 492792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 493792d376bSWei Song } 494792d376bSWei Song 495792d376bSWei Song /* update alarm */ 496792d376bSWei Song for (i = 0; i < ALARM_BEEP_REG_NUM; i++) 497792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 498792d376bSWei Song 499792d376bSWei Song data->last_updated = jiffies; 500792d376bSWei Song data->valid = 1; 501792d376bSWei Song 502792d376bSWei Song END: 503792d376bSWei Song mutex_unlock(&data->update_lock); 504792d376bSWei Song return data; 505792d376bSWei Song } 506792d376bSWei Song 507792d376bSWei Song /* 508792d376bSWei Song * Sysfs attributes 509792d376bSWei Song */ 510792d376bSWei Song 511792d376bSWei Song #define ALARM_STATUS 0 512792d376bSWei Song #define BEEP_ENABLE 1 513792d376bSWei Song static ssize_t 514792d376bSWei Song show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 515792d376bSWei Song { 516792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 517792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 518792d376bSWei Song to_sensor_dev_attr_2(attr); 519792d376bSWei Song int nr = sensor_attr->nr; 520792d376bSWei Song int index = sensor_attr->index >> 3; 521792d376bSWei Song int bit = sensor_attr->index & 0x07; 522792d376bSWei Song u8 val; 523792d376bSWei Song 524792d376bSWei Song if (ALARM_STATUS == nr) { 525792d376bSWei Song val = (data->alarms[index] >> (bit)) & 1; 526792d376bSWei Song } else { /* BEEP_ENABLE */ 527792d376bSWei Song val = (data->beeps[index] >> (bit)) & 1; 528792d376bSWei Song } 529792d376bSWei Song 530792d376bSWei Song return sprintf(buf, "%u\n", val); 531792d376bSWei Song } 532792d376bSWei Song 533792d376bSWei Song static ssize_t 534792d376bSWei Song store_beep(struct device *dev, struct device_attribute *attr, 535792d376bSWei Song const char *buf, size_t count) 536792d376bSWei Song { 537792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 538792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 539792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 540792d376bSWei Song to_sensor_dev_attr_2(attr); 541792d376bSWei Song int index = sensor_attr->index >> 3; 542792d376bSWei Song int shift = sensor_attr->index & 0x07; 543792d376bSWei Song u8 beep_bit = 1 << shift; 544792d376bSWei Song unsigned long val; 545792d376bSWei Song 546792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 547792d376bSWei Song return -EINVAL; 548792d376bSWei Song if (val != 0 && val != 1) 549792d376bSWei Song return -EINVAL; 550792d376bSWei Song 551792d376bSWei Song mutex_lock(&data->update_lock); 552792d376bSWei Song data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 553792d376bSWei Song data->beeps[index] &= ~beep_bit; 554792d376bSWei Song data->beeps[index] |= val << shift; 555792d376bSWei Song w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 556792d376bSWei Song mutex_unlock(&data->update_lock); 557792d376bSWei Song 558792d376bSWei Song return count; 559792d376bSWei Song } 560792d376bSWei Song 561792d376bSWei Song static ssize_t 562792d376bSWei Song show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf) 563792d376bSWei Song { 564792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 565792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 566792d376bSWei Song return sprintf(buf, "%u\n", data->beep_enable); 567792d376bSWei Song } 568792d376bSWei Song 569792d376bSWei Song static ssize_t 570792d376bSWei Song store_beep_enable(struct device *dev, struct device_attribute *attr, 571792d376bSWei Song const char *buf, size_t count) 572792d376bSWei Song { 573792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 574792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 575792d376bSWei Song unsigned long val; 576792d376bSWei Song u8 tmp; 577792d376bSWei Song 578792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 579792d376bSWei Song return -EINVAL; 580792d376bSWei Song if (val != 0 && val != 1) 581792d376bSWei Song return -EINVAL; 582792d376bSWei Song 583792d376bSWei Song mutex_lock(&data->update_lock); 584792d376bSWei Song data->beep_enable = val; 585792d376bSWei Song tmp = w83795_read(client, W83795_REG_BEEP(5)); 586792d376bSWei Song tmp &= 0x7f; 587792d376bSWei Song tmp |= val << 7; 588792d376bSWei Song w83795_write(client, W83795_REG_BEEP(5), tmp); 589792d376bSWei Song mutex_unlock(&data->update_lock); 590792d376bSWei Song 591792d376bSWei Song return count; 592792d376bSWei Song } 593792d376bSWei Song 594792d376bSWei Song /* Write any value to clear chassis alarm */ 595792d376bSWei Song static ssize_t 596792d376bSWei Song store_chassis_clear(struct device *dev, 597792d376bSWei Song struct device_attribute *attr, const char *buf, 598792d376bSWei Song size_t count) 599792d376bSWei Song { 600792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 601792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 602792d376bSWei Song u8 val; 603792d376bSWei Song 604792d376bSWei Song mutex_lock(&data->update_lock); 605792d376bSWei Song val = w83795_read(client, W83795_REG_CLR_CHASSIS); 606792d376bSWei Song val |= 0x80; 607792d376bSWei Song w83795_write(client, W83795_REG_CLR_CHASSIS, val); 608792d376bSWei Song mutex_unlock(&data->update_lock); 609792d376bSWei Song return count; 610792d376bSWei Song } 611792d376bSWei Song 612792d376bSWei Song #define FAN_INPUT 0 613792d376bSWei Song #define FAN_MIN 1 614792d376bSWei Song static ssize_t 615792d376bSWei Song show_fan(struct device *dev, struct device_attribute *attr, char *buf) 616792d376bSWei Song { 617792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 618792d376bSWei Song to_sensor_dev_attr_2(attr); 619792d376bSWei Song int nr = sensor_attr->nr; 620792d376bSWei Song int index = sensor_attr->index; 621792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 622792d376bSWei Song u16 val; 623792d376bSWei Song 624792d376bSWei Song if (FAN_INPUT == nr) 625792d376bSWei Song val = data->fan[index] & 0x0fff; 626792d376bSWei Song else 627792d376bSWei Song val = data->fan_min[index] & 0x0fff; 628792d376bSWei Song 629792d376bSWei Song return sprintf(buf, "%lu\n", fan_from_reg(val)); 630792d376bSWei Song } 631792d376bSWei Song 632792d376bSWei Song static ssize_t 633792d376bSWei Song store_fan_min(struct device *dev, struct device_attribute *attr, 634792d376bSWei Song const char *buf, size_t count) 635792d376bSWei Song { 636792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 637792d376bSWei Song to_sensor_dev_attr_2(attr); 638792d376bSWei Song int index = sensor_attr->index; 639792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 640792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 641792d376bSWei Song unsigned long val; 642792d376bSWei Song 643792d376bSWei Song if (strict_strtoul(buf, 10, &val)) 644792d376bSWei Song return -EINVAL; 645792d376bSWei Song val = fan_to_reg(val); 646792d376bSWei Song 647792d376bSWei Song mutex_lock(&data->update_lock); 648792d376bSWei Song data->fan_min[index] = val; 649792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 650792d376bSWei Song val &= 0x0f; 651792d376bSWei Song if (index % 1) { 652792d376bSWei Song val <<= 4; 653792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 654792d376bSWei Song & 0x0f; 655792d376bSWei Song } else { 656792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 657792d376bSWei Song & 0xf0; 658792d376bSWei Song } 659792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 660792d376bSWei Song mutex_unlock(&data->update_lock); 661792d376bSWei Song 662792d376bSWei Song return count; 663792d376bSWei Song } 664792d376bSWei Song 665792d376bSWei Song static ssize_t 666792d376bSWei Song show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 667792d376bSWei Song { 668792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 669792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 670792d376bSWei Song to_sensor_dev_attr_2(attr); 671792d376bSWei Song int nr = sensor_attr->nr; 672792d376bSWei Song int index = sensor_attr->index; 673792d376bSWei Song u16 val; 674792d376bSWei Song 675792d376bSWei Song switch (nr) { 676792d376bSWei Song case PWM_STOP_TIME: 677792d376bSWei Song val = time_from_reg(data->pwm[index][nr]); 678792d376bSWei Song break; 679792d376bSWei Song case PWM_DIV: 680792d376bSWei Song val = W83795_REG_FOPFP_DIV(data->pwm[index][nr] & 0x0f); 681792d376bSWei Song break; 682792d376bSWei Song default: 683792d376bSWei Song val = data->pwm[index][nr]; 684792d376bSWei Song break; 685792d376bSWei Song } 686792d376bSWei Song 687792d376bSWei Song return sprintf(buf, "%u\n", val); 688792d376bSWei Song } 689792d376bSWei Song 690792d376bSWei Song static ssize_t 691792d376bSWei Song store_pwm(struct device *dev, struct device_attribute *attr, 692792d376bSWei Song const char *buf, size_t count) 693792d376bSWei Song { 694792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 695792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 696792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 697792d376bSWei Song to_sensor_dev_attr_2(attr); 698792d376bSWei Song int nr = sensor_attr->nr; 699792d376bSWei Song int index = sensor_attr->index; 700792d376bSWei Song unsigned long val; 701792d376bSWei Song int i; 702792d376bSWei Song 703792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 704792d376bSWei Song return -EINVAL; 705792d376bSWei Song 706792d376bSWei Song mutex_lock(&data->update_lock); 707792d376bSWei Song switch (nr) { 708792d376bSWei Song case PWM_STOP_TIME: 709792d376bSWei Song val = time_to_reg(val); 710792d376bSWei Song break; 711792d376bSWei Song case PWM_DIV: 712792d376bSWei Song for (i = 0; i < 16; i++) { 713792d376bSWei Song if (W83795_REG_FOPFP_DIV(i) == val) { 714792d376bSWei Song val = i; 715792d376bSWei Song break; 716792d376bSWei Song } 717792d376bSWei Song } 718792d376bSWei Song if (i >= 16) 719792d376bSWei Song goto err_end; 720792d376bSWei Song val |= w83795_read(client, W83795_REG_PWM(index, nr)) & 0x80; 721792d376bSWei Song break; 722792d376bSWei Song default: 723792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 724792d376bSWei Song break; 725792d376bSWei Song } 726792d376bSWei Song w83795_write(client, W83795_REG_PWM(index, nr), val); 727792d376bSWei Song data->pwm[index][nr] = val & 0xff; 728792d376bSWei Song mutex_unlock(&data->update_lock); 729792d376bSWei Song return count; 730792d376bSWei Song err_end: 731792d376bSWei Song mutex_unlock(&data->update_lock); 732792d376bSWei Song return -EINVAL; 733792d376bSWei Song } 734792d376bSWei Song 735792d376bSWei Song static ssize_t 736792d376bSWei Song show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 737792d376bSWei Song { 738792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 739792d376bSWei Song to_sensor_dev_attr_2(attr); 740792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 741792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 742792d376bSWei Song int index = sensor_attr->index; 743792d376bSWei Song u8 tmp; 744792d376bSWei Song 745792d376bSWei Song if (1 == (data->pwm_fcms[0] & (1 << index))) { 746792d376bSWei Song tmp = 2; 747792d376bSWei Song goto out; 748792d376bSWei Song } 749792d376bSWei Song for (tmp = 0; tmp < 6; tmp++) { 750792d376bSWei Song if (data->pwm_tfmr[tmp] & (1 << index)) { 751792d376bSWei Song tmp = 3; 752792d376bSWei Song goto out; 753792d376bSWei Song } 754792d376bSWei Song } 755792d376bSWei Song if (data->pwm_fomc & (1 << index)) 756792d376bSWei Song tmp = 0; 757792d376bSWei Song else 758792d376bSWei Song tmp = 1; 759792d376bSWei Song 760792d376bSWei Song out: 761792d376bSWei Song return sprintf(buf, "%u\n", tmp); 762792d376bSWei Song } 763792d376bSWei Song 764792d376bSWei Song static ssize_t 765792d376bSWei Song store_pwm_enable(struct device *dev, struct device_attribute *attr, 766792d376bSWei Song const char *buf, size_t count) 767792d376bSWei Song { 768792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 769792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 770792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 771792d376bSWei Song to_sensor_dev_attr_2(attr); 772792d376bSWei Song int index = sensor_attr->index; 773792d376bSWei Song unsigned long val; 774792d376bSWei Song int i; 775792d376bSWei Song 776792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 777792d376bSWei Song return -EINVAL; 778792d376bSWei Song if (val > 2) 779792d376bSWei Song return -EINVAL; 780792d376bSWei Song 781792d376bSWei Song mutex_lock(&data->update_lock); 782792d376bSWei Song switch (val) { 783792d376bSWei Song case 0: 784792d376bSWei Song case 1: 785792d376bSWei Song data->pwm_fcms[0] &= ~(1 << index); 786792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 787792d376bSWei Song for (i = 0; i < 6; i++) { 788792d376bSWei Song data->pwm_tfmr[i] &= ~(1 << index); 789792d376bSWei Song w83795_write(client, W83795_REG_TFMR(i), 790792d376bSWei Song data->pwm_tfmr[i]); 791792d376bSWei Song } 792792d376bSWei Song data->pwm_fomc |= 1 << index; 793792d376bSWei Song data->pwm_fomc ^= val << index; 794792d376bSWei Song w83795_write(client, W83795_REG_FOMC, data->pwm_fomc); 795792d376bSWei Song break; 796792d376bSWei Song case 2: 797792d376bSWei Song data->pwm_fcms[0] |= (1 << index); 798792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 799792d376bSWei Song break; 800792d376bSWei Song } 801792d376bSWei Song mutex_unlock(&data->update_lock); 802792d376bSWei Song return count; 803792d376bSWei Song } 804792d376bSWei Song 805792d376bSWei Song static ssize_t 806792d376bSWei Song show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 807792d376bSWei Song { 808792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 809792d376bSWei Song to_sensor_dev_attr_2(attr); 810792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 811792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 812792d376bSWei Song int index = sensor_attr->index; 813792d376bSWei Song u8 val = index / 2; 814792d376bSWei Song u8 tmp = data->temp_src[val]; 815792d376bSWei Song 816792d376bSWei Song if (index % 1) 817792d376bSWei Song val = 4; 818792d376bSWei Song else 819792d376bSWei Song val = 0; 820792d376bSWei Song tmp >>= val; 821792d376bSWei Song tmp &= 0x0f; 822792d376bSWei Song 823792d376bSWei Song return sprintf(buf, "%u\n", tmp); 824792d376bSWei Song } 825792d376bSWei Song 826792d376bSWei Song static ssize_t 827792d376bSWei Song store_temp_src(struct device *dev, struct device_attribute *attr, 828792d376bSWei Song const char *buf, size_t count) 829792d376bSWei Song { 830792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 831792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 832792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 833792d376bSWei Song to_sensor_dev_attr_2(attr); 834792d376bSWei Song int index = sensor_attr->index; 835792d376bSWei Song unsigned long tmp; 836792d376bSWei Song u8 val = index / 2; 837792d376bSWei Song 838792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 839792d376bSWei Song return -EINVAL; 840792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 15); 841792d376bSWei Song 842792d376bSWei Song mutex_lock(&data->update_lock); 843792d376bSWei Song if (index % 1) { 844792d376bSWei Song tmp <<= 4; 845792d376bSWei Song data->temp_src[val] &= 0x0f; 846792d376bSWei Song } else { 847792d376bSWei Song data->temp_src[val] &= 0xf0; 848792d376bSWei Song } 849792d376bSWei Song data->temp_src[val] |= tmp; 850792d376bSWei Song w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 851792d376bSWei Song mutex_unlock(&data->update_lock); 852792d376bSWei Song 853792d376bSWei Song return count; 854792d376bSWei Song } 855792d376bSWei Song 856792d376bSWei Song #define TEMP_PWM_ENABLE 0 857792d376bSWei Song #define TEMP_PWM_FAN_MAP 1 858792d376bSWei Song static ssize_t 859792d376bSWei Song show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 860792d376bSWei Song char *buf) 861792d376bSWei Song { 862792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 863792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 864792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 865792d376bSWei Song to_sensor_dev_attr_2(attr); 866792d376bSWei Song int nr = sensor_attr->nr; 867792d376bSWei Song int index = sensor_attr->index; 868792d376bSWei Song u8 tmp = 0xff; 869792d376bSWei Song 870792d376bSWei Song switch (nr) { 871792d376bSWei Song case TEMP_PWM_ENABLE: 872792d376bSWei Song tmp = (data->pwm_fcms[1] >> index) & 1; 873792d376bSWei Song if (tmp) 874792d376bSWei Song tmp = 4; 875792d376bSWei Song else 876792d376bSWei Song tmp = 3; 877792d376bSWei Song break; 878792d376bSWei Song case TEMP_PWM_FAN_MAP: 879792d376bSWei Song tmp = data->pwm_tfmr[index]; 880792d376bSWei Song break; 881792d376bSWei Song } 882792d376bSWei Song 883792d376bSWei Song return sprintf(buf, "%u\n", tmp); 884792d376bSWei Song } 885792d376bSWei Song 886792d376bSWei Song static ssize_t 887792d376bSWei Song store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 888792d376bSWei Song const char *buf, size_t count) 889792d376bSWei Song { 890792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 891792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 892792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 893792d376bSWei Song to_sensor_dev_attr_2(attr); 894792d376bSWei Song int nr = sensor_attr->nr; 895792d376bSWei Song int index = sensor_attr->index; 896792d376bSWei Song unsigned long tmp; 897792d376bSWei Song 898792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 899792d376bSWei Song return -EINVAL; 900792d376bSWei Song 901792d376bSWei Song switch (nr) { 902792d376bSWei Song case TEMP_PWM_ENABLE: 903792d376bSWei Song if ((tmp != 3) && (tmp != 4)) 904792d376bSWei Song return -EINVAL; 905792d376bSWei Song tmp -= 3; 906792d376bSWei Song mutex_lock(&data->update_lock); 907792d376bSWei Song data->pwm_fcms[1] &= ~(1 << index); 908792d376bSWei Song data->pwm_fcms[1] |= tmp << index; 909792d376bSWei Song w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 910792d376bSWei Song mutex_unlock(&data->update_lock); 911792d376bSWei Song break; 912792d376bSWei Song case TEMP_PWM_FAN_MAP: 913792d376bSWei Song mutex_lock(&data->update_lock); 914792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 0xff); 915792d376bSWei Song w83795_write(client, W83795_REG_TFMR(index), tmp); 916792d376bSWei Song data->pwm_tfmr[index] = tmp; 917792d376bSWei Song mutex_unlock(&data->update_lock); 918792d376bSWei Song break; 919792d376bSWei Song } 920792d376bSWei Song return count; 921792d376bSWei Song } 922792d376bSWei Song 923792d376bSWei Song #define FANIN_TARGET 0 924792d376bSWei Song #define FANIN_TOL 1 925792d376bSWei Song static ssize_t 926792d376bSWei Song show_fanin(struct device *dev, struct device_attribute *attr, char *buf) 927792d376bSWei Song { 928792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 929792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 930792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 931792d376bSWei Song to_sensor_dev_attr_2(attr); 932792d376bSWei Song int nr = sensor_attr->nr; 933792d376bSWei Song int index = sensor_attr->index; 934792d376bSWei Song u16 tmp = 0; 935792d376bSWei Song 936792d376bSWei Song switch (nr) { 937792d376bSWei Song case FANIN_TARGET: 938792d376bSWei Song tmp = fan_from_reg(data->target_speed[index]); 939792d376bSWei Song break; 940792d376bSWei Song case FANIN_TOL: 941792d376bSWei Song tmp = data->tol_speed; 942792d376bSWei Song break; 943792d376bSWei Song } 944792d376bSWei Song 945792d376bSWei Song return sprintf(buf, "%u\n", tmp); 946792d376bSWei Song } 947792d376bSWei Song 948792d376bSWei Song static ssize_t 949792d376bSWei Song store_fanin(struct device *dev, struct device_attribute *attr, 950792d376bSWei Song const char *buf, size_t count) 951792d376bSWei Song { 952792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 953792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 954792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 955792d376bSWei Song to_sensor_dev_attr_2(attr); 956792d376bSWei Song int nr = sensor_attr->nr; 957792d376bSWei Song int index = sensor_attr->index; 958792d376bSWei Song unsigned long val; 959792d376bSWei Song 960792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 961792d376bSWei Song return -EINVAL; 962792d376bSWei Song 963792d376bSWei Song mutex_lock(&data->update_lock); 964792d376bSWei Song switch (nr) { 965792d376bSWei Song case FANIN_TARGET: 966792d376bSWei Song val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); 967792d376bSWei Song w83795_write(client, W83795_REG_FTSH(index), (val >> 4) & 0xff); 968792d376bSWei Song w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 969792d376bSWei Song data->target_speed[index] = val; 970792d376bSWei Song break; 971792d376bSWei Song case FANIN_TOL: 972792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3f); 973792d376bSWei Song w83795_write(client, W83795_REG_TFTS, val); 974792d376bSWei Song data->tol_speed = val; 975792d376bSWei Song break; 976792d376bSWei Song } 977792d376bSWei Song mutex_unlock(&data->update_lock); 978792d376bSWei Song 979792d376bSWei Song return count; 980792d376bSWei Song } 981792d376bSWei Song 982792d376bSWei Song 983792d376bSWei Song static ssize_t 984792d376bSWei Song show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 985792d376bSWei Song { 986792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 987792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 988792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 989792d376bSWei Song to_sensor_dev_attr_2(attr); 990792d376bSWei Song int nr = sensor_attr->nr; 991792d376bSWei Song int index = sensor_attr->index; 992792d376bSWei Song long tmp = temp_from_reg(data->pwm_temp[index][nr]); 993792d376bSWei Song 994792d376bSWei Song return sprintf(buf, "%ld\n", tmp); 995792d376bSWei Song } 996792d376bSWei Song 997792d376bSWei Song static ssize_t 998792d376bSWei Song store_temp_pwm(struct device *dev, struct device_attribute *attr, 999792d376bSWei Song const char *buf, size_t count) 1000792d376bSWei Song { 1001792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1002792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1003792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1004792d376bSWei Song to_sensor_dev_attr_2(attr); 1005792d376bSWei Song int nr = sensor_attr->nr; 1006792d376bSWei Song int index = sensor_attr->index; 1007792d376bSWei Song unsigned long val; 1008792d376bSWei Song u8 tmp; 1009792d376bSWei Song 1010792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1011792d376bSWei Song return -EINVAL; 1012792d376bSWei Song val /= 1000; 1013792d376bSWei Song 1014792d376bSWei Song mutex_lock(&data->update_lock); 1015792d376bSWei Song switch (nr) { 1016792d376bSWei Song case TEMP_PWM_TTTI: 1017792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1018792d376bSWei Song w83795_write(client, W83795_REG_TTTI(index), val); 1019792d376bSWei Song break; 1020792d376bSWei Song case TEMP_PWM_CTFS: 1021792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1022792d376bSWei Song w83795_write(client, W83795_REG_CTFS(index), val); 1023792d376bSWei Song break; 1024792d376bSWei Song case TEMP_PWM_HCT: 1025792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1026792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1027792d376bSWei Song tmp &= 0x0f; 1028792d376bSWei Song tmp |= (val << 4) & 0xf0; 1029792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1030792d376bSWei Song break; 1031792d376bSWei Song case TEMP_PWM_HOT: 1032792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1033792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1034792d376bSWei Song tmp &= 0xf0; 1035792d376bSWei Song tmp |= val & 0x0f; 1036792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1037792d376bSWei Song break; 1038792d376bSWei Song } 1039792d376bSWei Song data->pwm_temp[index][nr] = val; 1040792d376bSWei Song mutex_unlock(&data->update_lock); 1041792d376bSWei Song 1042792d376bSWei Song return count; 1043792d376bSWei Song } 1044792d376bSWei Song 1045792d376bSWei Song static ssize_t 1046792d376bSWei Song show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1047792d376bSWei Song { 1048792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1049792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1050792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1051792d376bSWei Song to_sensor_dev_attr_2(attr); 1052792d376bSWei Song int nr = sensor_attr->nr; 1053792d376bSWei Song int index = sensor_attr->index; 1054792d376bSWei Song 1055792d376bSWei Song return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 1056792d376bSWei Song } 1057792d376bSWei Song 1058792d376bSWei Song static ssize_t 1059792d376bSWei Song store_sf4_pwm(struct device *dev, struct device_attribute *attr, 1060792d376bSWei Song const char *buf, size_t count) 1061792d376bSWei Song { 1062792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1063792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1064792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1065792d376bSWei Song to_sensor_dev_attr_2(attr); 1066792d376bSWei Song int nr = sensor_attr->nr; 1067792d376bSWei Song int index = sensor_attr->index; 1068792d376bSWei Song unsigned long val; 1069792d376bSWei Song 1070792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1071792d376bSWei Song return -EINVAL; 1072792d376bSWei Song 1073792d376bSWei Song mutex_lock(&data->update_lock); 1074792d376bSWei Song w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 1075792d376bSWei Song data->sf4_reg[index][SF4_PWM][nr] = val; 1076792d376bSWei Song mutex_unlock(&data->update_lock); 1077792d376bSWei Song 1078792d376bSWei Song return count; 1079792d376bSWei Song } 1080792d376bSWei Song 1081792d376bSWei Song static ssize_t 1082792d376bSWei Song show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 1083792d376bSWei Song { 1084792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1085792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1086792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1087792d376bSWei Song to_sensor_dev_attr_2(attr); 1088792d376bSWei Song int nr = sensor_attr->nr; 1089792d376bSWei Song int index = sensor_attr->index; 1090792d376bSWei Song 1091792d376bSWei Song return sprintf(buf, "%u\n", 1092792d376bSWei Song (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 1093792d376bSWei Song } 1094792d376bSWei Song 1095792d376bSWei Song static ssize_t 1096792d376bSWei Song store_sf4_temp(struct device *dev, struct device_attribute *attr, 1097792d376bSWei Song const char *buf, size_t count) 1098792d376bSWei Song { 1099792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1100792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1101792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1102792d376bSWei Song to_sensor_dev_attr_2(attr); 1103792d376bSWei Song int nr = sensor_attr->nr; 1104792d376bSWei Song int index = sensor_attr->index; 1105792d376bSWei Song unsigned long val; 1106792d376bSWei Song 1107792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1108792d376bSWei Song return -EINVAL; 1109792d376bSWei Song val /= 1000; 1110792d376bSWei Song 1111792d376bSWei Song mutex_lock(&data->update_lock); 1112792d376bSWei Song w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 1113792d376bSWei Song data->sf4_reg[index][SF4_TEMP][nr] = val; 1114792d376bSWei Song mutex_unlock(&data->update_lock); 1115792d376bSWei Song 1116792d376bSWei Song return count; 1117792d376bSWei Song } 1118792d376bSWei Song 1119792d376bSWei Song 1120792d376bSWei Song static ssize_t 1121792d376bSWei Song show_temp(struct device *dev, struct device_attribute *attr, char *buf) 1122792d376bSWei Song { 1123792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1124792d376bSWei Song to_sensor_dev_attr_2(attr); 1125792d376bSWei Song int nr = sensor_attr->nr; 1126792d376bSWei Song int index = sensor_attr->index; 1127792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1128792d376bSWei Song long temp = temp_from_reg(data->temp[index][nr] & 0x7f); 1129792d376bSWei Song 1130792d376bSWei Song if (TEMP_READ == nr) 1131792d376bSWei Song temp += ((data->temp_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) 1132792d376bSWei Song * 250; 1133792d376bSWei Song if (data->temp[index][nr] & 0x80) 1134792d376bSWei Song temp = -temp; 1135792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1136792d376bSWei Song } 1137792d376bSWei Song 1138792d376bSWei Song static ssize_t 1139792d376bSWei Song store_temp(struct device *dev, struct device_attribute *attr, 1140792d376bSWei Song const char *buf, size_t count) 1141792d376bSWei Song { 1142792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1143792d376bSWei Song to_sensor_dev_attr_2(attr); 1144792d376bSWei Song int nr = sensor_attr->nr; 1145792d376bSWei Song int index = sensor_attr->index; 1146792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1147792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1148792d376bSWei Song long tmp; 1149792d376bSWei Song 1150792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1151792d376bSWei Song return -EINVAL; 1152792d376bSWei Song 1153792d376bSWei Song mutex_lock(&data->update_lock); 1154792d376bSWei Song data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 1155792d376bSWei Song w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 1156792d376bSWei Song mutex_unlock(&data->update_lock); 1157792d376bSWei Song return count; 1158792d376bSWei Song } 1159792d376bSWei Song 1160792d376bSWei Song 1161792d376bSWei Song static ssize_t 1162792d376bSWei Song show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) 1163792d376bSWei Song { 1164792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1165792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1166792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1167792d376bSWei Song to_sensor_dev_attr_2(attr); 1168792d376bSWei Song int index = sensor_attr->index; 1169792d376bSWei Song u8 tmp; 1170792d376bSWei Song 1171792d376bSWei Song if (data->enable_dts == 0) 1172792d376bSWei Song return sprintf(buf, "%d\n", 0); 1173792d376bSWei Song 1174792d376bSWei Song if ((data->has_dts >> index) & 0x01) { 1175792d376bSWei Song if (data->enable_dts & 2) 1176792d376bSWei Song tmp = 5; 1177792d376bSWei Song else 1178792d376bSWei Song tmp = 6; 1179792d376bSWei Song } else { 1180792d376bSWei Song tmp = 0; 1181792d376bSWei Song } 1182792d376bSWei Song 1183792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1184792d376bSWei Song } 1185792d376bSWei Song 1186792d376bSWei Song static ssize_t 1187792d376bSWei Song show_dts(struct device *dev, struct device_attribute *attr, char *buf) 1188792d376bSWei Song { 1189792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1190792d376bSWei Song to_sensor_dev_attr_2(attr); 1191792d376bSWei Song int index = sensor_attr->index; 1192792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1193792d376bSWei Song long temp = temp_from_reg(data->dts[index] & 0x7f); 1194792d376bSWei Song 1195792d376bSWei Song temp += ((data->dts_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250; 1196792d376bSWei Song if (data->dts[index] & 0x80) 1197792d376bSWei Song temp = -temp; 1198792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1199792d376bSWei Song } 1200792d376bSWei Song 1201792d376bSWei Song static ssize_t 1202792d376bSWei Song show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 1203792d376bSWei Song { 1204792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1205792d376bSWei Song to_sensor_dev_attr_2(attr); 1206792d376bSWei Song int nr = sensor_attr->nr; 1207792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1208792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1209792d376bSWei Song long temp = temp_from_reg(data->dts_ext[nr] & 0x7f); 1210792d376bSWei Song 1211792d376bSWei Song if (data->dts_ext[nr] & 0x80) 1212792d376bSWei Song temp = -temp; 1213792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1214792d376bSWei Song } 1215792d376bSWei Song 1216792d376bSWei Song static ssize_t 1217792d376bSWei Song store_dts_ext(struct device *dev, struct device_attribute *attr, 1218792d376bSWei Song const char *buf, size_t count) 1219792d376bSWei Song { 1220792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1221792d376bSWei Song to_sensor_dev_attr_2(attr); 1222792d376bSWei Song int nr = sensor_attr->nr; 1223792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1224792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1225792d376bSWei Song long tmp; 1226792d376bSWei Song 1227792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1228792d376bSWei Song return -EINVAL; 1229792d376bSWei Song 1230792d376bSWei Song mutex_lock(&data->update_lock); 1231792d376bSWei Song data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 1232792d376bSWei Song w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 1233792d376bSWei Song mutex_unlock(&data->update_lock); 1234792d376bSWei Song return count; 1235792d376bSWei Song } 1236792d376bSWei Song 1237792d376bSWei Song 1238792d376bSWei Song /* 1239792d376bSWei Song Type 3: Thermal diode 1240792d376bSWei Song Type 4: Thermistor 1241792d376bSWei Song 1242792d376bSWei Song Temp5-6, default TR 1243792d376bSWei Song Temp1-4, default TD 1244792d376bSWei Song */ 1245792d376bSWei Song 1246792d376bSWei Song static ssize_t 1247792d376bSWei Song show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 1248792d376bSWei Song { 1249792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1250792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1251792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1252792d376bSWei Song to_sensor_dev_attr_2(attr); 1253792d376bSWei Song int index = sensor_attr->index; 1254792d376bSWei Song u8 tmp; 1255792d376bSWei Song 1256792d376bSWei Song if (data->has_temp >> index & 0x01) { 1257792d376bSWei Song if (data->temp_mode >> index & 0x01) 1258792d376bSWei Song tmp = 3; 1259792d376bSWei Song else 1260792d376bSWei Song tmp = 4; 1261792d376bSWei Song } else { 1262792d376bSWei Song tmp = 0; 1263792d376bSWei Song } 1264792d376bSWei Song 1265792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1266792d376bSWei Song } 1267792d376bSWei Song 1268792d376bSWei Song static ssize_t 1269792d376bSWei Song store_temp_mode(struct device *dev, struct device_attribute *attr, 1270792d376bSWei Song const char *buf, size_t count) 1271792d376bSWei Song { 1272792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1273792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1274792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1275792d376bSWei Song to_sensor_dev_attr_2(attr); 1276792d376bSWei Song int index = sensor_attr->index; 1277792d376bSWei Song unsigned long val; 1278792d376bSWei Song u8 tmp; 1279792d376bSWei Song u32 mask; 1280792d376bSWei Song 1281792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1282792d376bSWei Song return -EINVAL; 1283792d376bSWei Song if ((val != 4) && (val != 3)) 1284792d376bSWei Song return -EINVAL; 1285792d376bSWei Song if ((index > 3) && (val == 3)) 1286792d376bSWei Song return -EINVAL; 1287792d376bSWei Song 1288792d376bSWei Song mutex_lock(&data->update_lock); 1289792d376bSWei Song if (val == 3) { 1290792d376bSWei Song val = TEMP_CTRL_TD; 1291792d376bSWei Song data->has_temp |= 1 << index; 1292792d376bSWei Song data->temp_mode |= 1 << index; 1293792d376bSWei Song } else if (val == 4) { 1294792d376bSWei Song val = TEMP_CTRL_TR; 1295792d376bSWei Song data->has_temp |= 1 << index; 1296792d376bSWei Song tmp = 1 << index; 1297792d376bSWei Song data->temp_mode &= ~tmp; 1298792d376bSWei Song } 1299792d376bSWei Song 1300792d376bSWei Song if (index > 3) 1301792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 1302792d376bSWei Song else 1303792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 1304792d376bSWei Song 1305792d376bSWei Song mask = 0x03 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_SHIFT]; 1306792d376bSWei Song tmp &= ~mask; 1307792d376bSWei Song tmp |= W83795_REG_TEMP_CTRL[index][val]; 1308792d376bSWei Song 1309792d376bSWei Song mask = 1 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_HASIN_SHIFT]; 1310792d376bSWei Song data->has_in &= ~mask; 1311792d376bSWei Song 1312792d376bSWei Song if (index > 3) 1313792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL1, tmp); 1314792d376bSWei Song else 1315792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 1316792d376bSWei Song 1317792d376bSWei Song mutex_unlock(&data->update_lock); 1318792d376bSWei Song return count; 1319792d376bSWei Song } 1320792d376bSWei Song 1321792d376bSWei Song 1322792d376bSWei Song /* show/store VIN */ 1323792d376bSWei Song static ssize_t 1324792d376bSWei Song show_in(struct device *dev, struct device_attribute *attr, char *buf) 1325792d376bSWei Song { 1326792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1327792d376bSWei Song to_sensor_dev_attr_2(attr); 1328792d376bSWei Song int nr = sensor_attr->nr; 1329792d376bSWei Song int index = sensor_attr->index; 1330792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1331792d376bSWei Song u16 val = data->in[index][nr]; 1332792d376bSWei Song u8 lsb_idx; 1333792d376bSWei Song 1334792d376bSWei Song switch (nr) { 1335792d376bSWei Song case IN_READ: 1336792d376bSWei Song /* calculate this value again by sensors as sensors3.conf */ 1337792d376bSWei Song if ((index >= 17) && 1338792d376bSWei Song ((data->has_gain >> (index - 17)) & 1)) 1339792d376bSWei Song val *= 8; 1340792d376bSWei Song break; 1341792d376bSWei Song case IN_MAX: 1342792d376bSWei Song case IN_LOW: 1343792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1344792d376bSWei Song val <<= 2; 1345792d376bSWei Song val |= (data->in_lsb[lsb_idx][nr] >> 1346792d376bSWei Song IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; 1347792d376bSWei Song if ((index >= 17) && 1348792d376bSWei Song ((data->has_gain >> (index - 17)) & 1)) 1349792d376bSWei Song val *= 8; 1350792d376bSWei Song break; 1351792d376bSWei Song } 1352792d376bSWei Song val = in_from_reg(index, val); 1353792d376bSWei Song 1354792d376bSWei Song return sprintf(buf, "%d\n", val); 1355792d376bSWei Song } 1356792d376bSWei Song 1357792d376bSWei Song static ssize_t 1358792d376bSWei Song store_in(struct device *dev, struct device_attribute *attr, 1359792d376bSWei Song const char *buf, size_t count) 1360792d376bSWei Song { 1361792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1362792d376bSWei Song to_sensor_dev_attr_2(attr); 1363792d376bSWei Song int nr = sensor_attr->nr; 1364792d376bSWei Song int index = sensor_attr->index; 1365792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1366792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1367792d376bSWei Song unsigned long val; 1368792d376bSWei Song u8 tmp; 1369792d376bSWei Song u8 lsb_idx; 1370792d376bSWei Song 1371792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1372792d376bSWei Song return -EINVAL; 1373792d376bSWei Song val = in_to_reg(index, val); 1374792d376bSWei Song 1375792d376bSWei Song if ((index >= 17) && 1376792d376bSWei Song ((data->has_gain >> (index - 17)) & 1)) 1377792d376bSWei Song val /= 8; 1378792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3FF); 1379792d376bSWei Song mutex_lock(&data->update_lock); 1380792d376bSWei Song 1381792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1382792d376bSWei Song tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 1383792d376bSWei Song tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 1384792d376bSWei Song tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 1385792d376bSWei Song w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 1386792d376bSWei Song data->in_lsb[lsb_idx][nr] = tmp; 1387792d376bSWei Song 1388792d376bSWei Song tmp = (val >> 2) & 0xff; 1389792d376bSWei Song w83795_write(client, W83795_REG_IN[index][nr], tmp); 1390792d376bSWei Song data->in[index][nr] = tmp; 1391792d376bSWei Song 1392792d376bSWei Song mutex_unlock(&data->update_lock); 1393792d376bSWei Song return count; 1394792d376bSWei Song } 1395792d376bSWei Song 1396792d376bSWei Song 1397792d376bSWei Song static ssize_t 1398792d376bSWei Song show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 1399792d376bSWei Song { 1400792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1401792d376bSWei Song to_sensor_dev_attr_2(attr); 1402792d376bSWei Song int nr = sensor_attr->nr; 1403792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1404792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1405792d376bSWei Song u16 val = data->setup_pwm[nr]; 1406792d376bSWei Song 1407792d376bSWei Song switch (nr) { 1408792d376bSWei Song case SETUP_PWM_UPTIME: 1409792d376bSWei Song case SETUP_PWM_DOWNTIME: 1410792d376bSWei Song val = time_from_reg(val); 1411792d376bSWei Song break; 1412792d376bSWei Song } 1413792d376bSWei Song 1414792d376bSWei Song return sprintf(buf, "%d\n", val); 1415792d376bSWei Song } 1416792d376bSWei Song 1417792d376bSWei Song static ssize_t 1418792d376bSWei Song store_sf_setup(struct device *dev, struct device_attribute *attr, 1419792d376bSWei Song const char *buf, size_t count) 1420792d376bSWei Song { 1421792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1422792d376bSWei Song to_sensor_dev_attr_2(attr); 1423792d376bSWei Song int nr = sensor_attr->nr; 1424792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1425792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1426792d376bSWei Song unsigned long val; 1427792d376bSWei Song 1428792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1429792d376bSWei Song return -EINVAL; 1430792d376bSWei Song 1431792d376bSWei Song switch (nr) { 1432792d376bSWei Song case SETUP_PWM_DEFAULT: 1433792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 1434792d376bSWei Song break; 1435792d376bSWei Song case SETUP_PWM_UPTIME: 1436792d376bSWei Song case SETUP_PWM_DOWNTIME: 1437792d376bSWei Song val = time_to_reg(val); 1438792d376bSWei Song if (val == 0) 1439792d376bSWei Song return -EINVAL; 1440792d376bSWei Song break; 1441792d376bSWei Song } 1442792d376bSWei Song 1443792d376bSWei Song mutex_lock(&data->update_lock); 1444792d376bSWei Song data->setup_pwm[nr] = val; 1445792d376bSWei Song w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 1446792d376bSWei Song mutex_unlock(&data->update_lock); 1447792d376bSWei Song return count; 1448792d376bSWei Song } 1449792d376bSWei Song 1450792d376bSWei Song 1451792d376bSWei Song #define NOT_USED -1 1452792d376bSWei Song 145387df0dadSJean Delvare #define SENSOR_ATTR_IN(index) { \ 1454792d376bSWei Song SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 1455792d376bSWei Song IN_READ, index), \ 1456792d376bSWei Song SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 1457792d376bSWei Song store_in, IN_MAX, index), \ 1458792d376bSWei Song SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 1459792d376bSWei Song store_in, IN_LOW, index), \ 1460792d376bSWei Song SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 1461792d376bSWei Song NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 1462792d376bSWei Song SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 1463792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 146487df0dadSJean Delvare index + ((index > 14) ? 1 : 0)) } 1465792d376bSWei Song 146687df0dadSJean Delvare #define SENSOR_ATTR_FAN(index) { \ 1467792d376bSWei Song SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 1468792d376bSWei Song NULL, FAN_INPUT, index - 1), \ 1469792d376bSWei Song SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 1470792d376bSWei Song show_fan, store_fan_min, FAN_MIN, index - 1), \ 1471792d376bSWei Song SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 1472792d376bSWei Song NULL, ALARM_STATUS, index + 31), \ 1473792d376bSWei Song SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 147487df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 1475792d376bSWei Song 1476b5f6a90aSJean Delvare #define SENSOR_ATTR_PWM(index) { \ 1477792d376bSWei Song SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 1478792d376bSWei Song store_pwm, PWM_OUTPUT, index - 1), \ 1479792d376bSWei Song SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 1480792d376bSWei Song show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 1481792d376bSWei Song SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 1482792d376bSWei Song show_pwm, store_pwm, PWM_START, index - 1), \ 1483792d376bSWei Song SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 1484792d376bSWei Song show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 1485792d376bSWei Song SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \ 1486792d376bSWei Song show_pwm, store_pwm, PWM_DIV, index - 1), \ 1487792d376bSWei Song SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 1488b2cc528eSJean Delvare show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 1489b2cc528eSJean Delvare SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 1490b2cc528eSJean Delvare show_fanin, store_fanin, FANIN_TARGET, index - 1) } 1491792d376bSWei Song 149287df0dadSJean Delvare #define SENSOR_ATTR_DTS(index) { \ 1493792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 1494792d376bSWei Song show_dts_mode, NULL, NOT_USED, index - 7), \ 1495792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 1496792d376bSWei Song NULL, NOT_USED, index - 7), \ 1497792d376bSWei Song SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 1498792d376bSWei Song store_dts_ext, DTS_CRIT, NOT_USED), \ 1499792d376bSWei Song SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1500792d376bSWei Song show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 1501792d376bSWei Song SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_dts_ext, \ 1502792d376bSWei Song store_dts_ext, DTS_WARN, NOT_USED), \ 1503792d376bSWei Song SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ 1504792d376bSWei Song show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 1505792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1506792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 1507792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 150887df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 1509792d376bSWei Song 151087df0dadSJean Delvare #define SENSOR_ATTR_TEMP(index) { \ 1511792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \ 1512792d376bSWei Song show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 1513792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 1514792d376bSWei Song NULL, TEMP_READ, index - 1), \ 1515792d376bSWei Song SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 1516792d376bSWei Song store_temp, TEMP_CRIT, index - 1), \ 1517792d376bSWei Song SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1518792d376bSWei Song show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 1519792d376bSWei Song SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \ 1520792d376bSWei Song store_temp, TEMP_WARN, index - 1), \ 1521792d376bSWei Song SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ 1522792d376bSWei Song show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 1523792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1524792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, \ 1525792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1526792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 1527792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 1528792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1529792d376bSWei Song SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \ 1530792d376bSWei Song show_temp_src, store_temp_src, NOT_USED, index - 1), \ 1531792d376bSWei Song SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 1532792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1533792d376bSWei Song TEMP_PWM_ENABLE, index - 1), \ 1534792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 1535792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1536792d376bSWei Song TEMP_PWM_FAN_MAP, index - 1), \ 1537792d376bSWei Song SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 1538792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 1539792d376bSWei Song SENSOR_ATTR_2(temp##index##_crit, S_IWUSR | S_IRUGO, \ 1540792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 1541792d376bSWei Song SENSOR_ATTR_2(temp##index##_crit_hyst, S_IWUSR | S_IRUGO, \ 1542792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 1543792d376bSWei Song SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 1544792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 1545792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 1546792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 1547792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 1548792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 1549792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 1550792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 1551792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 1552792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 1553792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 1554792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 1555792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 1556792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 1557792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 1558792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 1559792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 1560792d376bSWei Song show_sf4_temp, store_sf4_temp, 0, index - 1), \ 1561792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 1562792d376bSWei Song show_sf4_temp, store_sf4_temp, 1, index - 1), \ 1563792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 1564792d376bSWei Song show_sf4_temp, store_sf4_temp, 2, index - 1), \ 1565792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 1566792d376bSWei Song show_sf4_temp, store_sf4_temp, 3, index - 1), \ 1567792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 1568792d376bSWei Song show_sf4_temp, store_sf4_temp, 4, index - 1), \ 1569792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 1570792d376bSWei Song show_sf4_temp, store_sf4_temp, 5, index - 1), \ 1571792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 157287df0dadSJean Delvare show_sf4_temp, store_sf4_temp, 6, index - 1) } 1573792d376bSWei Song 1574792d376bSWei Song 157587df0dadSJean Delvare static struct sensor_device_attribute_2 w83795_in[][5] = { 1576792d376bSWei Song SENSOR_ATTR_IN(0), 1577792d376bSWei Song SENSOR_ATTR_IN(1), 1578792d376bSWei Song SENSOR_ATTR_IN(2), 1579792d376bSWei Song SENSOR_ATTR_IN(3), 1580792d376bSWei Song SENSOR_ATTR_IN(4), 1581792d376bSWei Song SENSOR_ATTR_IN(5), 1582792d376bSWei Song SENSOR_ATTR_IN(6), 1583792d376bSWei Song SENSOR_ATTR_IN(7), 1584792d376bSWei Song SENSOR_ATTR_IN(8), 1585792d376bSWei Song SENSOR_ATTR_IN(9), 1586792d376bSWei Song SENSOR_ATTR_IN(10), 1587792d376bSWei Song SENSOR_ATTR_IN(11), 1588792d376bSWei Song SENSOR_ATTR_IN(12), 1589792d376bSWei Song SENSOR_ATTR_IN(13), 1590792d376bSWei Song SENSOR_ATTR_IN(14), 1591792d376bSWei Song SENSOR_ATTR_IN(15), 1592792d376bSWei Song SENSOR_ATTR_IN(16), 1593792d376bSWei Song SENSOR_ATTR_IN(17), 1594792d376bSWei Song SENSOR_ATTR_IN(18), 1595792d376bSWei Song SENSOR_ATTR_IN(19), 1596792d376bSWei Song SENSOR_ATTR_IN(20), 1597792d376bSWei Song }; 1598792d376bSWei Song 159986ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_fan[][4] = { 1600792d376bSWei Song SENSOR_ATTR_FAN(1), 1601792d376bSWei Song SENSOR_ATTR_FAN(2), 1602792d376bSWei Song SENSOR_ATTR_FAN(3), 1603792d376bSWei Song SENSOR_ATTR_FAN(4), 1604792d376bSWei Song SENSOR_ATTR_FAN(5), 1605792d376bSWei Song SENSOR_ATTR_FAN(6), 1606792d376bSWei Song SENSOR_ATTR_FAN(7), 1607792d376bSWei Song SENSOR_ATTR_FAN(8), 1608792d376bSWei Song SENSOR_ATTR_FAN(9), 1609792d376bSWei Song SENSOR_ATTR_FAN(10), 1610792d376bSWei Song SENSOR_ATTR_FAN(11), 1611792d376bSWei Song SENSOR_ATTR_FAN(12), 1612792d376bSWei Song SENSOR_ATTR_FAN(13), 1613792d376bSWei Song SENSOR_ATTR_FAN(14), 1614792d376bSWei Song }; 1615792d376bSWei Song 161686ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_temp[][29] = { 1617792d376bSWei Song SENSOR_ATTR_TEMP(1), 1618792d376bSWei Song SENSOR_ATTR_TEMP(2), 1619792d376bSWei Song SENSOR_ATTR_TEMP(3), 1620792d376bSWei Song SENSOR_ATTR_TEMP(4), 1621792d376bSWei Song SENSOR_ATTR_TEMP(5), 1622792d376bSWei Song SENSOR_ATTR_TEMP(6), 1623792d376bSWei Song }; 1624792d376bSWei Song 162586ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_dts[][8] = { 1626792d376bSWei Song SENSOR_ATTR_DTS(7), 1627792d376bSWei Song SENSOR_ATTR_DTS(8), 1628792d376bSWei Song SENSOR_ATTR_DTS(9), 1629792d376bSWei Song SENSOR_ATTR_DTS(10), 1630792d376bSWei Song SENSOR_ATTR_DTS(11), 1631792d376bSWei Song SENSOR_ATTR_DTS(12), 1632792d376bSWei Song SENSOR_ATTR_DTS(13), 1633792d376bSWei Song SENSOR_ATTR_DTS(14), 1634792d376bSWei Song }; 1635792d376bSWei Song 163686ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_pwm[][7] = { 1637b5f6a90aSJean Delvare SENSOR_ATTR_PWM(1), 1638b5f6a90aSJean Delvare SENSOR_ATTR_PWM(2), 1639792d376bSWei Song SENSOR_ATTR_PWM(3), 1640792d376bSWei Song SENSOR_ATTR_PWM(4), 1641792d376bSWei Song SENSOR_ATTR_PWM(5), 1642792d376bSWei Song SENSOR_ATTR_PWM(6), 1643792d376bSWei Song SENSOR_ATTR_PWM(7), 1644792d376bSWei Song SENSOR_ATTR_PWM(8), 1645792d376bSWei Song }; 1646792d376bSWei Song 164786ef4d2fSJean Delvare static const struct sensor_device_attribute_2 sda_single_files[] = { 1648792d376bSWei Song SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, 1649792d376bSWei Song store_chassis_clear, ALARM_STATUS, 46), 1650792d376bSWei Song SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, 1651792d376bSWei Song store_beep_enable, NOT_USED, NOT_USED), 1652792d376bSWei Song SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 1653792d376bSWei Song store_fanin, FANIN_TOL, NOT_USED), 1654792d376bSWei Song SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 1655792d376bSWei Song store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 1656792d376bSWei Song SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 1657792d376bSWei Song store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 1658792d376bSWei Song SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 1659792d376bSWei Song store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 1660792d376bSWei Song }; 1661792d376bSWei Song 1662792d376bSWei Song /* 1663792d376bSWei Song * Driver interface 1664792d376bSWei Song */ 1665792d376bSWei Song 1666792d376bSWei Song static void w83795_init_client(struct i2c_client *client) 1667792d376bSWei Song { 166880646b95SJean Delvare u8 config; 166980646b95SJean Delvare 1670792d376bSWei Song if (reset) 1671792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 0x80); 1672792d376bSWei Song 167380646b95SJean Delvare /* Start monitoring if needed */ 167480646b95SJean Delvare config = w83795_read(client, W83795_REG_CONFIG); 167580646b95SJean Delvare if (!(config & W83795_REG_CONFIG_START)) { 167680646b95SJean Delvare dev_info(&client->dev, "Enabling monitoring operations\n"); 1677792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 167880646b95SJean Delvare config | W83795_REG_CONFIG_START); 167980646b95SJean Delvare } 1680792d376bSWei Song } 1681792d376bSWei Song 16822be381deSJean Delvare static int w83795_get_device_id(struct i2c_client *client) 16832be381deSJean Delvare { 16842be381deSJean Delvare int device_id; 16852be381deSJean Delvare 16862be381deSJean Delvare device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 16872be381deSJean Delvare 16882be381deSJean Delvare /* Special case for rev. A chips; can't be checked first because later 16892be381deSJean Delvare revisions emulate this for compatibility */ 16902be381deSJean Delvare if (device_id < 0 || (device_id & 0xf0) != 0x50) { 16912be381deSJean Delvare int alt_id; 16922be381deSJean Delvare 16932be381deSJean Delvare alt_id = i2c_smbus_read_byte_data(client, 16942be381deSJean Delvare W83795_REG_DEVICEID_A); 16952be381deSJean Delvare if (alt_id == 0x50) 16962be381deSJean Delvare device_id = alt_id; 16972be381deSJean Delvare } 16982be381deSJean Delvare 16992be381deSJean Delvare return device_id; 17002be381deSJean Delvare } 17012be381deSJean Delvare 1702792d376bSWei Song /* Return 0 if detection is successful, -ENODEV otherwise */ 1703792d376bSWei Song static int w83795_detect(struct i2c_client *client, 1704792d376bSWei Song struct i2c_board_info *info) 1705792d376bSWei Song { 17062be381deSJean Delvare int bank, vendor_id, device_id, expected, i2c_addr, config; 1707792d376bSWei Song struct i2c_adapter *adapter = client->adapter; 1708792d376bSWei Song unsigned short address = client->addr; 1709093d1a47SJean Delvare const char *chip_name; 1710792d376bSWei Song 1711792d376bSWei Song if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1712792d376bSWei Song return -ENODEV; 1713792d376bSWei Song bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 17142be381deSJean Delvare if (bank < 0 || (bank & 0x7c)) { 17152be381deSJean Delvare dev_dbg(&adapter->dev, 17162be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17172be381deSJean Delvare address, "bank"); 17182be381deSJean Delvare return -ENODEV; 17192be381deSJean Delvare } 1720792d376bSWei Song 1721792d376bSWei Song /* Check Nuvoton vendor ID */ 17222be381deSJean Delvare vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 17232be381deSJean Delvare expected = bank & 0x80 ? 0x5c : 0xa3; 17242be381deSJean Delvare if (vendor_id != expected) { 17252be381deSJean Delvare dev_dbg(&adapter->dev, 17262be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17272be381deSJean Delvare address, "vendor id"); 17282be381deSJean Delvare return -ENODEV; 17292be381deSJean Delvare } 17302be381deSJean Delvare 17312be381deSJean Delvare /* Check device ID */ 17322be381deSJean Delvare device_id = w83795_get_device_id(client) | 17332be381deSJean Delvare (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 17342be381deSJean Delvare if ((device_id >> 4) != 0x795) { 17352be381deSJean Delvare dev_dbg(&adapter->dev, 17362be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17372be381deSJean Delvare address, "device id\n"); 1738792d376bSWei Song return -ENODEV; 1739792d376bSWei Song } 1740792d376bSWei Song 1741792d376bSWei Song /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 1742792d376bSWei Song should match */ 17432be381deSJean Delvare if ((bank & 0x07) == 0) { 17442be381deSJean Delvare i2c_addr = i2c_smbus_read_byte_data(client, 17452be381deSJean Delvare W83795_REG_I2C_ADDR); 17462be381deSJean Delvare if ((i2c_addr & 0x7f) != address) { 17472be381deSJean Delvare dev_dbg(&adapter->dev, 17482be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, " 17492be381deSJean Delvare "check %s\n", address, "i2c addr"); 1750792d376bSWei Song return -ENODEV; 1751792d376bSWei Song } 1752792d376bSWei Song } 1753792d376bSWei Song 1754093d1a47SJean Delvare /* Check 795 chip type: 795G or 795ADG 1755093d1a47SJean Delvare Usually we don't write to chips during detection, but here we don't 1756093d1a47SJean Delvare quite have the choice; hopefully it's OK, we are about to return 1757093d1a47SJean Delvare success anyway */ 1758093d1a47SJean Delvare if ((bank & 0x07) != 0) 1759093d1a47SJean Delvare i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 1760093d1a47SJean Delvare bank & ~0x07); 17612be381deSJean Delvare config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 17622be381deSJean Delvare if (config & W83795_REG_CONFIG_CONFIG48) 1763093d1a47SJean Delvare chip_name = "w83795adg"; 17642be381deSJean Delvare else 1765093d1a47SJean Delvare chip_name = "w83795g"; 1766792d376bSWei Song 1767093d1a47SJean Delvare strlcpy(info->type, chip_name, I2C_NAME_SIZE); 17682be381deSJean Delvare dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 17692be381deSJean Delvare 'A' + (device_id & 0xf), address); 1770792d376bSWei Song 1771792d376bSWei Song return 0; 1772792d376bSWei Song } 1773792d376bSWei Song 17746f3dcde9SJean Delvare static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 17756f3dcde9SJean Delvare const struct device_attribute *)) 1776892514a6SJean Delvare { 1777892514a6SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 177887df0dadSJean Delvare int err, i, j; 1779892514a6SJean Delvare 1780892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 178187df0dadSJean Delvare if (!(data->has_in & (1 << i))) 1782892514a6SJean Delvare continue; 178387df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 178487df0dadSJean Delvare err = fn(dev, &w83795_in[i][j].dev_attr); 1785892514a6SJean Delvare if (err) 1786892514a6SJean Delvare return err; 1787892514a6SJean Delvare } 178887df0dadSJean Delvare } 1789892514a6SJean Delvare 1790892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 179187df0dadSJean Delvare if (!(data->has_fan & (1 << i))) 1792892514a6SJean Delvare continue; 179387df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 179487df0dadSJean Delvare err = fn(dev, &w83795_fan[i][j].dev_attr); 1795892514a6SJean Delvare if (err) 1796892514a6SJean Delvare return err; 1797892514a6SJean Delvare } 179887df0dadSJean Delvare } 1799892514a6SJean Delvare 1800892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 18016f3dcde9SJean Delvare err = fn(dev, &sda_single_files[i].dev_attr); 1802892514a6SJean Delvare if (err) 1803892514a6SJean Delvare return err; 1804892514a6SJean Delvare } 1805892514a6SJean Delvare 1806b5f6a90aSJean Delvare for (i = 0; i < data->has_pwm; i++) { 1807b5f6a90aSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { 1808b5f6a90aSJean Delvare err = fn(dev, &w83795_pwm[i][j].dev_attr); 1809892514a6SJean Delvare if (err) 1810892514a6SJean Delvare return err; 1811892514a6SJean Delvare } 1812892514a6SJean Delvare } 1813892514a6SJean Delvare 1814892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 181587df0dadSJean Delvare if (!(data->has_temp & (1 << i))) 1816892514a6SJean Delvare continue; 181787df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { 181887df0dadSJean Delvare err = fn(dev, &w83795_temp[i][j].dev_attr); 1819892514a6SJean Delvare if (err) 1820892514a6SJean Delvare return err; 1821892514a6SJean Delvare } 182287df0dadSJean Delvare } 1823892514a6SJean Delvare 1824892514a6SJean Delvare if (data->enable_dts != 0) { 1825892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 182687df0dadSJean Delvare if (!(data->has_dts & (1 << i))) 1827892514a6SJean Delvare continue; 182887df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 182987df0dadSJean Delvare err = fn(dev, &w83795_dts[i][j].dev_attr); 1830892514a6SJean Delvare if (err) 1831892514a6SJean Delvare return err; 1832892514a6SJean Delvare } 1833892514a6SJean Delvare } 183487df0dadSJean Delvare } 1835892514a6SJean Delvare 1836892514a6SJean Delvare return 0; 1837892514a6SJean Delvare } 1838892514a6SJean Delvare 18396f3dcde9SJean Delvare /* We need a wrapper that fits in w83795_handle_files */ 18406f3dcde9SJean Delvare static int device_remove_file_wrapper(struct device *dev, 18416f3dcde9SJean Delvare const struct device_attribute *attr) 18422fa09878SJean Delvare { 18436f3dcde9SJean Delvare device_remove_file(dev, attr); 18446f3dcde9SJean Delvare return 0; 18452fa09878SJean Delvare } 18462fa09878SJean Delvare 1847792d376bSWei Song static int w83795_probe(struct i2c_client *client, 1848792d376bSWei Song const struct i2c_device_id *id) 1849792d376bSWei Song { 1850792d376bSWei Song int i; 1851792d376bSWei Song u8 tmp; 1852792d376bSWei Song struct device *dev = &client->dev; 1853792d376bSWei Song struct w83795_data *data; 1854792d376bSWei Song int err = 0; 1855792d376bSWei Song 1856792d376bSWei Song data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); 1857792d376bSWei Song if (!data) { 1858792d376bSWei Song err = -ENOMEM; 1859792d376bSWei Song goto exit; 1860792d376bSWei Song } 1861792d376bSWei Song 1862792d376bSWei Song i2c_set_clientdata(client, data); 1863093d1a47SJean Delvare data->chip_type = id->driver_data; 1864792d376bSWei Song data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 1865792d376bSWei Song mutex_init(&data->update_lock); 1866792d376bSWei Song 1867792d376bSWei Song /* Initialize the chip */ 1868792d376bSWei Song w83795_init_client(client); 1869792d376bSWei Song 1870792d376bSWei Song data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1); 1871792d376bSWei Song data->has_in |= w83795_read(client, W83795_REG_VOLT_CTRL2) << 8; 1872792d376bSWei Song /* VSEN11-9 not for 795adg */ 1873792d376bSWei Song if (data->chip_type == w83795adg) 1874792d376bSWei Song data->has_in &= 0xf8ff; 1875792d376bSWei Song data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1); 1876792d376bSWei Song data->has_fan |= w83795_read(client, W83795_REG_FANIN_CTRL2) << 8; 1877792d376bSWei Song 1878792d376bSWei Song /* VDSEN12-17 and TR1-6, TD1-4 use same register */ 1879792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 1880792d376bSWei Song if (tmp & 0x20) 1881792d376bSWei Song data->enable_dts = 1; 1882792d376bSWei Song else 1883792d376bSWei Song data->enable_dts = 0; 1884792d376bSWei Song data->has_temp = 0; 1885792d376bSWei Song data->temp_mode = 0; 1886792d376bSWei Song if (tmp & 0x08) { 1887792d376bSWei Song if (tmp & 0x04) 1888792d376bSWei Song data->has_temp |= 0x20; 1889792d376bSWei Song else 1890792d376bSWei Song data->has_in |= 0x10000; 1891792d376bSWei Song } 1892792d376bSWei Song if (tmp & 0x02) { 1893792d376bSWei Song if (tmp & 0x01) 1894792d376bSWei Song data->has_temp |= 0x10; 1895792d376bSWei Song else 1896792d376bSWei Song data->has_in |= 0x8000; 1897792d376bSWei Song } 1898792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 1899792d376bSWei Song if (tmp & 0x40) { 1900792d376bSWei Song data->has_temp |= 0x08; 1901792d376bSWei Song if (!(tmp & 0x80)) 1902792d376bSWei Song data->temp_mode |= 0x08; 1903792d376bSWei Song } else if (tmp & 0x80) { 1904792d376bSWei Song data->has_in |= 0x100000; 1905792d376bSWei Song } 1906792d376bSWei Song if (tmp & 0x10) { 1907792d376bSWei Song data->has_temp |= 0x04; 1908792d376bSWei Song if (!(tmp & 0x20)) 1909792d376bSWei Song data->temp_mode |= 0x04; 1910792d376bSWei Song } else if (tmp & 0x20) { 1911792d376bSWei Song data->has_in |= 0x80000; 1912792d376bSWei Song } 1913792d376bSWei Song if (tmp & 0x04) { 1914792d376bSWei Song data->has_temp |= 0x02; 1915792d376bSWei Song if (!(tmp & 0x08)) 1916792d376bSWei Song data->temp_mode |= 0x02; 1917792d376bSWei Song } else if (tmp & 0x08) { 1918792d376bSWei Song data->has_in |= 0x40000; 1919792d376bSWei Song } 1920792d376bSWei Song if (tmp & 0x01) { 1921792d376bSWei Song data->has_temp |= 0x01; 1922792d376bSWei Song if (!(tmp & 0x02)) 1923792d376bSWei Song data->temp_mode |= 0x01; 1924792d376bSWei Song } else if (tmp & 0x02) { 1925792d376bSWei Song data->has_in |= 0x20000; 1926792d376bSWei Song } 1927792d376bSWei Song 1928792d376bSWei Song /* Check DTS enable status */ 1929792d376bSWei Song if (data->enable_dts == 0) { 1930792d376bSWei Song data->has_dts = 0; 1931792d376bSWei Song } else { 1932792d376bSWei Song if (1 & w83795_read(client, W83795_REG_DTSC)) 1933792d376bSWei Song data->enable_dts |= 2; 1934792d376bSWei Song data->has_dts = w83795_read(client, W83795_REG_DTSE); 1935792d376bSWei Song } 1936792d376bSWei Song 1937792d376bSWei Song /* First update the voltages measured value and limits */ 1938792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 1939792d376bSWei Song if (!(data->has_in & (1 << i))) 1940792d376bSWei Song continue; 1941792d376bSWei Song data->in[i][IN_MAX] = 1942792d376bSWei Song w83795_read(client, W83795_REG_IN[i][IN_MAX]); 1943792d376bSWei Song data->in[i][IN_LOW] = 1944792d376bSWei Song w83795_read(client, W83795_REG_IN[i][IN_LOW]); 1945792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 1946792d376bSWei Song tmp |= (w83795_read(client, W83795_REG_VRLSB) 1947792d376bSWei Song >> VRLSB_SHIFT) & 0x03; 1948792d376bSWei Song data->in[i][IN_READ] = tmp; 1949792d376bSWei Song } 1950792d376bSWei Song for (i = 0; i < IN_LSB_REG_NUM; i++) { 1951792d376bSWei Song data->in_lsb[i][IN_MAX] = 1952792d376bSWei Song w83795_read(client, IN_LSB_REG(i, IN_MAX)); 1953792d376bSWei Song data->in_lsb[i][IN_LOW] = 1954792d376bSWei Song w83795_read(client, IN_LSB_REG(i, IN_LOW)); 1955792d376bSWei Song } 1956792d376bSWei Song data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 1957792d376bSWei Song 1958792d376bSWei Song /* First update fan and limits */ 1959792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 1960792d376bSWei Song if (!(data->has_fan & (1 << i))) 1961792d376bSWei Song continue; 1962792d376bSWei Song data->fan_min[i] = 1963792d376bSWei Song w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 1964792d376bSWei Song data->fan_min[i] |= 1965792d376bSWei Song (w83795_read(client, W83795_REG_FAN_MIN_LSB(i) >> 1966792d376bSWei Song W83795_REG_FAN_MIN_LSB_SHIFT(i))) & 0x0F; 1967792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 1968792d376bSWei Song data->fan[i] |= 1969792d376bSWei Song (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F; 1970792d376bSWei Song } 1971792d376bSWei Song 1972792d376bSWei Song /* temperature and limits */ 1973792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 1974792d376bSWei Song if (!(data->has_temp & (1 << i))) 1975792d376bSWei Song continue; 1976792d376bSWei Song data->temp[i][TEMP_CRIT] = 1977792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT]); 1978792d376bSWei Song data->temp[i][TEMP_CRIT_HYST] = 1979792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT_HYST]); 1980792d376bSWei Song data->temp[i][TEMP_WARN] = 1981792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN]); 1982792d376bSWei Song data->temp[i][TEMP_WARN_HYST] = 1983792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]); 1984792d376bSWei Song data->temp[i][TEMP_READ] = 1985792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 1986792d376bSWei Song data->temp_read_vrlsb[i] = 1987792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 1988792d376bSWei Song } 1989792d376bSWei Song 1990792d376bSWei Song /* dts temperature and limits */ 1991792d376bSWei Song if (data->enable_dts != 0) { 1992792d376bSWei Song data->dts_ext[DTS_CRIT] = 1993792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT)); 1994792d376bSWei Song data->dts_ext[DTS_CRIT_HYST] = 1995792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT_HYST)); 1996792d376bSWei Song data->dts_ext[DTS_WARN] = 1997792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN)); 1998792d376bSWei Song data->dts_ext[DTS_WARN_HYST] = 1999792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN_HYST)); 2000792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 2001792d376bSWei Song if (!(data->has_dts & (1 << i))) 2002792d376bSWei Song continue; 2003792d376bSWei Song data->dts[i] = w83795_read(client, W83795_REG_DTS(i)); 2004792d376bSWei Song data->dts_read_vrlsb[i] = 2005792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 2006792d376bSWei Song } 2007792d376bSWei Song } 2008792d376bSWei Song 2009792d376bSWei Song /* First update temp source selction */ 2010792d376bSWei Song for (i = 0; i < 3; i++) 2011792d376bSWei Song data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 2012792d376bSWei Song 2013792d376bSWei Song /* pwm and smart fan */ 2014792d376bSWei Song if (data->chip_type == w83795g) 2015792d376bSWei Song data->has_pwm = 8; 2016792d376bSWei Song else 2017792d376bSWei Song data->has_pwm = 2; 2018792d376bSWei Song data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 2019792d376bSWei Song data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 2020792d376bSWei Song /* w83795adg only support pwm2-0 */ 2021792d376bSWei Song for (i = 0; i < W83795_REG_TEMP_NUM; i++) 2022792d376bSWei Song data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 2023792d376bSWei Song data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 2024792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 2025792d376bSWei Song for (tmp = 0; tmp < 5; tmp++) { 2026792d376bSWei Song data->pwm[i][tmp] = 2027792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, tmp)); 2028792d376bSWei Song } 2029792d376bSWei Song } 2030792d376bSWei Song for (i = 0; i < 8; i++) { 2031792d376bSWei Song data->target_speed[i] = 2032792d376bSWei Song w83795_read(client, W83795_REG_FTSH(i)) << 4; 2033792d376bSWei Song data->target_speed[i] |= 2034792d376bSWei Song w83795_read(client, W83795_REG_FTSL(i)) >> 4; 2035792d376bSWei Song } 2036792d376bSWei Song data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 2037792d376bSWei Song 2038792d376bSWei Song for (i = 0; i < W83795_REG_TEMP_NUM; i++) { 2039792d376bSWei Song data->pwm_temp[i][TEMP_PWM_TTTI] = 2040792d376bSWei Song w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 2041792d376bSWei Song data->pwm_temp[i][TEMP_PWM_CTFS] = 2042792d376bSWei Song w83795_read(client, W83795_REG_CTFS(i)); 2043792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(i)); 2044792d376bSWei Song data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; 2045792d376bSWei Song data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 2046792d376bSWei Song } 2047792d376bSWei Song for (i = 0; i < W83795_REG_TEMP_NUM; i++) { 2048792d376bSWei Song for (tmp = 0; tmp < 7; tmp++) { 2049792d376bSWei Song data->sf4_reg[i][SF4_TEMP][tmp] = 2050792d376bSWei Song w83795_read(client, 2051792d376bSWei Song W83795_REG_SF4_TEMP(i, tmp)); 2052792d376bSWei Song data->sf4_reg[i][SF4_PWM][tmp] = 2053792d376bSWei Song w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 2054792d376bSWei Song } 2055792d376bSWei Song } 2056792d376bSWei Song 2057792d376bSWei Song /* Setup PWM Register */ 2058792d376bSWei Song for (i = 0; i < 3; i++) { 2059792d376bSWei Song data->setup_pwm[i] = 2060792d376bSWei Song w83795_read(client, W83795_REG_SETUP_PWM(i)); 2061792d376bSWei Song } 2062792d376bSWei Song 2063792d376bSWei Song /* alarm and beep */ 2064792d376bSWei Song for (i = 0; i < ALARM_BEEP_REG_NUM; i++) { 2065792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 2066792d376bSWei Song data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); 2067792d376bSWei Song } 2068792d376bSWei Song data->beep_enable = 2069792d376bSWei Song (w83795_read(client, W83795_REG_BEEP(5)) >> 7) & 0x01; 2070792d376bSWei Song 20716f3dcde9SJean Delvare err = w83795_handle_files(dev, device_create_file); 2072792d376bSWei Song if (err) 2073792d376bSWei Song goto exit_remove; 2074792d376bSWei Song 2075792d376bSWei Song data->hwmon_dev = hwmon_device_register(dev); 2076792d376bSWei Song if (IS_ERR(data->hwmon_dev)) { 2077792d376bSWei Song err = PTR_ERR(data->hwmon_dev); 2078792d376bSWei Song goto exit_remove; 2079792d376bSWei Song } 2080792d376bSWei Song 2081792d376bSWei Song return 0; 2082792d376bSWei Song 2083792d376bSWei Song exit_remove: 20846f3dcde9SJean Delvare w83795_handle_files(dev, device_remove_file_wrapper); 2085792d376bSWei Song kfree(data); 2086792d376bSWei Song exit: 2087792d376bSWei Song return err; 2088792d376bSWei Song } 2089792d376bSWei Song 2090792d376bSWei Song static int w83795_remove(struct i2c_client *client) 2091792d376bSWei Song { 2092792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 2093792d376bSWei Song 2094792d376bSWei Song hwmon_device_unregister(data->hwmon_dev); 20956f3dcde9SJean Delvare w83795_handle_files(&client->dev, device_remove_file_wrapper); 2096792d376bSWei Song kfree(data); 2097792d376bSWei Song 2098792d376bSWei Song return 0; 2099792d376bSWei Song } 2100792d376bSWei Song 2101792d376bSWei Song 2102792d376bSWei Song static const struct i2c_device_id w83795_id[] = { 2103093d1a47SJean Delvare { "w83795g", w83795g }, 2104093d1a47SJean Delvare { "w83795adg", w83795adg }, 2105792d376bSWei Song { } 2106792d376bSWei Song }; 2107792d376bSWei Song MODULE_DEVICE_TABLE(i2c, w83795_id); 2108792d376bSWei Song 2109792d376bSWei Song static struct i2c_driver w83795_driver = { 2110792d376bSWei Song .driver = { 2111792d376bSWei Song .name = "w83795", 2112792d376bSWei Song }, 2113792d376bSWei Song .probe = w83795_probe, 2114792d376bSWei Song .remove = w83795_remove, 2115792d376bSWei Song .id_table = w83795_id, 2116792d376bSWei Song 2117792d376bSWei Song .class = I2C_CLASS_HWMON, 2118792d376bSWei Song .detect = w83795_detect, 2119792d376bSWei Song .address_list = normal_i2c, 2120792d376bSWei Song }; 2121792d376bSWei Song 2122792d376bSWei Song static int __init sensors_w83795_init(void) 2123792d376bSWei Song { 2124792d376bSWei Song return i2c_add_driver(&w83795_driver); 2125792d376bSWei Song } 2126792d376bSWei Song 2127792d376bSWei Song static void __exit sensors_w83795_exit(void) 2128792d376bSWei Song { 2129792d376bSWei Song i2c_del_driver(&w83795_driver); 2130792d376bSWei Song } 2131792d376bSWei Song 2132792d376bSWei Song MODULE_AUTHOR("Wei Song"); 2133315bacfdSJean Delvare MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 2134792d376bSWei Song MODULE_LICENSE("GPL"); 2135792d376bSWei Song 2136792d376bSWei Song module_init(sensors_w83795_init); 2137792d376bSWei Song module_exit(sensors_w83795_exit); 2138