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 204792d376bSWei Song #define W83795_REG_TSS(index) (0x209 + (index)) 205792d376bSWei Song 206792d376bSWei Song #define PWM_OUTPUT 0 207792d376bSWei Song #define PWM_START 1 208792d376bSWei Song #define PWM_NONSTOP 2 209792d376bSWei Song #define PWM_STOP_TIME 3 21001879a85SJean Delvare #define PWM_FREQ 4 211792d376bSWei Song #define W83795_REG_PWM(index, nr) \ 212792d376bSWei Song (((nr) == 0 ? 0x210 : \ 213792d376bSWei Song (nr) == 1 ? 0x220 : \ 214792d376bSWei Song (nr) == 2 ? 0x228 : \ 215792d376bSWei Song (nr) == 3 ? 0x230 : 0x218) + (index)) 216792d376bSWei Song 217792d376bSWei Song #define W83795_REG_FTSH(index) (0x240 + (index) * 2) 218792d376bSWei Song #define W83795_REG_FTSL(index) (0x241 + (index) * 2) 219792d376bSWei Song #define W83795_REG_TFTS 0x250 220792d376bSWei Song 221792d376bSWei Song #define TEMP_PWM_TTTI 0 222792d376bSWei Song #define TEMP_PWM_CTFS 1 223792d376bSWei Song #define TEMP_PWM_HCT 2 224792d376bSWei Song #define TEMP_PWM_HOT 3 225792d376bSWei Song #define W83795_REG_TTTI(index) (0x260 + (index)) 226792d376bSWei Song #define W83795_REG_CTFS(index) (0x268 + (index)) 227792d376bSWei Song #define W83795_REG_HT(index) (0x270 + (index)) 228792d376bSWei Song 229792d376bSWei Song #define SF4_TEMP 0 230792d376bSWei Song #define SF4_PWM 1 231792d376bSWei Song #define W83795_REG_SF4_TEMP(temp_num, index) \ 232792d376bSWei Song (0x280 + 0x10 * (temp_num) + (index)) 233792d376bSWei Song #define W83795_REG_SF4_PWM(temp_num, index) \ 234792d376bSWei Song (0x288 + 0x10 * (temp_num) + (index)) 235792d376bSWei Song 236792d376bSWei Song #define W83795_REG_DTSC 0x301 237792d376bSWei Song #define W83795_REG_DTSE 0x302 238792d376bSWei Song #define W83795_REG_DTS(index) (0x26 + (index)) 239792d376bSWei Song 240792d376bSWei Song #define DTS_CRIT 0 241792d376bSWei Song #define DTS_CRIT_HYST 1 242792d376bSWei Song #define DTS_WARN 2 243792d376bSWei Song #define DTS_WARN_HYST 3 244792d376bSWei Song #define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 245792d376bSWei Song 246792d376bSWei Song #define SETUP_PWM_DEFAULT 0 247792d376bSWei Song #define SETUP_PWM_UPTIME 1 248792d376bSWei Song #define SETUP_PWM_DOWNTIME 2 249792d376bSWei Song #define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 250792d376bSWei Song 251792d376bSWei Song static inline u16 in_from_reg(u8 index, u16 val) 252792d376bSWei Song { 253792d376bSWei Song if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) 254792d376bSWei Song return val * 6; 255792d376bSWei Song else 256792d376bSWei Song return val * 2; 257792d376bSWei Song } 258792d376bSWei Song 259792d376bSWei Song static inline u16 in_to_reg(u8 index, u16 val) 260792d376bSWei Song { 261792d376bSWei Song if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) 262792d376bSWei Song return val / 6; 263792d376bSWei Song else 264792d376bSWei Song return val / 2; 265792d376bSWei Song } 266792d376bSWei Song 267792d376bSWei Song static inline unsigned long fan_from_reg(u16 val) 268792d376bSWei Song { 2696c82b2f3SJean Delvare if ((val == 0xfff) || (val == 0)) 270792d376bSWei Song return 0; 271792d376bSWei Song return 1350000UL / val; 272792d376bSWei Song } 273792d376bSWei Song 274792d376bSWei Song static inline u16 fan_to_reg(long rpm) 275792d376bSWei Song { 276792d376bSWei Song if (rpm <= 0) 277792d376bSWei Song return 0x0fff; 278792d376bSWei Song return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 279792d376bSWei Song } 280792d376bSWei Song 281792d376bSWei Song static inline unsigned long time_from_reg(u8 reg) 282792d376bSWei Song { 283792d376bSWei Song return reg * 100; 284792d376bSWei Song } 285792d376bSWei Song 286792d376bSWei Song static inline u8 time_to_reg(unsigned long val) 287792d376bSWei Song { 288792d376bSWei Song return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); 289792d376bSWei Song } 290792d376bSWei Song 291792d376bSWei Song static inline long temp_from_reg(s8 reg) 292792d376bSWei Song { 293792d376bSWei Song return reg * 1000; 294792d376bSWei Song } 295792d376bSWei Song 296792d376bSWei Song static inline s8 temp_to_reg(long val, s8 min, s8 max) 297792d376bSWei Song { 298792d376bSWei Song return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); 299792d376bSWei Song } 300792d376bSWei Song 30101879a85SJean Delvare static const u16 pwm_freq_cksel0[16] = { 30201879a85SJean Delvare 1024, 512, 341, 256, 205, 171, 146, 128, 30301879a85SJean Delvare 85, 64, 32, 16, 8, 4, 2, 1 30401879a85SJean Delvare }; 30501879a85SJean Delvare 30601879a85SJean Delvare static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) 30701879a85SJean Delvare { 30801879a85SJean Delvare unsigned long base_clock; 30901879a85SJean Delvare 31001879a85SJean Delvare if (reg & 0x80) { 31101879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 31201879a85SJean Delvare return base_clock / ((reg & 0x7f) + 1); 31301879a85SJean Delvare } else 31401879a85SJean Delvare return pwm_freq_cksel0[reg & 0x0f]; 31501879a85SJean Delvare } 31601879a85SJean Delvare 31701879a85SJean Delvare static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) 31801879a85SJean Delvare { 31901879a85SJean Delvare unsigned long base_clock; 32001879a85SJean Delvare u8 reg0, reg1; 32101879a85SJean Delvare unsigned long best0, best1; 32201879a85SJean Delvare 32301879a85SJean Delvare /* Best fit for cksel = 0 */ 32401879a85SJean Delvare for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { 32501879a85SJean Delvare if (val > (pwm_freq_cksel0[reg0] + 32601879a85SJean Delvare pwm_freq_cksel0[reg0 + 1]) / 2) 32701879a85SJean Delvare break; 32801879a85SJean Delvare } 32901879a85SJean Delvare if (val < 375) /* cksel = 1 can't beat this */ 33001879a85SJean Delvare return reg0; 33101879a85SJean Delvare best0 = pwm_freq_cksel0[reg0]; 33201879a85SJean Delvare 33301879a85SJean Delvare /* Best fit for cksel = 1 */ 33401879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 33501879a85SJean Delvare reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); 33601879a85SJean Delvare best1 = base_clock / reg1; 33701879a85SJean Delvare reg1 = 0x80 | (reg1 - 1); 33801879a85SJean Delvare 33901879a85SJean Delvare /* Choose the closest one */ 34001879a85SJean Delvare if (abs(val - best0) > abs(val - best1)) 34101879a85SJean Delvare return reg1; 34201879a85SJean Delvare else 34301879a85SJean Delvare return reg0; 34401879a85SJean Delvare } 345792d376bSWei Song 346792d376bSWei Song enum chip_types {w83795g, w83795adg}; 347792d376bSWei Song 348792d376bSWei Song struct w83795_data { 349792d376bSWei Song struct device *hwmon_dev; 350792d376bSWei Song struct mutex update_lock; 351792d376bSWei Song unsigned long last_updated; /* In jiffies */ 352792d376bSWei Song enum chip_types chip_type; 353792d376bSWei Song 354792d376bSWei Song u8 bank; 355792d376bSWei Song 356792d376bSWei Song u32 has_in; /* Enable monitor VIN or not */ 3570e256018SJean Delvare u8 has_dyn_in; /* Only in2-0 can have this */ 358792d376bSWei Song u16 in[21][3]; /* Register value, read/high/low */ 359792d376bSWei Song u8 in_lsb[10][3]; /* LSB Register value, high/low */ 360792d376bSWei Song u8 has_gain; /* has gain: in17-20 * 8 */ 361792d376bSWei Song 362792d376bSWei Song u16 has_fan; /* Enable fan14-1 or not */ 363792d376bSWei Song u16 fan[14]; /* Register value combine */ 364792d376bSWei Song u16 fan_min[14]; /* Register value combine */ 365792d376bSWei Song 366792d376bSWei Song u8 has_temp; /* Enable monitor temp6-1 or not */ 367792d376bSWei Song u8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 368792d376bSWei Song u8 temp_read_vrlsb[6]; 369792d376bSWei Song u8 temp_mode; /* bit 0: TR mode, bit 1: TD mode */ 370792d376bSWei Song u8 temp_src[3]; /* Register value */ 371792d376bSWei Song 372792d376bSWei Song u8 enable_dts; /* Enable PECI and SB-TSI, 373792d376bSWei Song * bit 0: =1 enable, =0 disable, 374792d376bSWei Song * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ 375792d376bSWei Song u8 has_dts; /* Enable monitor DTS temp */ 376792d376bSWei Song u8 dts[8]; /* Register value */ 377792d376bSWei Song u8 dts_read_vrlsb[8]; /* Register value */ 378792d376bSWei Song u8 dts_ext[4]; /* Register value */ 379792d376bSWei Song 380792d376bSWei Song u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, 381792d376bSWei Song * no config register, only affected by chip 382792d376bSWei Song * type */ 383792d376bSWei Song u8 pwm[8][5]; /* Register value, output, start, non stop, stop 38401879a85SJean Delvare * time, freq */ 38501879a85SJean Delvare u16 clkin; /* CLKIN frequency in kHz */ 386792d376bSWei Song u8 pwm_fcms[2]; /* Register value */ 387792d376bSWei Song u8 pwm_tfmr[6]; /* Register value */ 388792d376bSWei Song u8 pwm_fomc; /* Register value */ 389792d376bSWei Song 390792d376bSWei Song u16 target_speed[8]; /* Register value, target speed for speed 391792d376bSWei Song * cruise */ 392792d376bSWei Song u8 tol_speed; /* tolerance of target speed */ 393792d376bSWei Song u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 394792d376bSWei Song u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 395792d376bSWei Song 396792d376bSWei Song u8 setup_pwm[3]; /* Register value */ 397792d376bSWei Song 398792d376bSWei Song u8 alarms[6]; /* Register value */ 399792d376bSWei Song u8 beeps[6]; /* Register value */ 400792d376bSWei Song u8 beep_enable; 401792d376bSWei Song 402792d376bSWei Song char valid; 403792d376bSWei Song }; 404792d376bSWei Song 405792d376bSWei Song /* 406792d376bSWei Song * Hardware access 407b2469f42SJean Delvare * We assume that nobdody can change the bank outside the driver. 408792d376bSWei Song */ 409792d376bSWei Song 410b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 411b2469f42SJean Delvare static int w83795_set_bank(struct i2c_client *client, u8 bank) 412792d376bSWei Song { 413792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 414b2469f42SJean Delvare int err; 415792d376bSWei Song 416b2469f42SJean Delvare /* If the same bank is already set, nothing to do */ 417b2469f42SJean Delvare if ((data->bank & 0x07) == bank) 418b2469f42SJean Delvare return 0; 419b2469f42SJean Delvare 420b2469f42SJean Delvare /* Change to new bank, preserve all other bits */ 421b2469f42SJean Delvare bank |= data->bank & ~0x07; 422b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 423b2469f42SJean Delvare if (err < 0) { 424792d376bSWei Song dev_err(&client->dev, 425b2469f42SJean Delvare "Failed to set bank to %d, err %d\n", 426b2469f42SJean Delvare (int)bank, err); 427b2469f42SJean Delvare return err; 428792d376bSWei Song } 429b2469f42SJean Delvare data->bank = bank; 430b2469f42SJean Delvare 431b2469f42SJean Delvare return 0; 432792d376bSWei Song } 433b2469f42SJean Delvare 434b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 435b2469f42SJean Delvare static u8 w83795_read(struct i2c_client *client, u16 reg) 436b2469f42SJean Delvare { 437b2469f42SJean Delvare int err; 438b2469f42SJean Delvare 439b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 440b2469f42SJean Delvare if (err < 0) 441b2469f42SJean Delvare return 0x00; /* Arbitrary */ 442b2469f42SJean Delvare 443b2469f42SJean Delvare err = i2c_smbus_read_byte_data(client, reg & 0xff); 444b2469f42SJean Delvare if (err < 0) { 445b2469f42SJean Delvare dev_err(&client->dev, 446b2469f42SJean Delvare "Failed to read from register 0x%03x, err %d\n", 447b2469f42SJean Delvare (int)reg, err); 448b2469f42SJean Delvare return 0x00; /* Arbitrary */ 449b2469f42SJean Delvare } 450b2469f42SJean Delvare return err; 451792d376bSWei Song } 452792d376bSWei Song 453792d376bSWei Song /* Must be called with data->update_lock held, except during initialization */ 454792d376bSWei Song static int w83795_write(struct i2c_client *client, u16 reg, u8 value) 455792d376bSWei Song { 456b2469f42SJean Delvare int err; 457792d376bSWei Song 458b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 459b2469f42SJean Delvare if (err < 0) 460b2469f42SJean Delvare return err; 461b2469f42SJean Delvare 462b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 463b2469f42SJean Delvare if (err < 0) 464792d376bSWei Song dev_err(&client->dev, 465b2469f42SJean Delvare "Failed to write to register 0x%03x, err %d\n", 466b2469f42SJean Delvare (int)reg, err); 467b2469f42SJean Delvare return err; 468792d376bSWei Song } 469792d376bSWei Song 470792d376bSWei Song static struct w83795_data *w83795_update_device(struct device *dev) 471792d376bSWei Song { 472792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 473792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 474792d376bSWei Song u16 tmp; 475792d376bSWei Song int i; 476792d376bSWei Song 477792d376bSWei Song mutex_lock(&data->update_lock); 478792d376bSWei Song 479792d376bSWei Song if (!(time_after(jiffies, data->last_updated + HZ * 2) 480792d376bSWei Song || !data->valid)) 481792d376bSWei Song goto END; 482792d376bSWei Song 483792d376bSWei Song /* Update the voltages value */ 484792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 485792d376bSWei Song if (!(data->has_in & (1 << i))) 486792d376bSWei Song continue; 487792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 488792d376bSWei Song tmp |= (w83795_read(client, W83795_REG_VRLSB) 489792d376bSWei Song >> VRLSB_SHIFT) & 0x03; 490792d376bSWei Song data->in[i][IN_READ] = tmp; 491792d376bSWei Song } 492792d376bSWei Song 4930e256018SJean Delvare /* in0-2 can have dynamic limits (W83795G only) */ 4940e256018SJean Delvare if (data->has_dyn_in) { 4950e256018SJean Delvare u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); 4960e256018SJean Delvare u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); 4970e256018SJean Delvare 4980e256018SJean Delvare for (i = 0; i < 3; i++) { 4990e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 5000e256018SJean Delvare continue; 5010e256018SJean Delvare data->in[i][IN_MAX] = 5020e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 5030e256018SJean Delvare data->in[i][IN_LOW] = 5040e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 5050e256018SJean Delvare data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; 5060e256018SJean Delvare data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; 5070e256018SJean Delvare } 5080e256018SJean Delvare } 5090e256018SJean Delvare 510792d376bSWei Song /* Update fan */ 511792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 512792d376bSWei Song if (!(data->has_fan & (1 << i))) 513792d376bSWei Song continue; 514792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 515792d376bSWei Song data->fan[i] |= 5166c82b2f3SJean Delvare (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; 517792d376bSWei Song } 518792d376bSWei Song 519792d376bSWei Song /* Update temperature */ 520792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 521792d376bSWei Song /* even stop monitor, register still keep value, just read out 522792d376bSWei Song * it */ 523792d376bSWei Song if (!(data->has_temp & (1 << i))) { 524792d376bSWei Song data->temp[i][TEMP_READ] = 0; 525792d376bSWei Song data->temp_read_vrlsb[i] = 0; 526792d376bSWei Song continue; 527792d376bSWei Song } 528792d376bSWei Song data->temp[i][TEMP_READ] = 529792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 530792d376bSWei Song data->temp_read_vrlsb[i] = 531792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 532792d376bSWei Song } 533792d376bSWei Song 534792d376bSWei Song /* Update dts temperature */ 535792d376bSWei Song if (data->enable_dts != 0) { 536792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 537792d376bSWei Song if (!(data->has_dts & (1 << i))) 538792d376bSWei Song continue; 539792d376bSWei Song data->dts[i] = 540792d376bSWei Song w83795_read(client, W83795_REG_DTS(i)); 541792d376bSWei Song data->dts_read_vrlsb[i] = 542792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 543792d376bSWei Song } 544792d376bSWei Song } 545792d376bSWei Song 546792d376bSWei Song /* Update pwm output */ 547792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 548792d376bSWei Song data->pwm[i][PWM_OUTPUT] = 549792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 550792d376bSWei Song } 551792d376bSWei Song 552792d376bSWei Song /* update alarm */ 553792d376bSWei Song for (i = 0; i < ALARM_BEEP_REG_NUM; i++) 554792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 555792d376bSWei Song 556792d376bSWei Song data->last_updated = jiffies; 557792d376bSWei Song data->valid = 1; 558792d376bSWei Song 559792d376bSWei Song END: 560792d376bSWei Song mutex_unlock(&data->update_lock); 561792d376bSWei Song return data; 562792d376bSWei Song } 563792d376bSWei Song 564792d376bSWei Song /* 565792d376bSWei Song * Sysfs attributes 566792d376bSWei Song */ 567792d376bSWei Song 568792d376bSWei Song #define ALARM_STATUS 0 569792d376bSWei Song #define BEEP_ENABLE 1 570792d376bSWei Song static ssize_t 571792d376bSWei Song show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 572792d376bSWei Song { 573792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 574792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 575792d376bSWei Song to_sensor_dev_attr_2(attr); 576792d376bSWei Song int nr = sensor_attr->nr; 577792d376bSWei Song int index = sensor_attr->index >> 3; 578792d376bSWei Song int bit = sensor_attr->index & 0x07; 579792d376bSWei Song u8 val; 580792d376bSWei Song 581792d376bSWei Song if (ALARM_STATUS == nr) { 582792d376bSWei Song val = (data->alarms[index] >> (bit)) & 1; 583792d376bSWei Song } else { /* BEEP_ENABLE */ 584792d376bSWei Song val = (data->beeps[index] >> (bit)) & 1; 585792d376bSWei Song } 586792d376bSWei Song 587792d376bSWei Song return sprintf(buf, "%u\n", val); 588792d376bSWei Song } 589792d376bSWei Song 590792d376bSWei Song static ssize_t 591792d376bSWei Song store_beep(struct device *dev, struct device_attribute *attr, 592792d376bSWei Song const char *buf, size_t count) 593792d376bSWei Song { 594792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 595792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 596792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 597792d376bSWei Song to_sensor_dev_attr_2(attr); 598792d376bSWei Song int index = sensor_attr->index >> 3; 599792d376bSWei Song int shift = sensor_attr->index & 0x07; 600792d376bSWei Song u8 beep_bit = 1 << shift; 601792d376bSWei Song unsigned long val; 602792d376bSWei Song 603792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 604792d376bSWei Song return -EINVAL; 605792d376bSWei Song if (val != 0 && val != 1) 606792d376bSWei Song return -EINVAL; 607792d376bSWei Song 608792d376bSWei Song mutex_lock(&data->update_lock); 609792d376bSWei Song data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 610792d376bSWei Song data->beeps[index] &= ~beep_bit; 611792d376bSWei Song data->beeps[index] |= val << shift; 612792d376bSWei Song w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 613792d376bSWei Song mutex_unlock(&data->update_lock); 614792d376bSWei Song 615792d376bSWei Song return count; 616792d376bSWei Song } 617792d376bSWei Song 618792d376bSWei Song static ssize_t 619792d376bSWei Song show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf) 620792d376bSWei Song { 621792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 622792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 623792d376bSWei Song return sprintf(buf, "%u\n", data->beep_enable); 624792d376bSWei Song } 625792d376bSWei Song 626792d376bSWei Song static ssize_t 627792d376bSWei Song store_beep_enable(struct device *dev, struct device_attribute *attr, 628792d376bSWei Song const char *buf, size_t count) 629792d376bSWei Song { 630792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 631792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 632792d376bSWei Song unsigned long val; 633792d376bSWei Song u8 tmp; 634792d376bSWei Song 635792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 636792d376bSWei Song return -EINVAL; 637792d376bSWei Song if (val != 0 && val != 1) 638792d376bSWei Song return -EINVAL; 639792d376bSWei Song 640792d376bSWei Song mutex_lock(&data->update_lock); 641792d376bSWei Song data->beep_enable = val; 642792d376bSWei Song tmp = w83795_read(client, W83795_REG_BEEP(5)); 643792d376bSWei Song tmp &= 0x7f; 644792d376bSWei Song tmp |= val << 7; 645792d376bSWei Song w83795_write(client, W83795_REG_BEEP(5), tmp); 646792d376bSWei Song mutex_unlock(&data->update_lock); 647792d376bSWei Song 648792d376bSWei Song return count; 649792d376bSWei Song } 650792d376bSWei Song 651792d376bSWei Song /* Write any value to clear chassis alarm */ 652792d376bSWei Song static ssize_t 653792d376bSWei Song store_chassis_clear(struct device *dev, 654792d376bSWei Song struct device_attribute *attr, const char *buf, 655792d376bSWei Song size_t count) 656792d376bSWei Song { 657792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 658792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 659792d376bSWei Song u8 val; 660792d376bSWei Song 661792d376bSWei Song mutex_lock(&data->update_lock); 662792d376bSWei Song val = w83795_read(client, W83795_REG_CLR_CHASSIS); 663792d376bSWei Song val |= 0x80; 664792d376bSWei Song w83795_write(client, W83795_REG_CLR_CHASSIS, val); 665792d376bSWei Song mutex_unlock(&data->update_lock); 666792d376bSWei Song return count; 667792d376bSWei Song } 668792d376bSWei Song 669792d376bSWei Song #define FAN_INPUT 0 670792d376bSWei Song #define FAN_MIN 1 671792d376bSWei Song static ssize_t 672792d376bSWei Song show_fan(struct device *dev, struct device_attribute *attr, char *buf) 673792d376bSWei Song { 674792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 675792d376bSWei Song to_sensor_dev_attr_2(attr); 676792d376bSWei Song int nr = sensor_attr->nr; 677792d376bSWei Song int index = sensor_attr->index; 678792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 679792d376bSWei Song u16 val; 680792d376bSWei Song 681792d376bSWei Song if (FAN_INPUT == nr) 682792d376bSWei Song val = data->fan[index] & 0x0fff; 683792d376bSWei Song else 684792d376bSWei Song val = data->fan_min[index] & 0x0fff; 685792d376bSWei Song 686792d376bSWei Song return sprintf(buf, "%lu\n", fan_from_reg(val)); 687792d376bSWei Song } 688792d376bSWei Song 689792d376bSWei Song static ssize_t 690792d376bSWei Song store_fan_min(struct device *dev, struct device_attribute *attr, 691792d376bSWei Song const char *buf, size_t count) 692792d376bSWei Song { 693792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 694792d376bSWei Song to_sensor_dev_attr_2(attr); 695792d376bSWei Song int index = sensor_attr->index; 696792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 697792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 698792d376bSWei Song unsigned long val; 699792d376bSWei Song 700792d376bSWei Song if (strict_strtoul(buf, 10, &val)) 701792d376bSWei Song return -EINVAL; 702792d376bSWei Song val = fan_to_reg(val); 703792d376bSWei Song 704792d376bSWei Song mutex_lock(&data->update_lock); 705792d376bSWei Song data->fan_min[index] = val; 706792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 707792d376bSWei Song val &= 0x0f; 708792d376bSWei Song if (index % 1) { 709792d376bSWei Song val <<= 4; 710792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 711792d376bSWei Song & 0x0f; 712792d376bSWei Song } else { 713792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 714792d376bSWei Song & 0xf0; 715792d376bSWei Song } 716792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 717792d376bSWei Song mutex_unlock(&data->update_lock); 718792d376bSWei Song 719792d376bSWei Song return count; 720792d376bSWei Song } 721792d376bSWei Song 722792d376bSWei Song static ssize_t 723792d376bSWei Song show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 724792d376bSWei Song { 725792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 726792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 727792d376bSWei Song to_sensor_dev_attr_2(attr); 728792d376bSWei Song int nr = sensor_attr->nr; 729792d376bSWei Song int index = sensor_attr->index; 73001879a85SJean Delvare unsigned int val; 731792d376bSWei Song 732792d376bSWei Song switch (nr) { 733792d376bSWei Song case PWM_STOP_TIME: 734792d376bSWei Song val = time_from_reg(data->pwm[index][nr]); 735792d376bSWei Song break; 73601879a85SJean Delvare case PWM_FREQ: 73701879a85SJean Delvare val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); 738792d376bSWei Song break; 739792d376bSWei Song default: 740792d376bSWei Song val = data->pwm[index][nr]; 741792d376bSWei Song break; 742792d376bSWei Song } 743792d376bSWei Song 744792d376bSWei Song return sprintf(buf, "%u\n", val); 745792d376bSWei Song } 746792d376bSWei Song 747792d376bSWei Song static ssize_t 748792d376bSWei Song store_pwm(struct device *dev, struct device_attribute *attr, 749792d376bSWei Song const char *buf, size_t count) 750792d376bSWei Song { 751792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 752792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 753792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 754792d376bSWei Song to_sensor_dev_attr_2(attr); 755792d376bSWei Song int nr = sensor_attr->nr; 756792d376bSWei Song int index = sensor_attr->index; 757792d376bSWei Song unsigned long val; 758792d376bSWei Song 759792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 760792d376bSWei Song return -EINVAL; 761792d376bSWei Song 762792d376bSWei Song mutex_lock(&data->update_lock); 763792d376bSWei Song switch (nr) { 764792d376bSWei Song case PWM_STOP_TIME: 765792d376bSWei Song val = time_to_reg(val); 766792d376bSWei Song break; 76701879a85SJean Delvare case PWM_FREQ: 76801879a85SJean Delvare val = pwm_freq_to_reg(val, data->clkin); 769792d376bSWei Song break; 770792d376bSWei Song default: 771792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 772792d376bSWei Song break; 773792d376bSWei Song } 774792d376bSWei Song w83795_write(client, W83795_REG_PWM(index, nr), val); 77501879a85SJean Delvare data->pwm[index][nr] = val; 776792d376bSWei Song mutex_unlock(&data->update_lock); 777792d376bSWei Song return count; 778792d376bSWei Song } 779792d376bSWei Song 780792d376bSWei Song static ssize_t 781792d376bSWei Song show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 782792d376bSWei Song { 783792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 784792d376bSWei Song to_sensor_dev_attr_2(attr); 785792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 786792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 787792d376bSWei Song int index = sensor_attr->index; 788792d376bSWei Song u8 tmp; 789792d376bSWei Song 790792d376bSWei Song if (1 == (data->pwm_fcms[0] & (1 << index))) { 791792d376bSWei Song tmp = 2; 792792d376bSWei Song goto out; 793792d376bSWei Song } 794792d376bSWei Song for (tmp = 0; tmp < 6; tmp++) { 795792d376bSWei Song if (data->pwm_tfmr[tmp] & (1 << index)) { 796792d376bSWei Song tmp = 3; 797792d376bSWei Song goto out; 798792d376bSWei Song } 799792d376bSWei Song } 800792d376bSWei Song if (data->pwm_fomc & (1 << index)) 801792d376bSWei Song tmp = 0; 802792d376bSWei Song else 803792d376bSWei Song tmp = 1; 804792d376bSWei Song 805792d376bSWei Song out: 806792d376bSWei Song return sprintf(buf, "%u\n", tmp); 807792d376bSWei Song } 808792d376bSWei Song 809792d376bSWei Song static ssize_t 810792d376bSWei Song store_pwm_enable(struct device *dev, struct device_attribute *attr, 811792d376bSWei Song const char *buf, size_t count) 812792d376bSWei Song { 813792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 814792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 815792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 816792d376bSWei Song to_sensor_dev_attr_2(attr); 817792d376bSWei Song int index = sensor_attr->index; 818792d376bSWei Song unsigned long val; 819792d376bSWei Song int i; 820792d376bSWei Song 821792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 822792d376bSWei Song return -EINVAL; 823792d376bSWei Song if (val > 2) 824792d376bSWei Song return -EINVAL; 825792d376bSWei Song 826792d376bSWei Song mutex_lock(&data->update_lock); 827792d376bSWei Song switch (val) { 828792d376bSWei Song case 0: 829792d376bSWei Song case 1: 830792d376bSWei Song data->pwm_fcms[0] &= ~(1 << index); 831792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 832792d376bSWei Song for (i = 0; i < 6; i++) { 833792d376bSWei Song data->pwm_tfmr[i] &= ~(1 << index); 834792d376bSWei Song w83795_write(client, W83795_REG_TFMR(i), 835792d376bSWei Song data->pwm_tfmr[i]); 836792d376bSWei Song } 837792d376bSWei Song data->pwm_fomc |= 1 << index; 838792d376bSWei Song data->pwm_fomc ^= val << index; 839792d376bSWei Song w83795_write(client, W83795_REG_FOMC, data->pwm_fomc); 840792d376bSWei Song break; 841792d376bSWei Song case 2: 842792d376bSWei Song data->pwm_fcms[0] |= (1 << index); 843792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 844792d376bSWei Song break; 845792d376bSWei Song } 846792d376bSWei Song mutex_unlock(&data->update_lock); 847792d376bSWei Song return count; 848792d376bSWei Song } 849792d376bSWei Song 850792d376bSWei Song static ssize_t 851792d376bSWei Song show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 852792d376bSWei Song { 853792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 854792d376bSWei Song to_sensor_dev_attr_2(attr); 855792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 856792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 857792d376bSWei Song int index = sensor_attr->index; 858792d376bSWei Song u8 val = index / 2; 859792d376bSWei Song u8 tmp = data->temp_src[val]; 860792d376bSWei Song 861792d376bSWei Song if (index % 1) 862792d376bSWei Song val = 4; 863792d376bSWei Song else 864792d376bSWei Song val = 0; 865792d376bSWei Song tmp >>= val; 866792d376bSWei Song tmp &= 0x0f; 867792d376bSWei Song 868792d376bSWei Song return sprintf(buf, "%u\n", tmp); 869792d376bSWei Song } 870792d376bSWei Song 871792d376bSWei Song static ssize_t 872792d376bSWei Song store_temp_src(struct device *dev, struct device_attribute *attr, 873792d376bSWei Song const char *buf, size_t count) 874792d376bSWei Song { 875792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 876792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 877792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 878792d376bSWei Song to_sensor_dev_attr_2(attr); 879792d376bSWei Song int index = sensor_attr->index; 880792d376bSWei Song unsigned long tmp; 881792d376bSWei Song u8 val = index / 2; 882792d376bSWei Song 883792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 884792d376bSWei Song return -EINVAL; 885792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 15); 886792d376bSWei Song 887792d376bSWei Song mutex_lock(&data->update_lock); 888792d376bSWei Song if (index % 1) { 889792d376bSWei Song tmp <<= 4; 890792d376bSWei Song data->temp_src[val] &= 0x0f; 891792d376bSWei Song } else { 892792d376bSWei Song data->temp_src[val] &= 0xf0; 893792d376bSWei Song } 894792d376bSWei Song data->temp_src[val] |= tmp; 895792d376bSWei Song w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 896792d376bSWei Song mutex_unlock(&data->update_lock); 897792d376bSWei Song 898792d376bSWei Song return count; 899792d376bSWei Song } 900792d376bSWei Song 901792d376bSWei Song #define TEMP_PWM_ENABLE 0 902792d376bSWei Song #define TEMP_PWM_FAN_MAP 1 903792d376bSWei Song static ssize_t 904792d376bSWei Song show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 905792d376bSWei Song char *buf) 906792d376bSWei Song { 907792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 908792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 909792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 910792d376bSWei Song to_sensor_dev_attr_2(attr); 911792d376bSWei Song int nr = sensor_attr->nr; 912792d376bSWei Song int index = sensor_attr->index; 913792d376bSWei Song u8 tmp = 0xff; 914792d376bSWei Song 915792d376bSWei Song switch (nr) { 916792d376bSWei Song case TEMP_PWM_ENABLE: 917792d376bSWei Song tmp = (data->pwm_fcms[1] >> index) & 1; 918792d376bSWei Song if (tmp) 919792d376bSWei Song tmp = 4; 920792d376bSWei Song else 921792d376bSWei Song tmp = 3; 922792d376bSWei Song break; 923792d376bSWei Song case TEMP_PWM_FAN_MAP: 924792d376bSWei Song tmp = data->pwm_tfmr[index]; 925792d376bSWei Song break; 926792d376bSWei Song } 927792d376bSWei Song 928792d376bSWei Song return sprintf(buf, "%u\n", tmp); 929792d376bSWei Song } 930792d376bSWei Song 931792d376bSWei Song static ssize_t 932792d376bSWei Song store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 933792d376bSWei Song const char *buf, size_t count) 934792d376bSWei Song { 935792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 936792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 937792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 938792d376bSWei Song to_sensor_dev_attr_2(attr); 939792d376bSWei Song int nr = sensor_attr->nr; 940792d376bSWei Song int index = sensor_attr->index; 941792d376bSWei Song unsigned long tmp; 942792d376bSWei Song 943792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 944792d376bSWei Song return -EINVAL; 945792d376bSWei Song 946792d376bSWei Song switch (nr) { 947792d376bSWei Song case TEMP_PWM_ENABLE: 948792d376bSWei Song if ((tmp != 3) && (tmp != 4)) 949792d376bSWei Song return -EINVAL; 950792d376bSWei Song tmp -= 3; 951792d376bSWei Song mutex_lock(&data->update_lock); 952792d376bSWei Song data->pwm_fcms[1] &= ~(1 << index); 953792d376bSWei Song data->pwm_fcms[1] |= tmp << index; 954792d376bSWei Song w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 955792d376bSWei Song mutex_unlock(&data->update_lock); 956792d376bSWei Song break; 957792d376bSWei Song case TEMP_PWM_FAN_MAP: 958792d376bSWei Song mutex_lock(&data->update_lock); 959792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 0xff); 960792d376bSWei Song w83795_write(client, W83795_REG_TFMR(index), tmp); 961792d376bSWei Song data->pwm_tfmr[index] = tmp; 962792d376bSWei Song mutex_unlock(&data->update_lock); 963792d376bSWei Song break; 964792d376bSWei Song } 965792d376bSWei Song return count; 966792d376bSWei Song } 967792d376bSWei Song 968792d376bSWei Song #define FANIN_TARGET 0 969792d376bSWei Song #define FANIN_TOL 1 970792d376bSWei Song static ssize_t 971792d376bSWei Song show_fanin(struct device *dev, struct device_attribute *attr, char *buf) 972792d376bSWei Song { 973792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 974792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 975792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 976792d376bSWei Song to_sensor_dev_attr_2(attr); 977792d376bSWei Song int nr = sensor_attr->nr; 978792d376bSWei Song int index = sensor_attr->index; 979792d376bSWei Song u16 tmp = 0; 980792d376bSWei Song 981792d376bSWei Song switch (nr) { 982792d376bSWei Song case FANIN_TARGET: 983792d376bSWei Song tmp = fan_from_reg(data->target_speed[index]); 984792d376bSWei Song break; 985792d376bSWei Song case FANIN_TOL: 986792d376bSWei Song tmp = data->tol_speed; 987792d376bSWei Song break; 988792d376bSWei Song } 989792d376bSWei Song 990792d376bSWei Song return sprintf(buf, "%u\n", tmp); 991792d376bSWei Song } 992792d376bSWei Song 993792d376bSWei Song static ssize_t 994792d376bSWei Song store_fanin(struct device *dev, struct device_attribute *attr, 995792d376bSWei Song const char *buf, size_t count) 996792d376bSWei Song { 997792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 998792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 999792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1000792d376bSWei Song to_sensor_dev_attr_2(attr); 1001792d376bSWei Song int nr = sensor_attr->nr; 1002792d376bSWei Song int index = sensor_attr->index; 1003792d376bSWei Song unsigned long val; 1004792d376bSWei Song 1005792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1006792d376bSWei Song return -EINVAL; 1007792d376bSWei Song 1008792d376bSWei Song mutex_lock(&data->update_lock); 1009792d376bSWei Song switch (nr) { 1010792d376bSWei Song case FANIN_TARGET: 1011792d376bSWei Song val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); 1012792d376bSWei Song w83795_write(client, W83795_REG_FTSH(index), (val >> 4) & 0xff); 1013792d376bSWei Song w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 1014792d376bSWei Song data->target_speed[index] = val; 1015792d376bSWei Song break; 1016792d376bSWei Song case FANIN_TOL: 1017792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3f); 1018792d376bSWei Song w83795_write(client, W83795_REG_TFTS, val); 1019792d376bSWei Song data->tol_speed = val; 1020792d376bSWei Song break; 1021792d376bSWei Song } 1022792d376bSWei Song mutex_unlock(&data->update_lock); 1023792d376bSWei Song 1024792d376bSWei Song return count; 1025792d376bSWei Song } 1026792d376bSWei Song 1027792d376bSWei Song 1028792d376bSWei Song static ssize_t 1029792d376bSWei Song show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1030792d376bSWei Song { 1031792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1032792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1033792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1034792d376bSWei Song to_sensor_dev_attr_2(attr); 1035792d376bSWei Song int nr = sensor_attr->nr; 1036792d376bSWei Song int index = sensor_attr->index; 1037792d376bSWei Song long tmp = temp_from_reg(data->pwm_temp[index][nr]); 1038792d376bSWei Song 1039792d376bSWei Song return sprintf(buf, "%ld\n", tmp); 1040792d376bSWei Song } 1041792d376bSWei Song 1042792d376bSWei Song static ssize_t 1043792d376bSWei Song store_temp_pwm(struct device *dev, struct device_attribute *attr, 1044792d376bSWei Song const char *buf, size_t count) 1045792d376bSWei Song { 1046792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1047792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1048792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1049792d376bSWei Song to_sensor_dev_attr_2(attr); 1050792d376bSWei Song int nr = sensor_attr->nr; 1051792d376bSWei Song int index = sensor_attr->index; 1052792d376bSWei Song unsigned long val; 1053792d376bSWei Song u8 tmp; 1054792d376bSWei Song 1055792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1056792d376bSWei Song return -EINVAL; 1057792d376bSWei Song val /= 1000; 1058792d376bSWei Song 1059792d376bSWei Song mutex_lock(&data->update_lock); 1060792d376bSWei Song switch (nr) { 1061792d376bSWei Song case TEMP_PWM_TTTI: 1062792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1063792d376bSWei Song w83795_write(client, W83795_REG_TTTI(index), val); 1064792d376bSWei Song break; 1065792d376bSWei Song case TEMP_PWM_CTFS: 1066792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1067792d376bSWei Song w83795_write(client, W83795_REG_CTFS(index), val); 1068792d376bSWei Song break; 1069792d376bSWei Song case TEMP_PWM_HCT: 1070792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1071792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1072792d376bSWei Song tmp &= 0x0f; 1073792d376bSWei Song tmp |= (val << 4) & 0xf0; 1074792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1075792d376bSWei Song break; 1076792d376bSWei Song case TEMP_PWM_HOT: 1077792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1078792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1079792d376bSWei Song tmp &= 0xf0; 1080792d376bSWei Song tmp |= val & 0x0f; 1081792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1082792d376bSWei Song break; 1083792d376bSWei Song } 1084792d376bSWei Song data->pwm_temp[index][nr] = val; 1085792d376bSWei Song mutex_unlock(&data->update_lock); 1086792d376bSWei Song 1087792d376bSWei Song return count; 1088792d376bSWei Song } 1089792d376bSWei Song 1090792d376bSWei Song static ssize_t 1091792d376bSWei Song show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1092792d376bSWei Song { 1093792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1094792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1095792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1096792d376bSWei Song to_sensor_dev_attr_2(attr); 1097792d376bSWei Song int nr = sensor_attr->nr; 1098792d376bSWei Song int index = sensor_attr->index; 1099792d376bSWei Song 1100792d376bSWei Song return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 1101792d376bSWei Song } 1102792d376bSWei Song 1103792d376bSWei Song static ssize_t 1104792d376bSWei Song store_sf4_pwm(struct device *dev, struct device_attribute *attr, 1105792d376bSWei Song const char *buf, size_t count) 1106792d376bSWei Song { 1107792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1108792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1109792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1110792d376bSWei Song to_sensor_dev_attr_2(attr); 1111792d376bSWei Song int nr = sensor_attr->nr; 1112792d376bSWei Song int index = sensor_attr->index; 1113792d376bSWei Song unsigned long val; 1114792d376bSWei Song 1115792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1116792d376bSWei Song return -EINVAL; 1117792d376bSWei Song 1118792d376bSWei Song mutex_lock(&data->update_lock); 1119792d376bSWei Song w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 1120792d376bSWei Song data->sf4_reg[index][SF4_PWM][nr] = val; 1121792d376bSWei Song mutex_unlock(&data->update_lock); 1122792d376bSWei Song 1123792d376bSWei Song return count; 1124792d376bSWei Song } 1125792d376bSWei Song 1126792d376bSWei Song static ssize_t 1127792d376bSWei Song show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 1128792d376bSWei Song { 1129792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1130792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1131792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1132792d376bSWei Song to_sensor_dev_attr_2(attr); 1133792d376bSWei Song int nr = sensor_attr->nr; 1134792d376bSWei Song int index = sensor_attr->index; 1135792d376bSWei Song 1136792d376bSWei Song return sprintf(buf, "%u\n", 1137792d376bSWei Song (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 1138792d376bSWei Song } 1139792d376bSWei Song 1140792d376bSWei Song static ssize_t 1141792d376bSWei Song store_sf4_temp(struct device *dev, struct device_attribute *attr, 1142792d376bSWei Song const char *buf, size_t count) 1143792d376bSWei Song { 1144792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1145792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1146792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1147792d376bSWei Song to_sensor_dev_attr_2(attr); 1148792d376bSWei Song int nr = sensor_attr->nr; 1149792d376bSWei Song int index = sensor_attr->index; 1150792d376bSWei Song unsigned long val; 1151792d376bSWei Song 1152792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1153792d376bSWei Song return -EINVAL; 1154792d376bSWei Song val /= 1000; 1155792d376bSWei Song 1156792d376bSWei Song mutex_lock(&data->update_lock); 1157792d376bSWei Song w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 1158792d376bSWei Song data->sf4_reg[index][SF4_TEMP][nr] = val; 1159792d376bSWei Song mutex_unlock(&data->update_lock); 1160792d376bSWei Song 1161792d376bSWei Song return count; 1162792d376bSWei Song } 1163792d376bSWei Song 1164792d376bSWei Song 1165792d376bSWei Song static ssize_t 1166792d376bSWei Song show_temp(struct device *dev, struct device_attribute *attr, char *buf) 1167792d376bSWei Song { 1168792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1169792d376bSWei Song to_sensor_dev_attr_2(attr); 1170792d376bSWei Song int nr = sensor_attr->nr; 1171792d376bSWei Song int index = sensor_attr->index; 1172792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1173792d376bSWei Song long temp = temp_from_reg(data->temp[index][nr] & 0x7f); 1174792d376bSWei Song 1175792d376bSWei Song if (TEMP_READ == nr) 1176792d376bSWei Song temp += ((data->temp_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) 1177792d376bSWei Song * 250; 1178792d376bSWei Song if (data->temp[index][nr] & 0x80) 1179792d376bSWei Song temp = -temp; 1180792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1181792d376bSWei Song } 1182792d376bSWei Song 1183792d376bSWei Song static ssize_t 1184792d376bSWei Song store_temp(struct device *dev, struct device_attribute *attr, 1185792d376bSWei Song const char *buf, size_t count) 1186792d376bSWei Song { 1187792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1188792d376bSWei Song to_sensor_dev_attr_2(attr); 1189792d376bSWei Song int nr = sensor_attr->nr; 1190792d376bSWei Song int index = sensor_attr->index; 1191792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1192792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1193792d376bSWei Song long tmp; 1194792d376bSWei Song 1195792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1196792d376bSWei Song return -EINVAL; 1197792d376bSWei Song 1198792d376bSWei Song mutex_lock(&data->update_lock); 1199792d376bSWei Song data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 1200792d376bSWei Song w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 1201792d376bSWei Song mutex_unlock(&data->update_lock); 1202792d376bSWei Song return count; 1203792d376bSWei Song } 1204792d376bSWei Song 1205792d376bSWei Song 1206792d376bSWei Song static ssize_t 1207792d376bSWei Song show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) 1208792d376bSWei Song { 1209792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1210792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1211792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1212792d376bSWei Song to_sensor_dev_attr_2(attr); 1213792d376bSWei Song int index = sensor_attr->index; 1214792d376bSWei Song u8 tmp; 1215792d376bSWei Song 1216792d376bSWei Song if (data->enable_dts == 0) 1217792d376bSWei Song return sprintf(buf, "%d\n", 0); 1218792d376bSWei Song 1219792d376bSWei Song if ((data->has_dts >> index) & 0x01) { 1220792d376bSWei Song if (data->enable_dts & 2) 1221792d376bSWei Song tmp = 5; 1222792d376bSWei Song else 1223792d376bSWei Song tmp = 6; 1224792d376bSWei Song } else { 1225792d376bSWei Song tmp = 0; 1226792d376bSWei Song } 1227792d376bSWei Song 1228792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1229792d376bSWei Song } 1230792d376bSWei Song 1231792d376bSWei Song static ssize_t 1232792d376bSWei Song show_dts(struct device *dev, struct device_attribute *attr, char *buf) 1233792d376bSWei Song { 1234792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1235792d376bSWei Song to_sensor_dev_attr_2(attr); 1236792d376bSWei Song int index = sensor_attr->index; 1237792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1238792d376bSWei Song long temp = temp_from_reg(data->dts[index] & 0x7f); 1239792d376bSWei Song 1240792d376bSWei Song temp += ((data->dts_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250; 1241792d376bSWei Song if (data->dts[index] & 0x80) 1242792d376bSWei Song temp = -temp; 1243792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1244792d376bSWei Song } 1245792d376bSWei Song 1246792d376bSWei Song static ssize_t 1247792d376bSWei Song show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 1248792d376bSWei Song { 1249792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1250792d376bSWei Song to_sensor_dev_attr_2(attr); 1251792d376bSWei Song int nr = sensor_attr->nr; 1252792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1253792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1254792d376bSWei Song long temp = temp_from_reg(data->dts_ext[nr] & 0x7f); 1255792d376bSWei Song 1256792d376bSWei Song if (data->dts_ext[nr] & 0x80) 1257792d376bSWei Song temp = -temp; 1258792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1259792d376bSWei Song } 1260792d376bSWei Song 1261792d376bSWei Song static ssize_t 1262792d376bSWei Song store_dts_ext(struct device *dev, struct device_attribute *attr, 1263792d376bSWei Song const char *buf, size_t count) 1264792d376bSWei Song { 1265792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1266792d376bSWei Song to_sensor_dev_attr_2(attr); 1267792d376bSWei Song int nr = sensor_attr->nr; 1268792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1269792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1270792d376bSWei Song long tmp; 1271792d376bSWei Song 1272792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1273792d376bSWei Song return -EINVAL; 1274792d376bSWei Song 1275792d376bSWei Song mutex_lock(&data->update_lock); 1276792d376bSWei Song data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 1277792d376bSWei Song w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 1278792d376bSWei Song mutex_unlock(&data->update_lock); 1279792d376bSWei Song return count; 1280792d376bSWei Song } 1281792d376bSWei Song 1282792d376bSWei Song 1283792d376bSWei Song /* 1284792d376bSWei Song Type 3: Thermal diode 1285792d376bSWei Song Type 4: Thermistor 1286792d376bSWei Song 1287792d376bSWei Song Temp5-6, default TR 1288792d376bSWei Song Temp1-4, default TD 1289792d376bSWei Song */ 1290792d376bSWei Song 1291792d376bSWei Song static ssize_t 1292792d376bSWei Song show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 1293792d376bSWei Song { 1294792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1295792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1296792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1297792d376bSWei Song to_sensor_dev_attr_2(attr); 1298792d376bSWei Song int index = sensor_attr->index; 1299792d376bSWei Song u8 tmp; 1300792d376bSWei Song 1301792d376bSWei Song if (data->has_temp >> index & 0x01) { 1302792d376bSWei Song if (data->temp_mode >> index & 0x01) 1303792d376bSWei Song tmp = 3; 1304792d376bSWei Song else 1305792d376bSWei Song tmp = 4; 1306792d376bSWei Song } else { 1307792d376bSWei Song tmp = 0; 1308792d376bSWei Song } 1309792d376bSWei Song 1310792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1311792d376bSWei Song } 1312792d376bSWei Song 1313792d376bSWei Song static ssize_t 1314792d376bSWei Song store_temp_mode(struct device *dev, struct device_attribute *attr, 1315792d376bSWei Song const char *buf, size_t count) 1316792d376bSWei Song { 1317792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1318792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1319792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1320792d376bSWei Song to_sensor_dev_attr_2(attr); 1321792d376bSWei Song int index = sensor_attr->index; 1322792d376bSWei Song unsigned long val; 1323792d376bSWei Song u8 tmp; 1324792d376bSWei Song u32 mask; 1325792d376bSWei Song 1326792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1327792d376bSWei Song return -EINVAL; 1328792d376bSWei Song if ((val != 4) && (val != 3)) 1329792d376bSWei Song return -EINVAL; 1330792d376bSWei Song if ((index > 3) && (val == 3)) 1331792d376bSWei Song return -EINVAL; 1332792d376bSWei Song 1333792d376bSWei Song mutex_lock(&data->update_lock); 1334792d376bSWei Song if (val == 3) { 1335792d376bSWei Song val = TEMP_CTRL_TD; 1336792d376bSWei Song data->has_temp |= 1 << index; 1337792d376bSWei Song data->temp_mode |= 1 << index; 1338792d376bSWei Song } else if (val == 4) { 1339792d376bSWei Song val = TEMP_CTRL_TR; 1340792d376bSWei Song data->has_temp |= 1 << index; 1341792d376bSWei Song tmp = 1 << index; 1342792d376bSWei Song data->temp_mode &= ~tmp; 1343792d376bSWei Song } 1344792d376bSWei Song 1345792d376bSWei Song if (index > 3) 1346792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 1347792d376bSWei Song else 1348792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 1349792d376bSWei Song 1350792d376bSWei Song mask = 0x03 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_SHIFT]; 1351792d376bSWei Song tmp &= ~mask; 1352792d376bSWei Song tmp |= W83795_REG_TEMP_CTRL[index][val]; 1353792d376bSWei Song 1354792d376bSWei Song mask = 1 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_HASIN_SHIFT]; 1355792d376bSWei Song data->has_in &= ~mask; 1356792d376bSWei Song 1357792d376bSWei Song if (index > 3) 1358792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL1, tmp); 1359792d376bSWei Song else 1360792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 1361792d376bSWei Song 1362792d376bSWei Song mutex_unlock(&data->update_lock); 1363792d376bSWei Song return count; 1364792d376bSWei Song } 1365792d376bSWei Song 1366792d376bSWei Song 1367792d376bSWei Song /* show/store VIN */ 1368792d376bSWei Song static ssize_t 1369792d376bSWei Song show_in(struct device *dev, struct device_attribute *attr, char *buf) 1370792d376bSWei Song { 1371792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1372792d376bSWei Song to_sensor_dev_attr_2(attr); 1373792d376bSWei Song int nr = sensor_attr->nr; 1374792d376bSWei Song int index = sensor_attr->index; 1375792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1376792d376bSWei Song u16 val = data->in[index][nr]; 1377792d376bSWei Song u8 lsb_idx; 1378792d376bSWei Song 1379792d376bSWei Song switch (nr) { 1380792d376bSWei Song case IN_READ: 1381792d376bSWei Song /* calculate this value again by sensors as sensors3.conf */ 1382792d376bSWei Song if ((index >= 17) && 13836f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1384792d376bSWei Song val *= 8; 1385792d376bSWei Song break; 1386792d376bSWei Song case IN_MAX: 1387792d376bSWei Song case IN_LOW: 1388792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1389792d376bSWei Song val <<= 2; 1390792d376bSWei Song val |= (data->in_lsb[lsb_idx][nr] >> 1391792d376bSWei Song IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; 1392792d376bSWei Song if ((index >= 17) && 13936f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1394792d376bSWei Song val *= 8; 1395792d376bSWei Song break; 1396792d376bSWei Song } 1397792d376bSWei Song val = in_from_reg(index, val); 1398792d376bSWei Song 1399792d376bSWei Song return sprintf(buf, "%d\n", val); 1400792d376bSWei Song } 1401792d376bSWei Song 1402792d376bSWei Song static ssize_t 1403792d376bSWei Song store_in(struct device *dev, struct device_attribute *attr, 1404792d376bSWei Song const char *buf, size_t count) 1405792d376bSWei Song { 1406792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1407792d376bSWei Song to_sensor_dev_attr_2(attr); 1408792d376bSWei Song int nr = sensor_attr->nr; 1409792d376bSWei Song int index = sensor_attr->index; 1410792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1411792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1412792d376bSWei Song unsigned long val; 1413792d376bSWei Song u8 tmp; 1414792d376bSWei Song u8 lsb_idx; 1415792d376bSWei Song 1416792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1417792d376bSWei Song return -EINVAL; 1418792d376bSWei Song val = in_to_reg(index, val); 1419792d376bSWei Song 1420792d376bSWei Song if ((index >= 17) && 14216f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1422792d376bSWei Song val /= 8; 1423792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3FF); 1424792d376bSWei Song mutex_lock(&data->update_lock); 1425792d376bSWei Song 1426792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1427792d376bSWei Song tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 1428792d376bSWei Song tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 1429792d376bSWei Song tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 1430792d376bSWei Song w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 1431792d376bSWei Song data->in_lsb[lsb_idx][nr] = tmp; 1432792d376bSWei Song 1433792d376bSWei Song tmp = (val >> 2) & 0xff; 1434792d376bSWei Song w83795_write(client, W83795_REG_IN[index][nr], tmp); 1435792d376bSWei Song data->in[index][nr] = tmp; 1436792d376bSWei Song 1437792d376bSWei Song mutex_unlock(&data->update_lock); 1438792d376bSWei Song return count; 1439792d376bSWei Song } 1440792d376bSWei Song 1441792d376bSWei Song 1442792d376bSWei Song static ssize_t 1443792d376bSWei Song show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 1444792d376bSWei Song { 1445792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1446792d376bSWei Song to_sensor_dev_attr_2(attr); 1447792d376bSWei Song int nr = sensor_attr->nr; 1448792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1449792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1450792d376bSWei Song u16 val = data->setup_pwm[nr]; 1451792d376bSWei Song 1452792d376bSWei Song switch (nr) { 1453792d376bSWei Song case SETUP_PWM_UPTIME: 1454792d376bSWei Song case SETUP_PWM_DOWNTIME: 1455792d376bSWei Song val = time_from_reg(val); 1456792d376bSWei Song break; 1457792d376bSWei Song } 1458792d376bSWei Song 1459792d376bSWei Song return sprintf(buf, "%d\n", val); 1460792d376bSWei Song } 1461792d376bSWei Song 1462792d376bSWei Song static ssize_t 1463792d376bSWei Song store_sf_setup(struct device *dev, struct device_attribute *attr, 1464792d376bSWei Song const char *buf, size_t count) 1465792d376bSWei Song { 1466792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1467792d376bSWei Song to_sensor_dev_attr_2(attr); 1468792d376bSWei Song int nr = sensor_attr->nr; 1469792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1470792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1471792d376bSWei Song unsigned long val; 1472792d376bSWei Song 1473792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1474792d376bSWei Song return -EINVAL; 1475792d376bSWei Song 1476792d376bSWei Song switch (nr) { 1477792d376bSWei Song case SETUP_PWM_DEFAULT: 1478792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 1479792d376bSWei Song break; 1480792d376bSWei Song case SETUP_PWM_UPTIME: 1481792d376bSWei Song case SETUP_PWM_DOWNTIME: 1482792d376bSWei Song val = time_to_reg(val); 1483792d376bSWei Song if (val == 0) 1484792d376bSWei Song return -EINVAL; 1485792d376bSWei Song break; 1486792d376bSWei Song } 1487792d376bSWei Song 1488792d376bSWei Song mutex_lock(&data->update_lock); 1489792d376bSWei Song data->setup_pwm[nr] = val; 1490792d376bSWei Song w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 1491792d376bSWei Song mutex_unlock(&data->update_lock); 1492792d376bSWei Song return count; 1493792d376bSWei Song } 1494792d376bSWei Song 1495792d376bSWei Song 1496792d376bSWei Song #define NOT_USED -1 1497792d376bSWei Song 14980e256018SJean Delvare /* Don't change the attribute order, _max and _min are accessed by index 14990e256018SJean Delvare * somewhere else in the code */ 150087df0dadSJean Delvare #define SENSOR_ATTR_IN(index) { \ 1501792d376bSWei Song SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 1502792d376bSWei Song IN_READ, index), \ 1503792d376bSWei Song SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 1504792d376bSWei Song store_in, IN_MAX, index), \ 1505792d376bSWei Song SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 1506792d376bSWei Song store_in, IN_LOW, index), \ 1507792d376bSWei Song SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 1508792d376bSWei Song NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 1509792d376bSWei Song SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 1510792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 151187df0dadSJean Delvare index + ((index > 14) ? 1 : 0)) } 1512792d376bSWei Song 151387df0dadSJean Delvare #define SENSOR_ATTR_FAN(index) { \ 1514792d376bSWei Song SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 1515792d376bSWei Song NULL, FAN_INPUT, index - 1), \ 1516792d376bSWei Song SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 1517792d376bSWei Song show_fan, store_fan_min, FAN_MIN, index - 1), \ 1518792d376bSWei Song SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 1519792d376bSWei Song NULL, ALARM_STATUS, index + 31), \ 1520792d376bSWei Song SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 152187df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 1522792d376bSWei Song 1523b5f6a90aSJean Delvare #define SENSOR_ATTR_PWM(index) { \ 1524792d376bSWei Song SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 1525792d376bSWei Song store_pwm, PWM_OUTPUT, index - 1), \ 1526792d376bSWei Song SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 1527792d376bSWei Song show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 1528792d376bSWei Song SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 1529792d376bSWei Song show_pwm, store_pwm, PWM_START, index - 1), \ 1530792d376bSWei Song SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 1531792d376bSWei Song show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 153201879a85SJean Delvare SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ 153301879a85SJean Delvare show_pwm, store_pwm, PWM_FREQ, index - 1), \ 1534792d376bSWei Song SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 1535b2cc528eSJean Delvare show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 1536b2cc528eSJean Delvare SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 1537b2cc528eSJean Delvare show_fanin, store_fanin, FANIN_TARGET, index - 1) } 1538792d376bSWei Song 153987df0dadSJean Delvare #define SENSOR_ATTR_DTS(index) { \ 1540792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 1541792d376bSWei Song show_dts_mode, NULL, NOT_USED, index - 7), \ 1542792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 1543792d376bSWei Song NULL, NOT_USED, index - 7), \ 1544a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ 1545792d376bSWei Song store_dts_ext, DTS_CRIT, NOT_USED), \ 1546a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1547792d376bSWei Song show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 1548a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 1549792d376bSWei Song store_dts_ext, DTS_WARN, NOT_USED), \ 1550a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1551792d376bSWei Song show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 1552792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1553792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 1554792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 155587df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 1556792d376bSWei Song 155787df0dadSJean Delvare #define SENSOR_ATTR_TEMP(index) { \ 1558792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \ 1559792d376bSWei Song show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 1560792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 1561792d376bSWei Song NULL, TEMP_READ, index - 1), \ 1562a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ 1563792d376bSWei Song store_temp, TEMP_CRIT, index - 1), \ 1564a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1565792d376bSWei Song show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 1566a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 1567792d376bSWei Song store_temp, TEMP_WARN, index - 1), \ 1568a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1569792d376bSWei Song show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 1570792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1571792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, \ 1572792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1573792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 1574792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 1575792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1576792d376bSWei Song SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \ 1577792d376bSWei Song show_temp_src, store_temp_src, NOT_USED, index - 1), \ 1578792d376bSWei Song SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 1579792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1580792d376bSWei Song TEMP_PWM_ENABLE, index - 1), \ 1581792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 1582792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1583792d376bSWei Song TEMP_PWM_FAN_MAP, index - 1), \ 1584792d376bSWei Song SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 1585792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 1586a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ 1587792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 1588a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ 1589792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 1590792d376bSWei Song SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 1591792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 1592792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 1593792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 1594792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 1595792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 1596792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 1597792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 1598792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 1599792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 1600792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 1601792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 1602792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 1603792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 1604792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 1605792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 1606792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 1607792d376bSWei Song show_sf4_temp, store_sf4_temp, 0, index - 1), \ 1608792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 1609792d376bSWei Song show_sf4_temp, store_sf4_temp, 1, index - 1), \ 1610792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 1611792d376bSWei Song show_sf4_temp, store_sf4_temp, 2, index - 1), \ 1612792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 1613792d376bSWei Song show_sf4_temp, store_sf4_temp, 3, index - 1), \ 1614792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 1615792d376bSWei Song show_sf4_temp, store_sf4_temp, 4, index - 1), \ 1616792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 1617792d376bSWei Song show_sf4_temp, store_sf4_temp, 5, index - 1), \ 1618792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 161987df0dadSJean Delvare show_sf4_temp, store_sf4_temp, 6, index - 1) } 1620792d376bSWei Song 1621792d376bSWei Song 162287df0dadSJean Delvare static struct sensor_device_attribute_2 w83795_in[][5] = { 1623792d376bSWei Song SENSOR_ATTR_IN(0), 1624792d376bSWei Song SENSOR_ATTR_IN(1), 1625792d376bSWei Song SENSOR_ATTR_IN(2), 1626792d376bSWei Song SENSOR_ATTR_IN(3), 1627792d376bSWei Song SENSOR_ATTR_IN(4), 1628792d376bSWei Song SENSOR_ATTR_IN(5), 1629792d376bSWei Song SENSOR_ATTR_IN(6), 1630792d376bSWei Song SENSOR_ATTR_IN(7), 1631792d376bSWei Song SENSOR_ATTR_IN(8), 1632792d376bSWei Song SENSOR_ATTR_IN(9), 1633792d376bSWei Song SENSOR_ATTR_IN(10), 1634792d376bSWei Song SENSOR_ATTR_IN(11), 1635792d376bSWei Song SENSOR_ATTR_IN(12), 1636792d376bSWei Song SENSOR_ATTR_IN(13), 1637792d376bSWei Song SENSOR_ATTR_IN(14), 1638792d376bSWei Song SENSOR_ATTR_IN(15), 1639792d376bSWei Song SENSOR_ATTR_IN(16), 1640792d376bSWei Song SENSOR_ATTR_IN(17), 1641792d376bSWei Song SENSOR_ATTR_IN(18), 1642792d376bSWei Song SENSOR_ATTR_IN(19), 1643792d376bSWei Song SENSOR_ATTR_IN(20), 1644792d376bSWei Song }; 1645792d376bSWei Song 164686ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_fan[][4] = { 1647792d376bSWei Song SENSOR_ATTR_FAN(1), 1648792d376bSWei Song SENSOR_ATTR_FAN(2), 1649792d376bSWei Song SENSOR_ATTR_FAN(3), 1650792d376bSWei Song SENSOR_ATTR_FAN(4), 1651792d376bSWei Song SENSOR_ATTR_FAN(5), 1652792d376bSWei Song SENSOR_ATTR_FAN(6), 1653792d376bSWei Song SENSOR_ATTR_FAN(7), 1654792d376bSWei Song SENSOR_ATTR_FAN(8), 1655792d376bSWei Song SENSOR_ATTR_FAN(9), 1656792d376bSWei Song SENSOR_ATTR_FAN(10), 1657792d376bSWei Song SENSOR_ATTR_FAN(11), 1658792d376bSWei Song SENSOR_ATTR_FAN(12), 1659792d376bSWei Song SENSOR_ATTR_FAN(13), 1660792d376bSWei Song SENSOR_ATTR_FAN(14), 1661792d376bSWei Song }; 1662792d376bSWei Song 166386ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_temp[][29] = { 1664792d376bSWei Song SENSOR_ATTR_TEMP(1), 1665792d376bSWei Song SENSOR_ATTR_TEMP(2), 1666792d376bSWei Song SENSOR_ATTR_TEMP(3), 1667792d376bSWei Song SENSOR_ATTR_TEMP(4), 1668792d376bSWei Song SENSOR_ATTR_TEMP(5), 1669792d376bSWei Song SENSOR_ATTR_TEMP(6), 1670792d376bSWei Song }; 1671792d376bSWei Song 167286ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_dts[][8] = { 1673792d376bSWei Song SENSOR_ATTR_DTS(7), 1674792d376bSWei Song SENSOR_ATTR_DTS(8), 1675792d376bSWei Song SENSOR_ATTR_DTS(9), 1676792d376bSWei Song SENSOR_ATTR_DTS(10), 1677792d376bSWei Song SENSOR_ATTR_DTS(11), 1678792d376bSWei Song SENSOR_ATTR_DTS(12), 1679792d376bSWei Song SENSOR_ATTR_DTS(13), 1680792d376bSWei Song SENSOR_ATTR_DTS(14), 1681792d376bSWei Song }; 1682792d376bSWei Song 168386ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_pwm[][7] = { 1684b5f6a90aSJean Delvare SENSOR_ATTR_PWM(1), 1685b5f6a90aSJean Delvare SENSOR_ATTR_PWM(2), 1686792d376bSWei Song SENSOR_ATTR_PWM(3), 1687792d376bSWei Song SENSOR_ATTR_PWM(4), 1688792d376bSWei Song SENSOR_ATTR_PWM(5), 1689792d376bSWei Song SENSOR_ATTR_PWM(6), 1690792d376bSWei Song SENSOR_ATTR_PWM(7), 1691792d376bSWei Song SENSOR_ATTR_PWM(8), 1692792d376bSWei Song }; 1693792d376bSWei Song 169486ef4d2fSJean Delvare static const struct sensor_device_attribute_2 sda_single_files[] = { 1695792d376bSWei Song SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, 1696792d376bSWei Song store_chassis_clear, ALARM_STATUS, 46), 1697792d376bSWei Song SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, 1698792d376bSWei Song store_beep_enable, NOT_USED, NOT_USED), 1699792d376bSWei Song SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 1700792d376bSWei Song store_fanin, FANIN_TOL, NOT_USED), 1701792d376bSWei Song SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 1702792d376bSWei Song store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 1703792d376bSWei Song SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 1704792d376bSWei Song store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 1705792d376bSWei Song SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 1706792d376bSWei Song store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 1707792d376bSWei Song }; 1708792d376bSWei Song 1709792d376bSWei Song /* 1710792d376bSWei Song * Driver interface 1711792d376bSWei Song */ 1712792d376bSWei Song 1713792d376bSWei Song static void w83795_init_client(struct i2c_client *client) 1714792d376bSWei Song { 171501879a85SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 171601879a85SJean Delvare static const u16 clkin[4] = { /* in kHz */ 171701879a85SJean Delvare 14318, 24000, 33333, 48000 171801879a85SJean Delvare }; 171980646b95SJean Delvare u8 config; 172080646b95SJean Delvare 1721792d376bSWei Song if (reset) 1722792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 0x80); 1723792d376bSWei Song 172480646b95SJean Delvare /* Start monitoring if needed */ 172580646b95SJean Delvare config = w83795_read(client, W83795_REG_CONFIG); 172680646b95SJean Delvare if (!(config & W83795_REG_CONFIG_START)) { 172780646b95SJean Delvare dev_info(&client->dev, "Enabling monitoring operations\n"); 1728792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 172980646b95SJean Delvare config | W83795_REG_CONFIG_START); 173080646b95SJean Delvare } 173101879a85SJean Delvare 173201879a85SJean Delvare data->clkin = clkin[(config >> 3) & 0x3]; 173301879a85SJean Delvare dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); 1734792d376bSWei Song } 1735792d376bSWei Song 17362be381deSJean Delvare static int w83795_get_device_id(struct i2c_client *client) 17372be381deSJean Delvare { 17382be381deSJean Delvare int device_id; 17392be381deSJean Delvare 17402be381deSJean Delvare device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 17412be381deSJean Delvare 17422be381deSJean Delvare /* Special case for rev. A chips; can't be checked first because later 17432be381deSJean Delvare revisions emulate this for compatibility */ 17442be381deSJean Delvare if (device_id < 0 || (device_id & 0xf0) != 0x50) { 17452be381deSJean Delvare int alt_id; 17462be381deSJean Delvare 17472be381deSJean Delvare alt_id = i2c_smbus_read_byte_data(client, 17482be381deSJean Delvare W83795_REG_DEVICEID_A); 17492be381deSJean Delvare if (alt_id == 0x50) 17502be381deSJean Delvare device_id = alt_id; 17512be381deSJean Delvare } 17522be381deSJean Delvare 17532be381deSJean Delvare return device_id; 17542be381deSJean Delvare } 17552be381deSJean Delvare 1756792d376bSWei Song /* Return 0 if detection is successful, -ENODEV otherwise */ 1757792d376bSWei Song static int w83795_detect(struct i2c_client *client, 1758792d376bSWei Song struct i2c_board_info *info) 1759792d376bSWei Song { 17602be381deSJean Delvare int bank, vendor_id, device_id, expected, i2c_addr, config; 1761792d376bSWei Song struct i2c_adapter *adapter = client->adapter; 1762792d376bSWei Song unsigned short address = client->addr; 1763093d1a47SJean Delvare const char *chip_name; 1764792d376bSWei Song 1765792d376bSWei Song if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1766792d376bSWei Song return -ENODEV; 1767792d376bSWei Song bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 17682be381deSJean Delvare if (bank < 0 || (bank & 0x7c)) { 17692be381deSJean Delvare dev_dbg(&adapter->dev, 17702be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17712be381deSJean Delvare address, "bank"); 17722be381deSJean Delvare return -ENODEV; 17732be381deSJean Delvare } 1774792d376bSWei Song 1775792d376bSWei Song /* Check Nuvoton vendor ID */ 17762be381deSJean Delvare vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 17772be381deSJean Delvare expected = bank & 0x80 ? 0x5c : 0xa3; 17782be381deSJean Delvare if (vendor_id != expected) { 17792be381deSJean Delvare dev_dbg(&adapter->dev, 17802be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17812be381deSJean Delvare address, "vendor id"); 17822be381deSJean Delvare return -ENODEV; 17832be381deSJean Delvare } 17842be381deSJean Delvare 17852be381deSJean Delvare /* Check device ID */ 17862be381deSJean Delvare device_id = w83795_get_device_id(client) | 17872be381deSJean Delvare (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 17882be381deSJean Delvare if ((device_id >> 4) != 0x795) { 17892be381deSJean Delvare dev_dbg(&adapter->dev, 17902be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 17912be381deSJean Delvare address, "device id\n"); 1792792d376bSWei Song return -ENODEV; 1793792d376bSWei Song } 1794792d376bSWei Song 1795792d376bSWei Song /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 1796792d376bSWei Song should match */ 17972be381deSJean Delvare if ((bank & 0x07) == 0) { 17982be381deSJean Delvare i2c_addr = i2c_smbus_read_byte_data(client, 17992be381deSJean Delvare W83795_REG_I2C_ADDR); 18002be381deSJean Delvare if ((i2c_addr & 0x7f) != address) { 18012be381deSJean Delvare dev_dbg(&adapter->dev, 18022be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, " 18032be381deSJean Delvare "check %s\n", address, "i2c addr"); 1804792d376bSWei Song return -ENODEV; 1805792d376bSWei Song } 1806792d376bSWei Song } 1807792d376bSWei Song 1808093d1a47SJean Delvare /* Check 795 chip type: 795G or 795ADG 1809093d1a47SJean Delvare Usually we don't write to chips during detection, but here we don't 1810093d1a47SJean Delvare quite have the choice; hopefully it's OK, we are about to return 1811093d1a47SJean Delvare success anyway */ 1812093d1a47SJean Delvare if ((bank & 0x07) != 0) 1813093d1a47SJean Delvare i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 1814093d1a47SJean Delvare bank & ~0x07); 18152be381deSJean Delvare config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 18162be381deSJean Delvare if (config & W83795_REG_CONFIG_CONFIG48) 1817093d1a47SJean Delvare chip_name = "w83795adg"; 18182be381deSJean Delvare else 1819093d1a47SJean Delvare chip_name = "w83795g"; 1820792d376bSWei Song 1821093d1a47SJean Delvare strlcpy(info->type, chip_name, I2C_NAME_SIZE); 18222be381deSJean Delvare dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 18232be381deSJean Delvare 'A' + (device_id & 0xf), address); 1824792d376bSWei Song 1825792d376bSWei Song return 0; 1826792d376bSWei Song } 1827792d376bSWei Song 18286f3dcde9SJean Delvare static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 18296f3dcde9SJean Delvare const struct device_attribute *)) 1830892514a6SJean Delvare { 1831892514a6SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 183287df0dadSJean Delvare int err, i, j; 1833892514a6SJean Delvare 1834892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 183587df0dadSJean Delvare if (!(data->has_in & (1 << i))) 1836892514a6SJean Delvare continue; 183787df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 183887df0dadSJean Delvare err = fn(dev, &w83795_in[i][j].dev_attr); 1839892514a6SJean Delvare if (err) 1840892514a6SJean Delvare return err; 1841892514a6SJean Delvare } 184287df0dadSJean Delvare } 1843892514a6SJean Delvare 1844892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 184587df0dadSJean Delvare if (!(data->has_fan & (1 << i))) 1846892514a6SJean Delvare continue; 184787df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 184887df0dadSJean Delvare err = fn(dev, &w83795_fan[i][j].dev_attr); 1849892514a6SJean Delvare if (err) 1850892514a6SJean Delvare return err; 1851892514a6SJean Delvare } 185287df0dadSJean Delvare } 1853892514a6SJean Delvare 1854892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 18556f3dcde9SJean Delvare err = fn(dev, &sda_single_files[i].dev_attr); 1856892514a6SJean Delvare if (err) 1857892514a6SJean Delvare return err; 1858892514a6SJean Delvare } 1859892514a6SJean Delvare 1860b5f6a90aSJean Delvare for (i = 0; i < data->has_pwm; i++) { 1861b5f6a90aSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { 1862b5f6a90aSJean Delvare err = fn(dev, &w83795_pwm[i][j].dev_attr); 1863892514a6SJean Delvare if (err) 1864892514a6SJean Delvare return err; 1865892514a6SJean Delvare } 1866892514a6SJean Delvare } 1867892514a6SJean Delvare 1868892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 186987df0dadSJean Delvare if (!(data->has_temp & (1 << i))) 1870892514a6SJean Delvare continue; 187187df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { 187287df0dadSJean Delvare err = fn(dev, &w83795_temp[i][j].dev_attr); 1873892514a6SJean Delvare if (err) 1874892514a6SJean Delvare return err; 1875892514a6SJean Delvare } 187687df0dadSJean Delvare } 1877892514a6SJean Delvare 1878892514a6SJean Delvare if (data->enable_dts != 0) { 1879892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 188087df0dadSJean Delvare if (!(data->has_dts & (1 << i))) 1881892514a6SJean Delvare continue; 188287df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 188387df0dadSJean Delvare err = fn(dev, &w83795_dts[i][j].dev_attr); 1884892514a6SJean Delvare if (err) 1885892514a6SJean Delvare return err; 1886892514a6SJean Delvare } 1887892514a6SJean Delvare } 188887df0dadSJean Delvare } 1889892514a6SJean Delvare 1890892514a6SJean Delvare return 0; 1891892514a6SJean Delvare } 1892892514a6SJean Delvare 18936f3dcde9SJean Delvare /* We need a wrapper that fits in w83795_handle_files */ 18946f3dcde9SJean Delvare static int device_remove_file_wrapper(struct device *dev, 18956f3dcde9SJean Delvare const struct device_attribute *attr) 18962fa09878SJean Delvare { 18976f3dcde9SJean Delvare device_remove_file(dev, attr); 18986f3dcde9SJean Delvare return 0; 18992fa09878SJean Delvare } 19002fa09878SJean Delvare 19010e256018SJean Delvare static void w83795_check_dynamic_in_limits(struct i2c_client *client) 19020e256018SJean Delvare { 19030e256018SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 19040e256018SJean Delvare u8 vid_ctl; 19050e256018SJean Delvare int i, err_max, err_min; 19060e256018SJean Delvare 19070e256018SJean Delvare vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); 19080e256018SJean Delvare 19090e256018SJean Delvare /* Return immediately if VRM isn't configured */ 19100e256018SJean Delvare if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) 19110e256018SJean Delvare return; 19120e256018SJean Delvare 19130e256018SJean Delvare data->has_dyn_in = (vid_ctl >> 3) & 0x07; 19140e256018SJean Delvare for (i = 0; i < 2; i++) { 19150e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 19160e256018SJean Delvare continue; 19170e256018SJean Delvare 19180e256018SJean Delvare /* Voltage limits in dynamic mode, switch to read-only */ 19190e256018SJean Delvare err_max = sysfs_chmod_file(&client->dev.kobj, 19200e256018SJean Delvare &w83795_in[i][2].dev_attr.attr, 19210e256018SJean Delvare S_IRUGO); 19220e256018SJean Delvare err_min = sysfs_chmod_file(&client->dev.kobj, 19230e256018SJean Delvare &w83795_in[i][3].dev_attr.attr, 19240e256018SJean Delvare S_IRUGO); 19250e256018SJean Delvare if (err_max || err_min) 19260e256018SJean Delvare dev_warn(&client->dev, "Failed to set in%d limits " 19270e256018SJean Delvare "read-only (%d, %d)\n", i, err_max, err_min); 19280e256018SJean Delvare else 19290e256018SJean Delvare dev_info(&client->dev, "in%d limits set dynamically " 19300e256018SJean Delvare "from VID\n", i); 19310e256018SJean Delvare } 19320e256018SJean Delvare } 19330e256018SJean Delvare 193471caf46fSJean Delvare /* Check pins that can be used for either temperature or voltage monitoring */ 193571caf46fSJean Delvare static void w83795_apply_temp_config(struct w83795_data *data, u8 config, 193671caf46fSJean Delvare int temp_chan, int in_chan) 193771caf46fSJean Delvare { 193871caf46fSJean Delvare /* config is a 2-bit value */ 193971caf46fSJean Delvare switch (config) { 194071caf46fSJean Delvare case 0x2: /* Voltage monitoring */ 194171caf46fSJean Delvare data->has_in |= 1 << in_chan; 194271caf46fSJean Delvare break; 194371caf46fSJean Delvare case 0x1: /* Thermal diode */ 194471caf46fSJean Delvare if (temp_chan >= 4) 194571caf46fSJean Delvare break; 194671caf46fSJean Delvare data->temp_mode |= 1 << temp_chan; 194771caf46fSJean Delvare /* fall through */ 194871caf46fSJean Delvare case 0x3: /* Thermistor */ 194971caf46fSJean Delvare data->has_temp |= 1 << temp_chan; 195071caf46fSJean Delvare break; 195171caf46fSJean Delvare } 195271caf46fSJean Delvare } 195371caf46fSJean Delvare 1954792d376bSWei Song static int w83795_probe(struct i2c_client *client, 1955792d376bSWei Song const struct i2c_device_id *id) 1956792d376bSWei Song { 1957792d376bSWei Song int i; 1958792d376bSWei Song u8 tmp; 1959792d376bSWei Song struct device *dev = &client->dev; 1960792d376bSWei Song struct w83795_data *data; 196171caf46fSJean Delvare int err; 1962792d376bSWei Song 1963792d376bSWei Song data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); 1964792d376bSWei Song if (!data) { 1965792d376bSWei Song err = -ENOMEM; 1966792d376bSWei Song goto exit; 1967792d376bSWei Song } 1968792d376bSWei Song 1969792d376bSWei Song i2c_set_clientdata(client, data); 1970093d1a47SJean Delvare data->chip_type = id->driver_data; 1971792d376bSWei Song data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 1972792d376bSWei Song mutex_init(&data->update_lock); 1973792d376bSWei Song 1974792d376bSWei Song /* Initialize the chip */ 1975792d376bSWei Song w83795_init_client(client); 1976792d376bSWei Song 197771caf46fSJean Delvare /* Check which voltages and fans are present */ 197871caf46fSJean Delvare data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) 197971caf46fSJean Delvare | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); 198071caf46fSJean Delvare data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) 198171caf46fSJean Delvare | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); 1982792d376bSWei Song 198371caf46fSJean Delvare /* Check which analog temperatures and extra voltages are present */ 1984792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 1985792d376bSWei Song if (tmp & 0x20) 1986792d376bSWei Song data->enable_dts = 1; 198771caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); 198871caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 4, 15); 1989792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 199071caf46fSJean Delvare w83795_apply_temp_config(data, tmp >> 6, 3, 20); 199171caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); 199271caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); 199371caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 0, 17); 1994792d376bSWei Song 1995792d376bSWei Song /* Check DTS enable status */ 199671caf46fSJean Delvare if (data->enable_dts) { 1997792d376bSWei Song if (1 & w83795_read(client, W83795_REG_DTSC)) 1998792d376bSWei Song data->enable_dts |= 2; 1999792d376bSWei Song data->has_dts = w83795_read(client, W83795_REG_DTSE); 2000792d376bSWei Song } 2001792d376bSWei Song 2002792d376bSWei Song /* First update the voltages measured value and limits */ 2003792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 2004792d376bSWei Song if (!(data->has_in & (1 << i))) 2005792d376bSWei Song continue; 2006792d376bSWei Song data->in[i][IN_MAX] = 2007792d376bSWei Song w83795_read(client, W83795_REG_IN[i][IN_MAX]); 2008792d376bSWei Song data->in[i][IN_LOW] = 2009792d376bSWei Song w83795_read(client, W83795_REG_IN[i][IN_LOW]); 2010792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 2011792d376bSWei Song tmp |= (w83795_read(client, W83795_REG_VRLSB) 2012792d376bSWei Song >> VRLSB_SHIFT) & 0x03; 2013792d376bSWei Song data->in[i][IN_READ] = tmp; 2014792d376bSWei Song } 2015792d376bSWei Song for (i = 0; i < IN_LSB_REG_NUM; i++) { 2016792d376bSWei Song data->in_lsb[i][IN_MAX] = 2017792d376bSWei Song w83795_read(client, IN_LSB_REG(i, IN_MAX)); 2018792d376bSWei Song data->in_lsb[i][IN_LOW] = 2019792d376bSWei Song w83795_read(client, IN_LSB_REG(i, IN_LOW)); 2020792d376bSWei Song } 2021792d376bSWei Song data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 2022792d376bSWei Song 2023792d376bSWei Song /* First update fan and limits */ 2024792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 2025792d376bSWei Song if (!(data->has_fan & (1 << i))) 2026792d376bSWei Song continue; 2027792d376bSWei Song data->fan_min[i] = 2028792d376bSWei Song w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 2029792d376bSWei Song data->fan_min[i] |= 20306c82b2f3SJean Delvare (w83795_read(client, W83795_REG_FAN_MIN_LSB(i)) >> 20316c82b2f3SJean Delvare W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; 2032792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 2033792d376bSWei Song data->fan[i] |= 20346c82b2f3SJean Delvare (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; 2035792d376bSWei Song } 2036792d376bSWei Song 2037792d376bSWei Song /* temperature and limits */ 2038792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 2039792d376bSWei Song if (!(data->has_temp & (1 << i))) 2040792d376bSWei Song continue; 2041792d376bSWei Song data->temp[i][TEMP_CRIT] = 2042792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT]); 2043792d376bSWei Song data->temp[i][TEMP_CRIT_HYST] = 2044792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT_HYST]); 2045792d376bSWei Song data->temp[i][TEMP_WARN] = 2046792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN]); 2047792d376bSWei Song data->temp[i][TEMP_WARN_HYST] = 2048792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]); 2049792d376bSWei Song data->temp[i][TEMP_READ] = 2050792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 2051792d376bSWei Song data->temp_read_vrlsb[i] = 2052792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 2053792d376bSWei Song } 2054792d376bSWei Song 2055792d376bSWei Song /* dts temperature and limits */ 2056792d376bSWei Song if (data->enable_dts != 0) { 2057792d376bSWei Song data->dts_ext[DTS_CRIT] = 2058792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT)); 2059792d376bSWei Song data->dts_ext[DTS_CRIT_HYST] = 2060792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT_HYST)); 2061792d376bSWei Song data->dts_ext[DTS_WARN] = 2062792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN)); 2063792d376bSWei Song data->dts_ext[DTS_WARN_HYST] = 2064792d376bSWei Song w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN_HYST)); 2065792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 2066792d376bSWei Song if (!(data->has_dts & (1 << i))) 2067792d376bSWei Song continue; 2068792d376bSWei Song data->dts[i] = w83795_read(client, W83795_REG_DTS(i)); 2069792d376bSWei Song data->dts_read_vrlsb[i] = 2070792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 2071792d376bSWei Song } 2072792d376bSWei Song } 2073792d376bSWei Song 2074792d376bSWei Song /* First update temp source selction */ 2075792d376bSWei Song for (i = 0; i < 3; i++) 2076792d376bSWei Song data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 2077792d376bSWei Song 2078792d376bSWei Song /* pwm and smart fan */ 2079792d376bSWei Song if (data->chip_type == w83795g) 2080792d376bSWei Song data->has_pwm = 8; 2081792d376bSWei Song else 2082792d376bSWei Song data->has_pwm = 2; 2083792d376bSWei Song data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 2084792d376bSWei Song data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 2085792d376bSWei Song for (i = 0; i < W83795_REG_TEMP_NUM; i++) 2086792d376bSWei Song data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 2087792d376bSWei Song data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 2088792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 2089792d376bSWei Song for (tmp = 0; tmp < 5; tmp++) { 2090792d376bSWei Song data->pwm[i][tmp] = 2091792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, tmp)); 2092792d376bSWei Song } 2093792d376bSWei Song } 2094792d376bSWei Song for (i = 0; i < 8; i++) { 2095792d376bSWei Song data->target_speed[i] = 2096792d376bSWei Song w83795_read(client, W83795_REG_FTSH(i)) << 4; 2097792d376bSWei Song data->target_speed[i] |= 2098792d376bSWei Song w83795_read(client, W83795_REG_FTSL(i)) >> 4; 2099792d376bSWei Song } 2100792d376bSWei Song data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 2101792d376bSWei Song 2102792d376bSWei Song for (i = 0; i < W83795_REG_TEMP_NUM; i++) { 2103792d376bSWei Song data->pwm_temp[i][TEMP_PWM_TTTI] = 2104792d376bSWei Song w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 2105792d376bSWei Song data->pwm_temp[i][TEMP_PWM_CTFS] = 2106792d376bSWei Song w83795_read(client, W83795_REG_CTFS(i)); 2107792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(i)); 2108792d376bSWei Song data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; 2109792d376bSWei Song data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 2110792d376bSWei Song } 2111792d376bSWei Song for (i = 0; i < W83795_REG_TEMP_NUM; i++) { 2112792d376bSWei Song for (tmp = 0; tmp < 7; tmp++) { 2113792d376bSWei Song data->sf4_reg[i][SF4_TEMP][tmp] = 2114792d376bSWei Song w83795_read(client, 2115792d376bSWei Song W83795_REG_SF4_TEMP(i, tmp)); 2116792d376bSWei Song data->sf4_reg[i][SF4_PWM][tmp] = 2117792d376bSWei Song w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 2118792d376bSWei Song } 2119792d376bSWei Song } 2120792d376bSWei Song 2121792d376bSWei Song /* Setup PWM Register */ 2122792d376bSWei Song for (i = 0; i < 3; i++) { 2123792d376bSWei Song data->setup_pwm[i] = 2124792d376bSWei Song w83795_read(client, W83795_REG_SETUP_PWM(i)); 2125792d376bSWei Song } 2126792d376bSWei Song 2127792d376bSWei Song /* alarm and beep */ 2128792d376bSWei Song for (i = 0; i < ALARM_BEEP_REG_NUM; i++) { 2129792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 2130792d376bSWei Song data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); 2131792d376bSWei Song } 2132792d376bSWei Song data->beep_enable = 2133792d376bSWei Song (w83795_read(client, W83795_REG_BEEP(5)) >> 7) & 0x01; 2134792d376bSWei Song 21356f3dcde9SJean Delvare err = w83795_handle_files(dev, device_create_file); 2136792d376bSWei Song if (err) 2137792d376bSWei Song goto exit_remove; 2138792d376bSWei Song 21390e256018SJean Delvare if (data->chip_type == w83795g) 21400e256018SJean Delvare w83795_check_dynamic_in_limits(client); 21410e256018SJean Delvare 2142792d376bSWei Song data->hwmon_dev = hwmon_device_register(dev); 2143792d376bSWei Song if (IS_ERR(data->hwmon_dev)) { 2144792d376bSWei Song err = PTR_ERR(data->hwmon_dev); 2145792d376bSWei Song goto exit_remove; 2146792d376bSWei Song } 2147792d376bSWei Song 2148792d376bSWei Song return 0; 2149792d376bSWei Song 2150792d376bSWei Song exit_remove: 21516f3dcde9SJean Delvare w83795_handle_files(dev, device_remove_file_wrapper); 2152792d376bSWei Song kfree(data); 2153792d376bSWei Song exit: 2154792d376bSWei Song return err; 2155792d376bSWei Song } 2156792d376bSWei Song 2157792d376bSWei Song static int w83795_remove(struct i2c_client *client) 2158792d376bSWei Song { 2159792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 2160792d376bSWei Song 2161792d376bSWei Song hwmon_device_unregister(data->hwmon_dev); 21626f3dcde9SJean Delvare w83795_handle_files(&client->dev, device_remove_file_wrapper); 2163792d376bSWei Song kfree(data); 2164792d376bSWei Song 2165792d376bSWei Song return 0; 2166792d376bSWei Song } 2167792d376bSWei Song 2168792d376bSWei Song 2169792d376bSWei Song static const struct i2c_device_id w83795_id[] = { 2170093d1a47SJean Delvare { "w83795g", w83795g }, 2171093d1a47SJean Delvare { "w83795adg", w83795adg }, 2172792d376bSWei Song { } 2173792d376bSWei Song }; 2174792d376bSWei Song MODULE_DEVICE_TABLE(i2c, w83795_id); 2175792d376bSWei Song 2176792d376bSWei Song static struct i2c_driver w83795_driver = { 2177792d376bSWei Song .driver = { 2178792d376bSWei Song .name = "w83795", 2179792d376bSWei Song }, 2180792d376bSWei Song .probe = w83795_probe, 2181792d376bSWei Song .remove = w83795_remove, 2182792d376bSWei Song .id_table = w83795_id, 2183792d376bSWei Song 2184792d376bSWei Song .class = I2C_CLASS_HWMON, 2185792d376bSWei Song .detect = w83795_detect, 2186792d376bSWei Song .address_list = normal_i2c, 2187792d376bSWei Song }; 2188792d376bSWei Song 2189792d376bSWei Song static int __init sensors_w83795_init(void) 2190792d376bSWei Song { 2191792d376bSWei Song return i2c_add_driver(&w83795_driver); 2192792d376bSWei Song } 2193792d376bSWei Song 2194792d376bSWei Song static void __exit sensors_w83795_exit(void) 2195792d376bSWei Song { 2196792d376bSWei Song i2c_del_driver(&w83795_driver); 2197792d376bSWei Song } 2198792d376bSWei Song 2199792d376bSWei Song MODULE_AUTHOR("Wei Song"); 2200315bacfdSJean Delvare MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 2201792d376bSWei Song MODULE_LICENSE("GPL"); 2202792d376bSWei Song 2203792d376bSWei Song module_init(sensors_w83795_init); 2204792d376bSWei Song module_exit(sensors_w83795_exit); 2205