1792d376bSWei Song /* 2792d376bSWei Song * w83795.c - Linux kernel driver for hardware monitoring 3792d376bSWei Song * Copyright (C) 2008 Nuvoton Technology Corp. 4792d376bSWei Song * Wei Song 5e3760b43SJean Delvare * Copyright (C) 2010 Jean Delvare <khali@linux-fr.org> 6792d376bSWei Song * 7792d376bSWei Song * This program is free software; you can redistribute it and/or modify 8792d376bSWei Song * it under the terms of the GNU General Public License as published by 9792d376bSWei Song * the Free Software Foundation - version 2. 10792d376bSWei Song * 11792d376bSWei Song * This program is distributed in the hope that it will be useful, 12792d376bSWei Song * but WITHOUT ANY WARRANTY; without even the implied warranty of 13792d376bSWei Song * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14792d376bSWei Song * GNU General Public License for more details. 15792d376bSWei Song * 16792d376bSWei Song * You should have received a copy of the GNU General Public License 17792d376bSWei Song * along with this program; if not, write to the Free Software 18792d376bSWei Song * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19792d376bSWei Song * 02110-1301 USA. 20792d376bSWei Song * 21792d376bSWei Song * Supports following chips: 22792d376bSWei Song * 23792d376bSWei Song * Chip #vin #fanin #pwm #temp #dts wchipid vendid i2c ISA 24792d376bSWei Song * w83795g 21 14 8 6 8 0x79 0x5ca3 yes no 25792d376bSWei Song * w83795adg 18 14 2 6 8 0x79 0x5ca3 yes no 26792d376bSWei Song */ 27792d376bSWei Song 28792d376bSWei Song #include <linux/kernel.h> 29792d376bSWei Song #include <linux/module.h> 30792d376bSWei Song #include <linux/init.h> 31792d376bSWei Song #include <linux/slab.h> 32792d376bSWei Song #include <linux/i2c.h> 33792d376bSWei Song #include <linux/hwmon.h> 34792d376bSWei Song #include <linux/hwmon-sysfs.h> 35792d376bSWei Song #include <linux/err.h> 36792d376bSWei Song #include <linux/mutex.h> 37792d376bSWei Song #include <linux/delay.h> 38792d376bSWei Song 39792d376bSWei Song /* Addresses to scan */ 4086ef4d2fSJean Delvare static const unsigned short normal_i2c[] = { 4186ef4d2fSJean Delvare 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END 4286ef4d2fSJean Delvare }; 43792d376bSWei Song 44792d376bSWei Song 45792d376bSWei Song static int reset; 46792d376bSWei Song module_param(reset, bool, 0); 47792d376bSWei Song MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); 48792d376bSWei Song 49792d376bSWei Song 50792d376bSWei Song #define W83795_REG_BANKSEL 0x00 51792d376bSWei Song #define W83795_REG_VENDORID 0xfd 52792d376bSWei Song #define W83795_REG_CHIPID 0xfe 53792d376bSWei Song #define W83795_REG_DEVICEID 0xfb 542be381deSJean Delvare #define W83795_REG_DEVICEID_A 0xff 55792d376bSWei Song 56792d376bSWei Song #define W83795_REG_I2C_ADDR 0xfc 57792d376bSWei Song #define W83795_REG_CONFIG 0x01 58792d376bSWei Song #define W83795_REG_CONFIG_CONFIG48 0x04 5980646b95SJean Delvare #define W83795_REG_CONFIG_START 0x01 60792d376bSWei Song 61792d376bSWei Song /* Multi-Function Pin Ctrl Registers */ 62792d376bSWei Song #define W83795_REG_VOLT_CTRL1 0x02 63792d376bSWei Song #define W83795_REG_VOLT_CTRL2 0x03 64792d376bSWei Song #define W83795_REG_TEMP_CTRL1 0x04 65792d376bSWei Song #define W83795_REG_TEMP_CTRL2 0x05 66792d376bSWei Song #define W83795_REG_FANIN_CTRL1 0x06 67792d376bSWei Song #define W83795_REG_FANIN_CTRL2 0x07 68792d376bSWei Song #define W83795_REG_VMIGB_CTRL 0x08 69792d376bSWei Song 70792d376bSWei Song #define TEMP_READ 0 71792d376bSWei Song #define TEMP_CRIT 1 72792d376bSWei Song #define TEMP_CRIT_HYST 2 73792d376bSWei Song #define TEMP_WARN 3 74792d376bSWei Song #define TEMP_WARN_HYST 4 75792d376bSWei Song /* only crit and crit_hyst affect real-time alarm status 76792d376bSWei Song * current crit crit_hyst warn warn_hyst */ 7786ef4d2fSJean Delvare static const u16 W83795_REG_TEMP[][5] = { 78792d376bSWei Song {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ 79792d376bSWei Song {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ 80792d376bSWei Song {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ 81792d376bSWei Song {0x24, 0xa2, 0xa3, 0xa4, 0xa5}, /* TD4/TR4 */ 82792d376bSWei Song {0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, /* TR5 */ 83792d376bSWei Song {0x20, 0xaa, 0xab, 0xac, 0xad}, /* TR6 */ 84792d376bSWei Song }; 85792d376bSWei Song 86792d376bSWei Song #define IN_READ 0 87792d376bSWei Song #define IN_MAX 1 88792d376bSWei Song #define IN_LOW 2 89792d376bSWei Song static const u16 W83795_REG_IN[][3] = { 90792d376bSWei Song /* Current, HL, LL */ 91792d376bSWei Song {0x10, 0x70, 0x71}, /* VSEN1 */ 92792d376bSWei Song {0x11, 0x72, 0x73}, /* VSEN2 */ 93792d376bSWei Song {0x12, 0x74, 0x75}, /* VSEN3 */ 94792d376bSWei Song {0x13, 0x76, 0x77}, /* VSEN4 */ 95792d376bSWei Song {0x14, 0x78, 0x79}, /* VSEN5 */ 96792d376bSWei Song {0x15, 0x7a, 0x7b}, /* VSEN6 */ 97792d376bSWei Song {0x16, 0x7c, 0x7d}, /* VSEN7 */ 98792d376bSWei Song {0x17, 0x7e, 0x7f}, /* VSEN8 */ 99792d376bSWei Song {0x18, 0x80, 0x81}, /* VSEN9 */ 100792d376bSWei Song {0x19, 0x82, 0x83}, /* VSEN10 */ 101792d376bSWei Song {0x1A, 0x84, 0x85}, /* VSEN11 */ 102792d376bSWei Song {0x1B, 0x86, 0x87}, /* VTT */ 103792d376bSWei Song {0x1C, 0x88, 0x89}, /* 3VDD */ 104792d376bSWei Song {0x1D, 0x8a, 0x8b}, /* 3VSB */ 105792d376bSWei Song {0x1E, 0x8c, 0x8d}, /* VBAT */ 106792d376bSWei Song {0x1F, 0xa6, 0xa7}, /* VSEN12 */ 107792d376bSWei Song {0x20, 0xaa, 0xab}, /* VSEN13 */ 108792d376bSWei Song {0x21, 0x96, 0x97}, /* VSEN14 */ 109792d376bSWei Song {0x22, 0x9a, 0x9b}, /* VSEN15 */ 110792d376bSWei Song {0x23, 0x9e, 0x9f}, /* VSEN16 */ 111792d376bSWei Song {0x24, 0xa2, 0xa3}, /* VSEN17 */ 112792d376bSWei Song }; 113792d376bSWei Song #define W83795_REG_VRLSB 0x3C 114792d376bSWei Song 115792d376bSWei Song static const u8 W83795_REG_IN_HL_LSB[] = { 116792d376bSWei Song 0x8e, /* VSEN1-4 */ 117792d376bSWei Song 0x90, /* VSEN5-8 */ 118792d376bSWei Song 0x92, /* VSEN9-11 */ 119792d376bSWei Song 0x94, /* VTT, 3VDD, 3VSB, 3VBAT */ 120792d376bSWei Song 0xa8, /* VSEN12 */ 121792d376bSWei Song 0xac, /* VSEN13 */ 122792d376bSWei Song 0x98, /* VSEN14 */ 123792d376bSWei Song 0x9c, /* VSEN15 */ 124792d376bSWei Song 0xa0, /* VSEN16 */ 125792d376bSWei Song 0xa4, /* VSEN17 */ 126792d376bSWei Song }; 127792d376bSWei Song 128792d376bSWei Song #define IN_LSB_REG(index, type) \ 129792d376bSWei Song (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ 130792d376bSWei Song : (W83795_REG_IN_HL_LSB[(index)] + 1)) 131792d376bSWei Song 132792d376bSWei Song #define IN_LSB_SHIFT 0 133792d376bSWei Song #define IN_LSB_IDX 1 134792d376bSWei Song static const u8 IN_LSB_SHIFT_IDX[][2] = { 135792d376bSWei Song /* High/Low LSB shift, LSB No. */ 136792d376bSWei Song {0x00, 0x00}, /* VSEN1 */ 137792d376bSWei Song {0x02, 0x00}, /* VSEN2 */ 138792d376bSWei Song {0x04, 0x00}, /* VSEN3 */ 139792d376bSWei Song {0x06, 0x00}, /* VSEN4 */ 140792d376bSWei Song {0x00, 0x01}, /* VSEN5 */ 141792d376bSWei Song {0x02, 0x01}, /* VSEN6 */ 142792d376bSWei Song {0x04, 0x01}, /* VSEN7 */ 143792d376bSWei Song {0x06, 0x01}, /* VSEN8 */ 144792d376bSWei Song {0x00, 0x02}, /* VSEN9 */ 145792d376bSWei Song {0x02, 0x02}, /* VSEN10 */ 146792d376bSWei Song {0x04, 0x02}, /* VSEN11 */ 147792d376bSWei Song {0x00, 0x03}, /* VTT */ 148792d376bSWei Song {0x02, 0x03}, /* 3VDD */ 149792d376bSWei Song {0x04, 0x03}, /* 3VSB */ 150792d376bSWei Song {0x06, 0x03}, /* VBAT */ 151792d376bSWei Song {0x06, 0x04}, /* VSEN12 */ 152792d376bSWei Song {0x06, 0x05}, /* VSEN13 */ 153792d376bSWei Song {0x06, 0x06}, /* VSEN14 */ 154792d376bSWei Song {0x06, 0x07}, /* VSEN15 */ 155792d376bSWei Song {0x06, 0x08}, /* VSEN16 */ 156792d376bSWei Song {0x06, 0x09}, /* VSEN17 */ 157792d376bSWei Song }; 158792d376bSWei Song 159792d376bSWei Song 160792d376bSWei Song #define W83795_REG_FAN(index) (0x2E + (index)) 161792d376bSWei Song #define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) 162792d376bSWei Song #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) 163792d376bSWei Song #define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ 1647eb8d508SJean Delvare (((index) & 1) ? 4 : 0) 165792d376bSWei Song 166792d376bSWei Song #define W83795_REG_VID_CTRL 0x6A 167792d376bSWei Song 168cf6b9ea6SJean Delvare #define W83795_REG_ALARM_CTRL 0x40 169cf6b9ea6SJean Delvare #define ALARM_CTRL_RTSACS (1 << 7) 170792d376bSWei Song #define W83795_REG_ALARM(index) (0x41 + (index)) 171792d376bSWei Song #define W83795_REG_CLR_CHASSIS 0x4D 172cf6b9ea6SJean Delvare #define W83795_REG_BEEP(index) (0x50 + (index)) 173792d376bSWei Song 174792d376bSWei Song 175792d376bSWei Song #define W83795_REG_FCMS1 0x201 176792d376bSWei Song #define W83795_REG_FCMS2 0x208 177792d376bSWei Song #define W83795_REG_TFMR(index) (0x202 + (index)) 178792d376bSWei Song #define W83795_REG_FOMC 0x20F 179792d376bSWei Song 180792d376bSWei Song #define W83795_REG_TSS(index) (0x209 + (index)) 181792d376bSWei Song 182edff2f8dSJean Delvare #define TSS_MAP_RESERVED 0xff 183edff2f8dSJean Delvare static const u8 tss_map[4][6] = { 184edff2f8dSJean Delvare { 0, 1, 2, 3, 4, 5}, 185edff2f8dSJean Delvare { 6, 7, 8, 9, 0, 1}, 186edff2f8dSJean Delvare {10, 11, 12, 13, 2, 3}, 187edff2f8dSJean Delvare { 4, 5, 4, 5, TSS_MAP_RESERVED, TSS_MAP_RESERVED}, 188edff2f8dSJean Delvare }; 189edff2f8dSJean Delvare 190792d376bSWei Song #define PWM_OUTPUT 0 191fd7f82b8SJean Delvare #define PWM_FREQ 1 192fd7f82b8SJean Delvare #define PWM_START 2 193fd7f82b8SJean Delvare #define PWM_NONSTOP 3 194fd7f82b8SJean Delvare #define PWM_STOP_TIME 4 195fd7f82b8SJean Delvare #define W83795_REG_PWM(index, nr) (0x210 + (nr) * 8 + (index)) 196792d376bSWei Song 197792d376bSWei Song #define W83795_REG_FTSH(index) (0x240 + (index) * 2) 198792d376bSWei Song #define W83795_REG_FTSL(index) (0x241 + (index) * 2) 199792d376bSWei Song #define W83795_REG_TFTS 0x250 200792d376bSWei Song 201792d376bSWei Song #define TEMP_PWM_TTTI 0 202792d376bSWei Song #define TEMP_PWM_CTFS 1 203792d376bSWei Song #define TEMP_PWM_HCT 2 204792d376bSWei Song #define TEMP_PWM_HOT 3 205792d376bSWei Song #define W83795_REG_TTTI(index) (0x260 + (index)) 206792d376bSWei Song #define W83795_REG_CTFS(index) (0x268 + (index)) 207792d376bSWei Song #define W83795_REG_HT(index) (0x270 + (index)) 208792d376bSWei Song 209792d376bSWei Song #define SF4_TEMP 0 210792d376bSWei Song #define SF4_PWM 1 211792d376bSWei Song #define W83795_REG_SF4_TEMP(temp_num, index) \ 212792d376bSWei Song (0x280 + 0x10 * (temp_num) + (index)) 213792d376bSWei Song #define W83795_REG_SF4_PWM(temp_num, index) \ 214792d376bSWei Song (0x288 + 0x10 * (temp_num) + (index)) 215792d376bSWei Song 216792d376bSWei Song #define W83795_REG_DTSC 0x301 217792d376bSWei Song #define W83795_REG_DTSE 0x302 218792d376bSWei Song #define W83795_REG_DTS(index) (0x26 + (index)) 21954891a3cSJean Delvare #define W83795_REG_PECI_TBASE(index) (0x320 + (index)) 220792d376bSWei Song 221792d376bSWei Song #define DTS_CRIT 0 222792d376bSWei Song #define DTS_CRIT_HYST 1 223792d376bSWei Song #define DTS_WARN 2 224792d376bSWei Song #define DTS_WARN_HYST 3 225792d376bSWei Song #define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 226792d376bSWei Song 227792d376bSWei Song #define SETUP_PWM_DEFAULT 0 228792d376bSWei Song #define SETUP_PWM_UPTIME 1 229792d376bSWei Song #define SETUP_PWM_DOWNTIME 2 230792d376bSWei Song #define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 231792d376bSWei Song 232792d376bSWei Song static inline u16 in_from_reg(u8 index, u16 val) 233792d376bSWei Song { 23449c7347aSJean Delvare /* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */ 23549c7347aSJean Delvare if (index >= 12 && index <= 14) 236792d376bSWei Song return val * 6; 237792d376bSWei Song else 238792d376bSWei Song return val * 2; 239792d376bSWei Song } 240792d376bSWei Song 241792d376bSWei Song static inline u16 in_to_reg(u8 index, u16 val) 242792d376bSWei Song { 24349c7347aSJean Delvare if (index >= 12 && index <= 14) 244792d376bSWei Song return val / 6; 245792d376bSWei Song else 246792d376bSWei Song return val / 2; 247792d376bSWei Song } 248792d376bSWei Song 249792d376bSWei Song static inline unsigned long fan_from_reg(u16 val) 250792d376bSWei Song { 2516c82b2f3SJean Delvare if ((val == 0xfff) || (val == 0)) 252792d376bSWei Song return 0; 253792d376bSWei Song return 1350000UL / val; 254792d376bSWei Song } 255792d376bSWei Song 256792d376bSWei Song static inline u16 fan_to_reg(long rpm) 257792d376bSWei Song { 258792d376bSWei Song if (rpm <= 0) 259792d376bSWei Song return 0x0fff; 260792d376bSWei Song return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 261792d376bSWei Song } 262792d376bSWei Song 263792d376bSWei Song static inline unsigned long time_from_reg(u8 reg) 264792d376bSWei Song { 265792d376bSWei Song return reg * 100; 266792d376bSWei Song } 267792d376bSWei Song 268792d376bSWei Song static inline u8 time_to_reg(unsigned long val) 269792d376bSWei Song { 270792d376bSWei Song return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); 271792d376bSWei Song } 272792d376bSWei Song 273792d376bSWei Song static inline long temp_from_reg(s8 reg) 274792d376bSWei Song { 275792d376bSWei Song return reg * 1000; 276792d376bSWei Song } 277792d376bSWei Song 278792d376bSWei Song static inline s8 temp_to_reg(long val, s8 min, s8 max) 279792d376bSWei Song { 280dd127f5cSJean Delvare return SENSORS_LIMIT(val / 1000, min, max); 281792d376bSWei Song } 282792d376bSWei Song 28301879a85SJean Delvare static const u16 pwm_freq_cksel0[16] = { 28401879a85SJean Delvare 1024, 512, 341, 256, 205, 171, 146, 128, 28501879a85SJean Delvare 85, 64, 32, 16, 8, 4, 2, 1 28601879a85SJean Delvare }; 28701879a85SJean Delvare 28801879a85SJean Delvare static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) 28901879a85SJean Delvare { 29001879a85SJean Delvare unsigned long base_clock; 29101879a85SJean Delvare 29201879a85SJean Delvare if (reg & 0x80) { 29301879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 29401879a85SJean Delvare return base_clock / ((reg & 0x7f) + 1); 29501879a85SJean Delvare } else 29601879a85SJean Delvare return pwm_freq_cksel0[reg & 0x0f]; 29701879a85SJean Delvare } 29801879a85SJean Delvare 29901879a85SJean Delvare static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) 30001879a85SJean Delvare { 30101879a85SJean Delvare unsigned long base_clock; 30201879a85SJean Delvare u8 reg0, reg1; 30301879a85SJean Delvare unsigned long best0, best1; 30401879a85SJean Delvare 30501879a85SJean Delvare /* Best fit for cksel = 0 */ 30601879a85SJean Delvare for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { 30701879a85SJean Delvare if (val > (pwm_freq_cksel0[reg0] + 30801879a85SJean Delvare pwm_freq_cksel0[reg0 + 1]) / 2) 30901879a85SJean Delvare break; 31001879a85SJean Delvare } 31101879a85SJean Delvare if (val < 375) /* cksel = 1 can't beat this */ 31201879a85SJean Delvare return reg0; 31301879a85SJean Delvare best0 = pwm_freq_cksel0[reg0]; 31401879a85SJean Delvare 31501879a85SJean Delvare /* Best fit for cksel = 1 */ 31601879a85SJean Delvare base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 31701879a85SJean Delvare reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); 31801879a85SJean Delvare best1 = base_clock / reg1; 31901879a85SJean Delvare reg1 = 0x80 | (reg1 - 1); 32001879a85SJean Delvare 32101879a85SJean Delvare /* Choose the closest one */ 32201879a85SJean Delvare if (abs(val - best0) > abs(val - best1)) 32301879a85SJean Delvare return reg1; 32401879a85SJean Delvare else 32501879a85SJean Delvare return reg0; 32601879a85SJean Delvare } 327792d376bSWei Song 328792d376bSWei Song enum chip_types {w83795g, w83795adg}; 329792d376bSWei Song 330792d376bSWei Song struct w83795_data { 331792d376bSWei Song struct device *hwmon_dev; 332792d376bSWei Song struct mutex update_lock; 333792d376bSWei Song unsigned long last_updated; /* In jiffies */ 334792d376bSWei Song enum chip_types chip_type; 335792d376bSWei Song 336792d376bSWei Song u8 bank; 337792d376bSWei Song 338792d376bSWei Song u32 has_in; /* Enable monitor VIN or not */ 3390e256018SJean Delvare u8 has_dyn_in; /* Only in2-0 can have this */ 340792d376bSWei Song u16 in[21][3]; /* Register value, read/high/low */ 341792d376bSWei Song u8 in_lsb[10][3]; /* LSB Register value, high/low */ 342792d376bSWei Song u8 has_gain; /* has gain: in17-20 * 8 */ 343792d376bSWei Song 344792d376bSWei Song u16 has_fan; /* Enable fan14-1 or not */ 345792d376bSWei Song u16 fan[14]; /* Register value combine */ 346792d376bSWei Song u16 fan_min[14]; /* Register value combine */ 347792d376bSWei Song 348792d376bSWei Song u8 has_temp; /* Enable monitor temp6-1 or not */ 349dd127f5cSJean Delvare s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 350792d376bSWei Song u8 temp_read_vrlsb[6]; 35139deb699SJean Delvare u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */ 352792d376bSWei Song u8 temp_src[3]; /* Register value */ 353792d376bSWei Song 354792d376bSWei Song u8 enable_dts; /* Enable PECI and SB-TSI, 355792d376bSWei Song * bit 0: =1 enable, =0 disable, 356792d376bSWei Song * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ 357792d376bSWei Song u8 has_dts; /* Enable monitor DTS temp */ 358dd127f5cSJean Delvare s8 dts[8]; /* Register value */ 359792d376bSWei Song u8 dts_read_vrlsb[8]; /* Register value */ 360dd127f5cSJean Delvare s8 dts_ext[4]; /* Register value */ 361792d376bSWei Song 362792d376bSWei Song u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, 363792d376bSWei Song * no config register, only affected by chip 364792d376bSWei Song * type */ 365fd7f82b8SJean Delvare u8 pwm[8][5]; /* Register value, output, freq, start, 366fd7f82b8SJean Delvare * non stop, stop time */ 36701879a85SJean Delvare u16 clkin; /* CLKIN frequency in kHz */ 368792d376bSWei Song u8 pwm_fcms[2]; /* Register value */ 369792d376bSWei Song u8 pwm_tfmr[6]; /* Register value */ 370792d376bSWei Song u8 pwm_fomc; /* Register value */ 371792d376bSWei Song 372792d376bSWei Song u16 target_speed[8]; /* Register value, target speed for speed 373792d376bSWei Song * cruise */ 374792d376bSWei Song u8 tol_speed; /* tolerance of target speed */ 375792d376bSWei Song u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 376792d376bSWei Song u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 377792d376bSWei Song 378792d376bSWei Song u8 setup_pwm[3]; /* Register value */ 379792d376bSWei Song 380792d376bSWei Song u8 alarms[6]; /* Register value */ 381792d376bSWei Song u8 beeps[6]; /* Register value */ 382792d376bSWei Song 383792d376bSWei Song char valid; 3842ae61de9SJean Delvare char valid_limits; 3851bb3450cSJean Delvare char valid_pwm_config; 386792d376bSWei Song }; 387792d376bSWei Song 388792d376bSWei Song /* 389792d376bSWei Song * Hardware access 390b2469f42SJean Delvare * We assume that nobdody can change the bank outside the driver. 391792d376bSWei Song */ 392792d376bSWei Song 393b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 394b2469f42SJean Delvare static int w83795_set_bank(struct i2c_client *client, u8 bank) 395792d376bSWei Song { 396792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 397b2469f42SJean Delvare int err; 398792d376bSWei Song 399b2469f42SJean Delvare /* If the same bank is already set, nothing to do */ 400b2469f42SJean Delvare if ((data->bank & 0x07) == bank) 401b2469f42SJean Delvare return 0; 402b2469f42SJean Delvare 403b2469f42SJean Delvare /* Change to new bank, preserve all other bits */ 404b2469f42SJean Delvare bank |= data->bank & ~0x07; 405b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 406b2469f42SJean Delvare if (err < 0) { 407792d376bSWei Song dev_err(&client->dev, 408b2469f42SJean Delvare "Failed to set bank to %d, err %d\n", 409b2469f42SJean Delvare (int)bank, err); 410b2469f42SJean Delvare return err; 411792d376bSWei Song } 412b2469f42SJean Delvare data->bank = bank; 413b2469f42SJean Delvare 414b2469f42SJean Delvare return 0; 415792d376bSWei Song } 416b2469f42SJean Delvare 417b2469f42SJean Delvare /* Must be called with data->update_lock held, except during initialization */ 418b2469f42SJean Delvare static u8 w83795_read(struct i2c_client *client, u16 reg) 419b2469f42SJean Delvare { 420b2469f42SJean Delvare int err; 421b2469f42SJean Delvare 422b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 423b2469f42SJean Delvare if (err < 0) 424b2469f42SJean Delvare return 0x00; /* Arbitrary */ 425b2469f42SJean Delvare 426b2469f42SJean Delvare err = i2c_smbus_read_byte_data(client, reg & 0xff); 427b2469f42SJean Delvare if (err < 0) { 428b2469f42SJean Delvare dev_err(&client->dev, 429b2469f42SJean Delvare "Failed to read from register 0x%03x, err %d\n", 430b2469f42SJean Delvare (int)reg, err); 431b2469f42SJean Delvare return 0x00; /* Arbitrary */ 432b2469f42SJean Delvare } 433b2469f42SJean Delvare return err; 434792d376bSWei Song } 435792d376bSWei Song 436792d376bSWei Song /* Must be called with data->update_lock held, except during initialization */ 437792d376bSWei Song static int w83795_write(struct i2c_client *client, u16 reg, u8 value) 438792d376bSWei Song { 439b2469f42SJean Delvare int err; 440792d376bSWei Song 441b2469f42SJean Delvare err = w83795_set_bank(client, reg >> 8); 442b2469f42SJean Delvare if (err < 0) 443b2469f42SJean Delvare return err; 444b2469f42SJean Delvare 445b2469f42SJean Delvare err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 446b2469f42SJean Delvare if (err < 0) 447792d376bSWei Song dev_err(&client->dev, 448b2469f42SJean Delvare "Failed to write to register 0x%03x, err %d\n", 449b2469f42SJean Delvare (int)reg, err); 450b2469f42SJean Delvare return err; 451792d376bSWei Song } 452792d376bSWei Song 4530d7237bfSJean Delvare static void w83795_update_limits(struct i2c_client *client) 4540d7237bfSJean Delvare { 4550d7237bfSJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 4560d7237bfSJean Delvare int i, limit; 4570d7237bfSJean Delvare 4580d7237bfSJean Delvare /* Read the voltage limits */ 4590d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->in); i++) { 4600d7237bfSJean Delvare if (!(data->has_in & (1 << i))) 4610d7237bfSJean Delvare continue; 4620d7237bfSJean Delvare data->in[i][IN_MAX] = 4630d7237bfSJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 4640d7237bfSJean Delvare data->in[i][IN_LOW] = 4650d7237bfSJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 4660d7237bfSJean Delvare } 4670d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { 4680d7237bfSJean Delvare if ((i == 2 && data->chip_type == w83795adg) || 4690d7237bfSJean Delvare (i >= 4 && !(data->has_in & (1 << (i + 11))))) 4700d7237bfSJean Delvare continue; 4710d7237bfSJean Delvare data->in_lsb[i][IN_MAX] = 4720d7237bfSJean Delvare w83795_read(client, IN_LSB_REG(i, IN_MAX)); 4730d7237bfSJean Delvare data->in_lsb[i][IN_LOW] = 4740d7237bfSJean Delvare w83795_read(client, IN_LSB_REG(i, IN_LOW)); 4750d7237bfSJean Delvare } 4760d7237bfSJean Delvare 4770d7237bfSJean Delvare /* Read the fan limits */ 4780d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 4790d7237bfSJean Delvare u8 lsb; 4800d7237bfSJean Delvare 4810d7237bfSJean Delvare /* Each register contains LSB for 2 fans, but we want to 4820d7237bfSJean Delvare * read it only once to save time */ 4830d7237bfSJean Delvare if ((i & 1) == 0 && (data->has_fan & (3 << i))) 4840d7237bfSJean Delvare lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); 4850d7237bfSJean Delvare 4860d7237bfSJean Delvare if (!(data->has_fan & (1 << i))) 4870d7237bfSJean Delvare continue; 4880d7237bfSJean Delvare data->fan_min[i] = 4890d7237bfSJean Delvare w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 4900d7237bfSJean Delvare data->fan_min[i] |= 4910d7237bfSJean Delvare (lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; 4920d7237bfSJean Delvare } 4930d7237bfSJean Delvare 4940d7237bfSJean Delvare /* Read the temperature limits */ 4950d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 4960d7237bfSJean Delvare if (!(data->has_temp & (1 << i))) 4970d7237bfSJean Delvare continue; 4980d7237bfSJean Delvare for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++) 4990d7237bfSJean Delvare data->temp[i][limit] = 5000d7237bfSJean Delvare w83795_read(client, W83795_REG_TEMP[i][limit]); 5010d7237bfSJean Delvare } 5020d7237bfSJean Delvare 5030d7237bfSJean Delvare /* Read the DTS limits */ 504eb02755aSJean Delvare if (data->enable_dts) { 5050d7237bfSJean Delvare for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++) 5060d7237bfSJean Delvare data->dts_ext[limit] = 5070d7237bfSJean Delvare w83795_read(client, W83795_REG_DTS_EXT(limit)); 5080d7237bfSJean Delvare } 5090d7237bfSJean Delvare 5100d7237bfSJean Delvare /* Read beep settings */ 5110d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->beeps); i++) 5120d7237bfSJean Delvare data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); 5132ae61de9SJean Delvare 5142ae61de9SJean Delvare data->valid_limits = 1; 5150d7237bfSJean Delvare } 5160d7237bfSJean Delvare 5171bb3450cSJean Delvare static struct w83795_data *w83795_update_pwm_config(struct device *dev) 5180d7237bfSJean Delvare { 5191bb3450cSJean Delvare struct i2c_client *client = to_i2c_client(dev); 5200d7237bfSJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 5210d7237bfSJean Delvare int i, tmp; 5220d7237bfSJean Delvare 5231bb3450cSJean Delvare mutex_lock(&data->update_lock); 5241bb3450cSJean Delvare 5251bb3450cSJean Delvare if (data->valid_pwm_config) 5261bb3450cSJean Delvare goto END; 5271bb3450cSJean Delvare 5280d7237bfSJean Delvare /* Read temperature source selection */ 5290d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp_src); i++) 5300d7237bfSJean Delvare data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 5310d7237bfSJean Delvare 5320d7237bfSJean Delvare /* Read automatic fan speed control settings */ 5330d7237bfSJean Delvare data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 5340d7237bfSJean Delvare data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 5350d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) 5360d7237bfSJean Delvare data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 5370d7237bfSJean Delvare data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 5380d7237bfSJean Delvare for (i = 0; i < data->has_pwm; i++) { 5390d7237bfSJean Delvare for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) 5400d7237bfSJean Delvare data->pwm[i][tmp] = 5410d7237bfSJean Delvare w83795_read(client, W83795_REG_PWM(i, tmp)); 5420d7237bfSJean Delvare } 5430d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) { 5440d7237bfSJean Delvare data->target_speed[i] = 5450d7237bfSJean Delvare w83795_read(client, W83795_REG_FTSH(i)) << 4; 5460d7237bfSJean Delvare data->target_speed[i] |= 5470d7237bfSJean Delvare w83795_read(client, W83795_REG_FTSL(i)) >> 4; 5480d7237bfSJean Delvare } 5490d7237bfSJean Delvare data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 5500d7237bfSJean Delvare 5510d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { 5520d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_TTTI] = 5530d7237bfSJean Delvare w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 5540d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_CTFS] = 5550d7237bfSJean Delvare w83795_read(client, W83795_REG_CTFS(i)); 5560d7237bfSJean Delvare tmp = w83795_read(client, W83795_REG_HT(i)); 557eb02755aSJean Delvare data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4; 5580d7237bfSJean Delvare data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 5590d7237bfSJean Delvare } 5600d7237bfSJean Delvare 5610d7237bfSJean Delvare /* Read SmartFanIV trip points */ 5620d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { 5630d7237bfSJean Delvare for (tmp = 0; tmp < 7; tmp++) { 5640d7237bfSJean Delvare data->sf4_reg[i][SF4_TEMP][tmp] = 5650d7237bfSJean Delvare w83795_read(client, 5660d7237bfSJean Delvare W83795_REG_SF4_TEMP(i, tmp)); 5670d7237bfSJean Delvare data->sf4_reg[i][SF4_PWM][tmp] = 5680d7237bfSJean Delvare w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 5690d7237bfSJean Delvare } 5700d7237bfSJean Delvare } 5710d7237bfSJean Delvare 5720d7237bfSJean Delvare /* Read setup PWM */ 5730d7237bfSJean Delvare for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++) 5740d7237bfSJean Delvare data->setup_pwm[i] = 5750d7237bfSJean Delvare w83795_read(client, W83795_REG_SETUP_PWM(i)); 5761bb3450cSJean Delvare 5771bb3450cSJean Delvare data->valid_pwm_config = 1; 5781bb3450cSJean Delvare 5791bb3450cSJean Delvare END: 5801bb3450cSJean Delvare mutex_unlock(&data->update_lock); 5811bb3450cSJean Delvare return data; 5820d7237bfSJean Delvare } 5830d7237bfSJean Delvare 584792d376bSWei Song static struct w83795_data *w83795_update_device(struct device *dev) 585792d376bSWei Song { 586792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 587792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 588792d376bSWei Song u16 tmp; 589cf6b9ea6SJean Delvare u8 intrusion; 590792d376bSWei Song int i; 591792d376bSWei Song 592792d376bSWei Song mutex_lock(&data->update_lock); 593792d376bSWei Song 5942ae61de9SJean Delvare if (!data->valid_limits) 5952ae61de9SJean Delvare w83795_update_limits(client); 5962ae61de9SJean Delvare 597792d376bSWei Song if (!(time_after(jiffies, data->last_updated + HZ * 2) 598792d376bSWei Song || !data->valid)) 599792d376bSWei Song goto END; 600792d376bSWei Song 601792d376bSWei Song /* Update the voltages value */ 602792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->in); i++) { 603792d376bSWei Song if (!(data->has_in & (1 << i))) 604792d376bSWei Song continue; 605792d376bSWei Song tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 606a654b9d4SJean Delvare tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; 607792d376bSWei Song data->in[i][IN_READ] = tmp; 608792d376bSWei Song } 609792d376bSWei Song 6100e256018SJean Delvare /* in0-2 can have dynamic limits (W83795G only) */ 6110e256018SJean Delvare if (data->has_dyn_in) { 6120e256018SJean Delvare u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); 6130e256018SJean Delvare u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); 6140e256018SJean Delvare 6150e256018SJean Delvare for (i = 0; i < 3; i++) { 6160e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 6170e256018SJean Delvare continue; 6180e256018SJean Delvare data->in[i][IN_MAX] = 6190e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_MAX]); 6200e256018SJean Delvare data->in[i][IN_LOW] = 6210e256018SJean Delvare w83795_read(client, W83795_REG_IN[i][IN_LOW]); 6220e256018SJean Delvare data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; 6230e256018SJean Delvare data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; 6240e256018SJean Delvare } 6250e256018SJean Delvare } 6260e256018SJean Delvare 627792d376bSWei Song /* Update fan */ 628792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 629792d376bSWei Song if (!(data->has_fan & (1 << i))) 630792d376bSWei Song continue; 631792d376bSWei Song data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 632eb02755aSJean Delvare data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; 633792d376bSWei Song } 634792d376bSWei Song 635792d376bSWei Song /* Update temperature */ 636792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 637792d376bSWei Song data->temp[i][TEMP_READ] = 638792d376bSWei Song w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 639792d376bSWei Song data->temp_read_vrlsb[i] = 640792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 641792d376bSWei Song } 642792d376bSWei Song 643792d376bSWei Song /* Update dts temperature */ 644eb02755aSJean Delvare if (data->enable_dts) { 645792d376bSWei Song for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 646792d376bSWei Song if (!(data->has_dts & (1 << i))) 647792d376bSWei Song continue; 648792d376bSWei Song data->dts[i] = 649792d376bSWei Song w83795_read(client, W83795_REG_DTS(i)); 650792d376bSWei Song data->dts_read_vrlsb[i] = 651792d376bSWei Song w83795_read(client, W83795_REG_VRLSB); 652792d376bSWei Song } 653792d376bSWei Song } 654792d376bSWei Song 655792d376bSWei Song /* Update pwm output */ 656792d376bSWei Song for (i = 0; i < data->has_pwm; i++) { 657792d376bSWei Song data->pwm[i][PWM_OUTPUT] = 658792d376bSWei Song w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 659792d376bSWei Song } 660792d376bSWei Song 661cf6b9ea6SJean Delvare /* Update intrusion and alarms 662cf6b9ea6SJean Delvare * It is important to read intrusion first, because reading from 663cf6b9ea6SJean Delvare * register SMI STS6 clears the interrupt status temporarily. */ 664cf6b9ea6SJean Delvare tmp = w83795_read(client, W83795_REG_ALARM_CTRL); 665cf6b9ea6SJean Delvare /* Switch to interrupt status for intrusion if needed */ 666cf6b9ea6SJean Delvare if (tmp & ALARM_CTRL_RTSACS) 667cf6b9ea6SJean Delvare w83795_write(client, W83795_REG_ALARM_CTRL, 668cf6b9ea6SJean Delvare tmp & ~ALARM_CTRL_RTSACS); 669cf6b9ea6SJean Delvare intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6); 670cf6b9ea6SJean Delvare /* Switch to real-time alarms */ 671cf6b9ea6SJean Delvare w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS); 672cd316df5SJean Delvare for (i = 0; i < ARRAY_SIZE(data->alarms); i++) 673792d376bSWei Song data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 674cf6b9ea6SJean Delvare data->alarms[5] |= intrusion; 675cf6b9ea6SJean Delvare /* Restore original configuration if needed */ 676cf6b9ea6SJean Delvare if (!(tmp & ALARM_CTRL_RTSACS)) 677cf6b9ea6SJean Delvare w83795_write(client, W83795_REG_ALARM_CTRL, 678cf6b9ea6SJean Delvare tmp & ~ALARM_CTRL_RTSACS); 679792d376bSWei Song 680792d376bSWei Song data->last_updated = jiffies; 681792d376bSWei Song data->valid = 1; 682792d376bSWei Song 683792d376bSWei Song END: 684792d376bSWei Song mutex_unlock(&data->update_lock); 685792d376bSWei Song return data; 686792d376bSWei Song } 687792d376bSWei Song 688792d376bSWei Song /* 689792d376bSWei Song * Sysfs attributes 690792d376bSWei Song */ 691792d376bSWei Song 692792d376bSWei Song #define ALARM_STATUS 0 693792d376bSWei Song #define BEEP_ENABLE 1 694792d376bSWei Song static ssize_t 695792d376bSWei Song show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 696792d376bSWei Song { 697792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 698792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 699792d376bSWei Song to_sensor_dev_attr_2(attr); 700792d376bSWei Song int nr = sensor_attr->nr; 701792d376bSWei Song int index = sensor_attr->index >> 3; 702792d376bSWei Song int bit = sensor_attr->index & 0x07; 703792d376bSWei Song u8 val; 704792d376bSWei Song 705eb02755aSJean Delvare if (nr == ALARM_STATUS) 706eb02755aSJean Delvare val = (data->alarms[index] >> bit) & 1; 707eb02755aSJean Delvare else /* BEEP_ENABLE */ 708eb02755aSJean Delvare val = (data->beeps[index] >> bit) & 1; 709792d376bSWei Song 710792d376bSWei Song return sprintf(buf, "%u\n", val); 711792d376bSWei Song } 712792d376bSWei Song 713792d376bSWei Song static ssize_t 714792d376bSWei Song store_beep(struct device *dev, struct device_attribute *attr, 715792d376bSWei Song const char *buf, size_t count) 716792d376bSWei Song { 717792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 718792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 719792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 720792d376bSWei Song to_sensor_dev_attr_2(attr); 721792d376bSWei Song int index = sensor_attr->index >> 3; 722792d376bSWei Song int shift = sensor_attr->index & 0x07; 723792d376bSWei Song u8 beep_bit = 1 << shift; 724792d376bSWei Song unsigned long val; 725792d376bSWei Song 726792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 727792d376bSWei Song return -EINVAL; 728792d376bSWei Song if (val != 0 && val != 1) 729792d376bSWei Song return -EINVAL; 730792d376bSWei Song 731792d376bSWei Song mutex_lock(&data->update_lock); 732792d376bSWei Song data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 733792d376bSWei Song data->beeps[index] &= ~beep_bit; 734792d376bSWei Song data->beeps[index] |= val << shift; 735792d376bSWei Song w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 736792d376bSWei Song mutex_unlock(&data->update_lock); 737792d376bSWei Song 738792d376bSWei Song return count; 739792d376bSWei Song } 740792d376bSWei Song 74124377101SJean Delvare /* Write 0 to clear chassis alarm */ 742792d376bSWei Song static ssize_t 743792d376bSWei Song store_chassis_clear(struct device *dev, 744792d376bSWei Song struct device_attribute *attr, const char *buf, 745792d376bSWei Song size_t count) 746792d376bSWei Song { 747792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 748792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 74924377101SJean Delvare unsigned long val; 75024377101SJean Delvare 75124377101SJean Delvare if (strict_strtoul(buf, 10, &val) < 0 || val != 0) 75224377101SJean Delvare return -EINVAL; 753792d376bSWei Song 754792d376bSWei Song mutex_lock(&data->update_lock); 755792d376bSWei Song val = w83795_read(client, W83795_REG_CLR_CHASSIS); 756792d376bSWei Song val |= 0x80; 757792d376bSWei Song w83795_write(client, W83795_REG_CLR_CHASSIS, val); 758792d376bSWei Song mutex_unlock(&data->update_lock); 759792d376bSWei Song return count; 760792d376bSWei Song } 761792d376bSWei Song 762792d376bSWei Song #define FAN_INPUT 0 763792d376bSWei Song #define FAN_MIN 1 764792d376bSWei Song static ssize_t 765792d376bSWei Song show_fan(struct device *dev, struct device_attribute *attr, char *buf) 766792d376bSWei Song { 767792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 768792d376bSWei Song to_sensor_dev_attr_2(attr); 769792d376bSWei Song int nr = sensor_attr->nr; 770792d376bSWei Song int index = sensor_attr->index; 771792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 772792d376bSWei Song u16 val; 773792d376bSWei Song 774eb02755aSJean Delvare if (nr == FAN_INPUT) 775792d376bSWei Song val = data->fan[index] & 0x0fff; 776792d376bSWei Song else 777792d376bSWei Song val = data->fan_min[index] & 0x0fff; 778792d376bSWei Song 779792d376bSWei Song return sprintf(buf, "%lu\n", fan_from_reg(val)); 780792d376bSWei Song } 781792d376bSWei Song 782792d376bSWei Song static ssize_t 783792d376bSWei Song store_fan_min(struct device *dev, struct device_attribute *attr, 784792d376bSWei Song const char *buf, size_t count) 785792d376bSWei Song { 786792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 787792d376bSWei Song to_sensor_dev_attr_2(attr); 788792d376bSWei Song int index = sensor_attr->index; 789792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 790792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 791792d376bSWei Song unsigned long val; 792792d376bSWei Song 793792d376bSWei Song if (strict_strtoul(buf, 10, &val)) 794792d376bSWei Song return -EINVAL; 795792d376bSWei Song val = fan_to_reg(val); 796792d376bSWei Song 797792d376bSWei Song mutex_lock(&data->update_lock); 798792d376bSWei Song data->fan_min[index] = val; 799792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 800792d376bSWei Song val &= 0x0f; 8017eb8d508SJean Delvare if (index & 1) { 802792d376bSWei Song val <<= 4; 803792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 804792d376bSWei Song & 0x0f; 805792d376bSWei Song } else { 806792d376bSWei Song val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 807792d376bSWei Song & 0xf0; 808792d376bSWei Song } 809792d376bSWei Song w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 810792d376bSWei Song mutex_unlock(&data->update_lock); 811792d376bSWei Song 812792d376bSWei Song return count; 813792d376bSWei Song } 814792d376bSWei Song 815792d376bSWei Song static ssize_t 816792d376bSWei Song show_pwm(struct device *dev, struct device_attribute *attr, char *buf) 817792d376bSWei Song { 8181bb3450cSJean Delvare struct w83795_data *data; 819792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 820792d376bSWei Song to_sensor_dev_attr_2(attr); 821792d376bSWei Song int nr = sensor_attr->nr; 822792d376bSWei Song int index = sensor_attr->index; 82301879a85SJean Delvare unsigned int val; 824792d376bSWei Song 8251bb3450cSJean Delvare data = nr == PWM_OUTPUT ? w83795_update_device(dev) 8261bb3450cSJean Delvare : w83795_update_pwm_config(dev); 8271bb3450cSJean Delvare 828792d376bSWei Song switch (nr) { 829792d376bSWei Song case PWM_STOP_TIME: 830792d376bSWei Song val = time_from_reg(data->pwm[index][nr]); 831792d376bSWei Song break; 83201879a85SJean Delvare case PWM_FREQ: 83301879a85SJean Delvare val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); 834792d376bSWei Song break; 835792d376bSWei Song default: 836792d376bSWei Song val = data->pwm[index][nr]; 837792d376bSWei Song break; 838792d376bSWei Song } 839792d376bSWei Song 840792d376bSWei Song return sprintf(buf, "%u\n", val); 841792d376bSWei Song } 842792d376bSWei Song 843792d376bSWei Song static ssize_t 844792d376bSWei Song store_pwm(struct device *dev, struct device_attribute *attr, 845792d376bSWei Song const char *buf, size_t count) 846792d376bSWei Song { 847792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 848792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 849792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 850792d376bSWei Song to_sensor_dev_attr_2(attr); 851792d376bSWei Song int nr = sensor_attr->nr; 852792d376bSWei Song int index = sensor_attr->index; 853792d376bSWei Song unsigned long val; 854792d376bSWei Song 855792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 856792d376bSWei Song return -EINVAL; 857792d376bSWei Song 858792d376bSWei Song mutex_lock(&data->update_lock); 859792d376bSWei Song switch (nr) { 860792d376bSWei Song case PWM_STOP_TIME: 861792d376bSWei Song val = time_to_reg(val); 862792d376bSWei Song break; 86301879a85SJean Delvare case PWM_FREQ: 86401879a85SJean Delvare val = pwm_freq_to_reg(val, data->clkin); 865792d376bSWei Song break; 866792d376bSWei Song default: 867792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 868792d376bSWei Song break; 869792d376bSWei Song } 870792d376bSWei Song w83795_write(client, W83795_REG_PWM(index, nr), val); 87101879a85SJean Delvare data->pwm[index][nr] = val; 872792d376bSWei Song mutex_unlock(&data->update_lock); 873792d376bSWei Song return count; 874792d376bSWei Song } 875792d376bSWei Song 876792d376bSWei Song static ssize_t 877792d376bSWei Song show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 878792d376bSWei Song { 879792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 880792d376bSWei Song to_sensor_dev_attr_2(attr); 8811bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 882792d376bSWei Song int index = sensor_attr->index; 883792d376bSWei Song u8 tmp; 884792d376bSWei Song 885ae51cd9bSJean Delvare /* Speed cruise mode */ 886ae51cd9bSJean Delvare if (data->pwm_fcms[0] & (1 << index)) { 887792d376bSWei Song tmp = 2; 888792d376bSWei Song goto out; 889792d376bSWei Song } 890ae51cd9bSJean Delvare /* Thermal cruise or SmartFan IV mode */ 891792d376bSWei Song for (tmp = 0; tmp < 6; tmp++) { 892792d376bSWei Song if (data->pwm_tfmr[tmp] & (1 << index)) { 893792d376bSWei Song tmp = 3; 894792d376bSWei Song goto out; 895792d376bSWei Song } 896792d376bSWei Song } 897ae51cd9bSJean Delvare /* Manual mode */ 898792d376bSWei Song tmp = 1; 899792d376bSWei Song 900792d376bSWei Song out: 901792d376bSWei Song return sprintf(buf, "%u\n", tmp); 902792d376bSWei Song } 903792d376bSWei Song 904792d376bSWei Song static ssize_t 905792d376bSWei Song store_pwm_enable(struct device *dev, struct device_attribute *attr, 906792d376bSWei Song const char *buf, size_t count) 907792d376bSWei Song { 908792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 9091bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 910792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 911792d376bSWei Song to_sensor_dev_attr_2(attr); 912792d376bSWei Song int index = sensor_attr->index; 913792d376bSWei Song unsigned long val; 914792d376bSWei Song int i; 915792d376bSWei Song 916792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 917792d376bSWei Song return -EINVAL; 918ae51cd9bSJean Delvare if (val < 1 || val > 2) 919792d376bSWei Song return -EINVAL; 920792d376bSWei Song 921792d376bSWei Song mutex_lock(&data->update_lock); 922792d376bSWei Song switch (val) { 923792d376bSWei Song case 1: 924ae51cd9bSJean Delvare /* Clear speed cruise mode bits */ 925792d376bSWei Song data->pwm_fcms[0] &= ~(1 << index); 926792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 927ae51cd9bSJean Delvare /* Clear thermal cruise mode bits */ 928792d376bSWei Song for (i = 0; i < 6; i++) { 929792d376bSWei Song data->pwm_tfmr[i] &= ~(1 << index); 930792d376bSWei Song w83795_write(client, W83795_REG_TFMR(i), 931792d376bSWei Song data->pwm_tfmr[i]); 932792d376bSWei Song } 933792d376bSWei Song break; 934792d376bSWei Song case 2: 935792d376bSWei Song data->pwm_fcms[0] |= (1 << index); 936792d376bSWei Song w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 937792d376bSWei Song break; 938792d376bSWei Song } 939792d376bSWei Song mutex_unlock(&data->update_lock); 940792d376bSWei Song return count; 941792d376bSWei Song } 942792d376bSWei Song 943792d376bSWei Song static ssize_t 944d5ab845aSJean Delvare show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) 945d5ab845aSJean Delvare { 946d5ab845aSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 947d5ab845aSJean Delvare int index = to_sensor_dev_attr_2(attr)->index; 948d5ab845aSJean Delvare unsigned int mode; 949d5ab845aSJean Delvare 950d5ab845aSJean Delvare if (data->pwm_fomc & (1 << index)) 951d5ab845aSJean Delvare mode = 0; /* DC */ 952d5ab845aSJean Delvare else 953d5ab845aSJean Delvare mode = 1; /* PWM */ 954d5ab845aSJean Delvare 955d5ab845aSJean Delvare return sprintf(buf, "%u\n", mode); 956d5ab845aSJean Delvare } 957d5ab845aSJean Delvare 958edff2f8dSJean Delvare /* 959edff2f8dSJean Delvare * Check whether a given temperature source can ever be useful. 960edff2f8dSJean Delvare * Returns the number of selectable temperature channels which are 961edff2f8dSJean Delvare * enabled. 962edff2f8dSJean Delvare */ 963edff2f8dSJean Delvare static int w83795_tss_useful(const struct w83795_data *data, int tsrc) 964edff2f8dSJean Delvare { 965edff2f8dSJean Delvare int useful = 0, i; 966edff2f8dSJean Delvare 967edff2f8dSJean Delvare for (i = 0; i < 4; i++) { 968edff2f8dSJean Delvare if (tss_map[i][tsrc] == TSS_MAP_RESERVED) 969edff2f8dSJean Delvare continue; 970edff2f8dSJean Delvare if (tss_map[i][tsrc] < 6) /* Analog */ 971edff2f8dSJean Delvare useful += (data->has_temp >> tss_map[i][tsrc]) & 1; 972edff2f8dSJean Delvare else /* Digital */ 973edff2f8dSJean Delvare useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1; 974edff2f8dSJean Delvare } 975edff2f8dSJean Delvare 976edff2f8dSJean Delvare return useful; 977edff2f8dSJean Delvare } 978edff2f8dSJean Delvare 979d5ab845aSJean Delvare static ssize_t 980792d376bSWei Song show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 981792d376bSWei Song { 982792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 983792d376bSWei Song to_sensor_dev_attr_2(attr); 9841bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 985792d376bSWei Song int index = sensor_attr->index; 9862a2d27daSJean Delvare u8 tmp = data->temp_src[index / 2]; 987792d376bSWei Song 9887eb8d508SJean Delvare if (index & 1) 9892a2d27daSJean Delvare tmp >>= 4; /* Pick high nibble */ 990792d376bSWei Song else 9912a2d27daSJean Delvare tmp &= 0x0f; /* Pick low nibble */ 992792d376bSWei Song 9932a2d27daSJean Delvare /* Look-up the actual temperature channel number */ 9942a2d27daSJean Delvare if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED) 9952a2d27daSJean Delvare return -EINVAL; /* Shouldn't happen */ 9962a2d27daSJean Delvare 9972a2d27daSJean Delvare return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1); 998792d376bSWei Song } 999792d376bSWei Song 1000792d376bSWei Song static ssize_t 1001792d376bSWei Song store_temp_src(struct device *dev, struct device_attribute *attr, 1002792d376bSWei Song const char *buf, size_t count) 1003792d376bSWei Song { 1004792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 10051bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1006792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1007792d376bSWei Song to_sensor_dev_attr_2(attr); 1008792d376bSWei Song int index = sensor_attr->index; 10092a2d27daSJean Delvare int tmp; 10102a2d27daSJean Delvare unsigned long channel; 1011792d376bSWei Song u8 val = index / 2; 1012792d376bSWei Song 10132a2d27daSJean Delvare if (strict_strtoul(buf, 10, &channel) < 0 || 10142a2d27daSJean Delvare channel < 1 || channel > 14) 1015792d376bSWei Song return -EINVAL; 10162a2d27daSJean Delvare 10172a2d27daSJean Delvare /* Check if request can be fulfilled */ 10182a2d27daSJean Delvare for (tmp = 0; tmp < 4; tmp++) { 10192a2d27daSJean Delvare if (tss_map[tmp][index] == channel - 1) 10202a2d27daSJean Delvare break; 10212a2d27daSJean Delvare } 10222a2d27daSJean Delvare if (tmp == 4) /* No match */ 10232a2d27daSJean Delvare return -EINVAL; 1024792d376bSWei Song 1025792d376bSWei Song mutex_lock(&data->update_lock); 10267eb8d508SJean Delvare if (index & 1) { 1027792d376bSWei Song tmp <<= 4; 1028792d376bSWei Song data->temp_src[val] &= 0x0f; 1029792d376bSWei Song } else { 1030792d376bSWei Song data->temp_src[val] &= 0xf0; 1031792d376bSWei Song } 1032792d376bSWei Song data->temp_src[val] |= tmp; 1033792d376bSWei Song w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 1034792d376bSWei Song mutex_unlock(&data->update_lock); 1035792d376bSWei Song 1036792d376bSWei Song return count; 1037792d376bSWei Song } 1038792d376bSWei Song 1039792d376bSWei Song #define TEMP_PWM_ENABLE 0 1040792d376bSWei Song #define TEMP_PWM_FAN_MAP 1 1041792d376bSWei Song static ssize_t 1042792d376bSWei Song show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 1043792d376bSWei Song char *buf) 1044792d376bSWei Song { 10451bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1046792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1047792d376bSWei Song to_sensor_dev_attr_2(attr); 1048792d376bSWei Song int nr = sensor_attr->nr; 1049792d376bSWei Song int index = sensor_attr->index; 1050792d376bSWei Song u8 tmp = 0xff; 1051792d376bSWei Song 1052792d376bSWei Song switch (nr) { 1053792d376bSWei Song case TEMP_PWM_ENABLE: 1054792d376bSWei Song tmp = (data->pwm_fcms[1] >> index) & 1; 1055792d376bSWei Song if (tmp) 1056792d376bSWei Song tmp = 4; 1057792d376bSWei Song else 1058792d376bSWei Song tmp = 3; 1059792d376bSWei Song break; 1060792d376bSWei Song case TEMP_PWM_FAN_MAP: 1061792d376bSWei Song tmp = data->pwm_tfmr[index]; 1062792d376bSWei Song break; 1063792d376bSWei Song } 1064792d376bSWei Song 1065792d376bSWei Song return sprintf(buf, "%u\n", tmp); 1066792d376bSWei Song } 1067792d376bSWei Song 1068792d376bSWei Song static ssize_t 1069792d376bSWei Song store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 1070792d376bSWei Song const char *buf, size_t count) 1071792d376bSWei Song { 1072792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 10731bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1074792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1075792d376bSWei Song to_sensor_dev_attr_2(attr); 1076792d376bSWei Song int nr = sensor_attr->nr; 1077792d376bSWei Song int index = sensor_attr->index; 1078792d376bSWei Song unsigned long tmp; 1079792d376bSWei Song 1080792d376bSWei Song if (strict_strtoul(buf, 10, &tmp) < 0) 1081792d376bSWei Song return -EINVAL; 1082792d376bSWei Song 1083792d376bSWei Song switch (nr) { 1084792d376bSWei Song case TEMP_PWM_ENABLE: 1085eb02755aSJean Delvare if (tmp != 3 && tmp != 4) 1086792d376bSWei Song return -EINVAL; 1087792d376bSWei Song tmp -= 3; 1088792d376bSWei Song mutex_lock(&data->update_lock); 1089792d376bSWei Song data->pwm_fcms[1] &= ~(1 << index); 1090792d376bSWei Song data->pwm_fcms[1] |= tmp << index; 1091792d376bSWei Song w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 1092792d376bSWei Song mutex_unlock(&data->update_lock); 1093792d376bSWei Song break; 1094792d376bSWei Song case TEMP_PWM_FAN_MAP: 1095792d376bSWei Song mutex_lock(&data->update_lock); 1096792d376bSWei Song tmp = SENSORS_LIMIT(tmp, 0, 0xff); 1097792d376bSWei Song w83795_write(client, W83795_REG_TFMR(index), tmp); 1098792d376bSWei Song data->pwm_tfmr[index] = tmp; 1099792d376bSWei Song mutex_unlock(&data->update_lock); 1100792d376bSWei Song break; 1101792d376bSWei Song } 1102792d376bSWei Song return count; 1103792d376bSWei Song } 1104792d376bSWei Song 1105792d376bSWei Song #define FANIN_TARGET 0 1106792d376bSWei Song #define FANIN_TOL 1 1107792d376bSWei Song static ssize_t 1108792d376bSWei Song show_fanin(struct device *dev, struct device_attribute *attr, char *buf) 1109792d376bSWei Song { 11101bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1111792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1112792d376bSWei Song to_sensor_dev_attr_2(attr); 1113792d376bSWei Song int nr = sensor_attr->nr; 1114792d376bSWei Song int index = sensor_attr->index; 1115792d376bSWei Song u16 tmp = 0; 1116792d376bSWei Song 1117792d376bSWei Song switch (nr) { 1118792d376bSWei Song case FANIN_TARGET: 1119792d376bSWei Song tmp = fan_from_reg(data->target_speed[index]); 1120792d376bSWei Song break; 1121792d376bSWei Song case FANIN_TOL: 1122792d376bSWei Song tmp = data->tol_speed; 1123792d376bSWei Song break; 1124792d376bSWei Song } 1125792d376bSWei Song 1126792d376bSWei Song return sprintf(buf, "%u\n", tmp); 1127792d376bSWei Song } 1128792d376bSWei Song 1129792d376bSWei Song static ssize_t 1130792d376bSWei Song store_fanin(struct device *dev, struct device_attribute *attr, 1131792d376bSWei Song const char *buf, size_t count) 1132792d376bSWei Song { 1133792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1134792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1135792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1136792d376bSWei Song to_sensor_dev_attr_2(attr); 1137792d376bSWei Song int nr = sensor_attr->nr; 1138792d376bSWei Song int index = sensor_attr->index; 1139792d376bSWei Song unsigned long val; 1140792d376bSWei Song 1141792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1142792d376bSWei Song return -EINVAL; 1143792d376bSWei Song 1144792d376bSWei Song mutex_lock(&data->update_lock); 1145792d376bSWei Song switch (nr) { 1146792d376bSWei Song case FANIN_TARGET: 1147792d376bSWei Song val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); 1148eb02755aSJean Delvare w83795_write(client, W83795_REG_FTSH(index), val >> 4); 1149792d376bSWei Song w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 1150792d376bSWei Song data->target_speed[index] = val; 1151792d376bSWei Song break; 1152792d376bSWei Song case FANIN_TOL: 1153792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3f); 1154792d376bSWei Song w83795_write(client, W83795_REG_TFTS, val); 1155792d376bSWei Song data->tol_speed = val; 1156792d376bSWei Song break; 1157792d376bSWei Song } 1158792d376bSWei Song mutex_unlock(&data->update_lock); 1159792d376bSWei Song 1160792d376bSWei Song return count; 1161792d376bSWei Song } 1162792d376bSWei Song 1163792d376bSWei Song 1164792d376bSWei Song static ssize_t 1165792d376bSWei Song show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1166792d376bSWei Song { 11671bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 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 long tmp = temp_from_reg(data->pwm_temp[index][nr]); 1173792d376bSWei Song 1174792d376bSWei Song return sprintf(buf, "%ld\n", tmp); 1175792d376bSWei Song } 1176792d376bSWei Song 1177792d376bSWei Song static ssize_t 1178792d376bSWei Song store_temp_pwm(struct device *dev, struct device_attribute *attr, 1179792d376bSWei Song const char *buf, size_t count) 1180792d376bSWei Song { 1181792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1182792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1183792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1184792d376bSWei Song to_sensor_dev_attr_2(attr); 1185792d376bSWei Song int nr = sensor_attr->nr; 1186792d376bSWei Song int index = sensor_attr->index; 1187792d376bSWei Song unsigned long val; 1188792d376bSWei Song u8 tmp; 1189792d376bSWei Song 1190792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1191792d376bSWei Song return -EINVAL; 1192792d376bSWei Song val /= 1000; 1193792d376bSWei Song 1194792d376bSWei Song mutex_lock(&data->update_lock); 1195792d376bSWei Song switch (nr) { 1196792d376bSWei Song case TEMP_PWM_TTTI: 1197792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1198792d376bSWei Song w83795_write(client, W83795_REG_TTTI(index), val); 1199792d376bSWei Song break; 1200792d376bSWei Song case TEMP_PWM_CTFS: 1201792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x7f); 1202792d376bSWei Song w83795_write(client, W83795_REG_CTFS(index), val); 1203792d376bSWei Song break; 1204792d376bSWei Song case TEMP_PWM_HCT: 1205792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1206792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1207792d376bSWei Song tmp &= 0x0f; 1208792d376bSWei Song tmp |= (val << 4) & 0xf0; 1209792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1210792d376bSWei Song break; 1211792d376bSWei Song case TEMP_PWM_HOT: 1212792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x0f); 1213792d376bSWei Song tmp = w83795_read(client, W83795_REG_HT(index)); 1214792d376bSWei Song tmp &= 0xf0; 1215792d376bSWei Song tmp |= val & 0x0f; 1216792d376bSWei Song w83795_write(client, W83795_REG_HT(index), tmp); 1217792d376bSWei Song break; 1218792d376bSWei Song } 1219792d376bSWei Song data->pwm_temp[index][nr] = val; 1220792d376bSWei Song mutex_unlock(&data->update_lock); 1221792d376bSWei Song 1222792d376bSWei Song return count; 1223792d376bSWei Song } 1224792d376bSWei Song 1225792d376bSWei Song static ssize_t 1226792d376bSWei Song show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 1227792d376bSWei Song { 12281bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1229792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1230792d376bSWei Song to_sensor_dev_attr_2(attr); 1231792d376bSWei Song int nr = sensor_attr->nr; 1232792d376bSWei Song int index = sensor_attr->index; 1233792d376bSWei Song 1234792d376bSWei Song return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 1235792d376bSWei Song } 1236792d376bSWei Song 1237792d376bSWei Song static ssize_t 1238792d376bSWei Song store_sf4_pwm(struct device *dev, struct device_attribute *attr, 1239792d376bSWei Song const char *buf, size_t count) 1240792d376bSWei Song { 1241792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1242792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1243792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1244792d376bSWei Song to_sensor_dev_attr_2(attr); 1245792d376bSWei Song int nr = sensor_attr->nr; 1246792d376bSWei Song int index = sensor_attr->index; 1247792d376bSWei Song unsigned long val; 1248792d376bSWei Song 1249792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1250792d376bSWei Song return -EINVAL; 1251792d376bSWei Song 1252792d376bSWei Song mutex_lock(&data->update_lock); 1253792d376bSWei Song w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 1254792d376bSWei Song data->sf4_reg[index][SF4_PWM][nr] = val; 1255792d376bSWei Song mutex_unlock(&data->update_lock); 1256792d376bSWei Song 1257792d376bSWei Song return count; 1258792d376bSWei Song } 1259792d376bSWei Song 1260792d376bSWei Song static ssize_t 1261792d376bSWei Song show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 1262792d376bSWei Song { 12631bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1264792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1265792d376bSWei Song to_sensor_dev_attr_2(attr); 1266792d376bSWei Song int nr = sensor_attr->nr; 1267792d376bSWei Song int index = sensor_attr->index; 1268792d376bSWei Song 1269792d376bSWei Song return sprintf(buf, "%u\n", 1270792d376bSWei Song (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 1271792d376bSWei Song } 1272792d376bSWei Song 1273792d376bSWei Song static ssize_t 1274792d376bSWei Song store_sf4_temp(struct device *dev, struct device_attribute *attr, 1275792d376bSWei Song const char *buf, size_t count) 1276792d376bSWei Song { 1277792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1278792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1279792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1280792d376bSWei Song to_sensor_dev_attr_2(attr); 1281792d376bSWei Song int nr = sensor_attr->nr; 1282792d376bSWei Song int index = sensor_attr->index; 1283792d376bSWei Song unsigned long val; 1284792d376bSWei Song 1285792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1286792d376bSWei Song return -EINVAL; 1287792d376bSWei Song val /= 1000; 1288792d376bSWei Song 1289792d376bSWei Song mutex_lock(&data->update_lock); 1290792d376bSWei Song w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 1291792d376bSWei Song data->sf4_reg[index][SF4_TEMP][nr] = val; 1292792d376bSWei Song mutex_unlock(&data->update_lock); 1293792d376bSWei Song 1294792d376bSWei Song return count; 1295792d376bSWei Song } 1296792d376bSWei Song 1297792d376bSWei Song 1298792d376bSWei Song static ssize_t 1299792d376bSWei Song show_temp(struct device *dev, struct device_attribute *attr, char *buf) 1300792d376bSWei Song { 1301792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1302792d376bSWei Song to_sensor_dev_attr_2(attr); 1303792d376bSWei Song int nr = sensor_attr->nr; 1304792d376bSWei Song int index = sensor_attr->index; 1305792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1306dd127f5cSJean Delvare long temp = temp_from_reg(data->temp[index][nr]); 1307792d376bSWei Song 1308eb02755aSJean Delvare if (nr == TEMP_READ) 1309a654b9d4SJean Delvare temp += (data->temp_read_vrlsb[index] >> 6) * 250; 1310792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1311792d376bSWei Song } 1312792d376bSWei Song 1313792d376bSWei Song static ssize_t 1314792d376bSWei Song store_temp(struct device *dev, struct device_attribute *attr, 1315792d376bSWei Song const char *buf, size_t count) 1316792d376bSWei Song { 1317792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1318792d376bSWei Song to_sensor_dev_attr_2(attr); 1319792d376bSWei Song int nr = sensor_attr->nr; 1320792d376bSWei Song int index = sensor_attr->index; 1321792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1322792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1323792d376bSWei Song long tmp; 1324792d376bSWei Song 1325792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1326792d376bSWei Song return -EINVAL; 1327792d376bSWei Song 1328792d376bSWei Song mutex_lock(&data->update_lock); 1329792d376bSWei Song data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 1330792d376bSWei Song w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 1331792d376bSWei Song mutex_unlock(&data->update_lock); 1332792d376bSWei Song return count; 1333792d376bSWei Song } 1334792d376bSWei Song 1335792d376bSWei Song 1336792d376bSWei Song static ssize_t 1337792d376bSWei Song show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) 1338792d376bSWei Song { 133921fc9775SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 134039deb699SJean Delvare int tmp; 1341792d376bSWei Song 1342792d376bSWei Song if (data->enable_dts & 2) 1343792d376bSWei Song tmp = 5; 1344792d376bSWei Song else 1345792d376bSWei Song tmp = 6; 1346792d376bSWei Song 1347792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1348792d376bSWei Song } 1349792d376bSWei Song 1350792d376bSWei Song static ssize_t 1351792d376bSWei Song show_dts(struct device *dev, struct device_attribute *attr, char *buf) 1352792d376bSWei Song { 1353792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1354792d376bSWei Song to_sensor_dev_attr_2(attr); 1355792d376bSWei Song int index = sensor_attr->index; 1356792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1357dd127f5cSJean Delvare long temp = temp_from_reg(data->dts[index]); 1358792d376bSWei Song 1359a654b9d4SJean Delvare temp += (data->dts_read_vrlsb[index] >> 6) * 250; 1360792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1361792d376bSWei Song } 1362792d376bSWei Song 1363792d376bSWei Song static ssize_t 1364792d376bSWei Song show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 1365792d376bSWei Song { 1366792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1367792d376bSWei Song to_sensor_dev_attr_2(attr); 1368792d376bSWei Song int nr = sensor_attr->nr; 136921fc9775SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 1370dd127f5cSJean Delvare long temp = temp_from_reg(data->dts_ext[nr]); 1371792d376bSWei Song 1372792d376bSWei Song return sprintf(buf, "%ld\n", temp); 1373792d376bSWei Song } 1374792d376bSWei Song 1375792d376bSWei Song static ssize_t 1376792d376bSWei Song store_dts_ext(struct device *dev, struct device_attribute *attr, 1377792d376bSWei Song const char *buf, size_t count) 1378792d376bSWei Song { 1379792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1380792d376bSWei Song to_sensor_dev_attr_2(attr); 1381792d376bSWei Song int nr = sensor_attr->nr; 1382792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1383792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1384792d376bSWei Song long tmp; 1385792d376bSWei Song 1386792d376bSWei Song if (strict_strtol(buf, 10, &tmp) < 0) 1387792d376bSWei Song return -EINVAL; 1388792d376bSWei Song 1389792d376bSWei Song mutex_lock(&data->update_lock); 1390792d376bSWei Song data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 1391792d376bSWei Song w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 1392792d376bSWei Song mutex_unlock(&data->update_lock); 1393792d376bSWei Song return count; 1394792d376bSWei Song } 1395792d376bSWei Song 1396792d376bSWei Song 1397792d376bSWei Song static ssize_t 1398792d376bSWei Song show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 1399792d376bSWei Song { 140021fc9775SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 1401792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1402792d376bSWei Song to_sensor_dev_attr_2(attr); 1403792d376bSWei Song int index = sensor_attr->index; 140439deb699SJean Delvare int tmp; 1405792d376bSWei Song 140639deb699SJean Delvare if (data->temp_mode & (1 << index)) 140739deb699SJean Delvare tmp = 3; /* Thermal diode */ 1408792d376bSWei Song else 140939deb699SJean Delvare tmp = 4; /* Thermistor */ 1410792d376bSWei Song 1411792d376bSWei Song return sprintf(buf, "%d\n", tmp); 1412792d376bSWei Song } 1413792d376bSWei Song 141439deb699SJean Delvare /* Only for temp1-4 (temp5-6 can only be thermistor) */ 1415792d376bSWei Song static ssize_t 1416792d376bSWei Song store_temp_mode(struct device *dev, struct device_attribute *attr, 1417792d376bSWei Song const char *buf, size_t count) 1418792d376bSWei Song { 1419792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1420792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1421792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1422792d376bSWei Song to_sensor_dev_attr_2(attr); 1423792d376bSWei Song int index = sensor_attr->index; 142439deb699SJean Delvare int reg_shift; 1425792d376bSWei Song unsigned long val; 1426792d376bSWei Song u8 tmp; 1427792d376bSWei Song 1428792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1429792d376bSWei Song return -EINVAL; 1430792d376bSWei Song if ((val != 4) && (val != 3)) 1431792d376bSWei Song return -EINVAL; 1432792d376bSWei Song 1433792d376bSWei Song mutex_lock(&data->update_lock); 1434792d376bSWei Song if (val == 3) { 143539deb699SJean Delvare /* Thermal diode */ 143639deb699SJean Delvare val = 0x01; 1437792d376bSWei Song data->temp_mode |= 1 << index; 1438792d376bSWei Song } else if (val == 4) { 143939deb699SJean Delvare /* Thermistor */ 144039deb699SJean Delvare val = 0x03; 144139deb699SJean Delvare data->temp_mode &= ~(1 << index); 1442792d376bSWei Song } 1443792d376bSWei Song 144439deb699SJean Delvare reg_shift = 2 * index; 1445792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 144639deb699SJean Delvare tmp &= ~(0x03 << reg_shift); 144739deb699SJean Delvare tmp |= val << reg_shift; 1448792d376bSWei Song w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 1449792d376bSWei Song 1450792d376bSWei Song mutex_unlock(&data->update_lock); 1451792d376bSWei Song return count; 1452792d376bSWei Song } 1453792d376bSWei Song 1454792d376bSWei Song 1455792d376bSWei Song /* show/store VIN */ 1456792d376bSWei Song static ssize_t 1457792d376bSWei Song show_in(struct device *dev, struct device_attribute *attr, char *buf) 1458792d376bSWei Song { 1459792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1460792d376bSWei Song to_sensor_dev_attr_2(attr); 1461792d376bSWei Song int nr = sensor_attr->nr; 1462792d376bSWei Song int index = sensor_attr->index; 1463792d376bSWei Song struct w83795_data *data = w83795_update_device(dev); 1464792d376bSWei Song u16 val = data->in[index][nr]; 1465792d376bSWei Song u8 lsb_idx; 1466792d376bSWei Song 1467792d376bSWei Song switch (nr) { 1468792d376bSWei Song case IN_READ: 1469792d376bSWei Song /* calculate this value again by sensors as sensors3.conf */ 1470792d376bSWei Song if ((index >= 17) && 14716f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1472792d376bSWei Song val *= 8; 1473792d376bSWei Song break; 1474792d376bSWei Song case IN_MAX: 1475792d376bSWei Song case IN_LOW: 1476792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1477792d376bSWei Song val <<= 2; 1478792d376bSWei Song val |= (data->in_lsb[lsb_idx][nr] >> 14795d2cd958SJean Delvare IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03; 1480792d376bSWei Song if ((index >= 17) && 14816f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1482792d376bSWei Song val *= 8; 1483792d376bSWei Song break; 1484792d376bSWei Song } 1485792d376bSWei Song val = in_from_reg(index, val); 1486792d376bSWei Song 1487792d376bSWei Song return sprintf(buf, "%d\n", val); 1488792d376bSWei Song } 1489792d376bSWei Song 1490792d376bSWei Song static ssize_t 1491792d376bSWei Song store_in(struct device *dev, struct device_attribute *attr, 1492792d376bSWei Song const char *buf, size_t count) 1493792d376bSWei Song { 1494792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1495792d376bSWei Song to_sensor_dev_attr_2(attr); 1496792d376bSWei Song int nr = sensor_attr->nr; 1497792d376bSWei Song int index = sensor_attr->index; 1498792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1499792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1500792d376bSWei Song unsigned long val; 1501792d376bSWei Song u8 tmp; 1502792d376bSWei Song u8 lsb_idx; 1503792d376bSWei Song 1504792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1505792d376bSWei Song return -EINVAL; 1506792d376bSWei Song val = in_to_reg(index, val); 1507792d376bSWei Song 1508792d376bSWei Song if ((index >= 17) && 15096f9dfd85SJean Delvare !((data->has_gain >> (index - 17)) & 1)) 1510792d376bSWei Song val /= 8; 1511792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0x3FF); 1512792d376bSWei Song mutex_lock(&data->update_lock); 1513792d376bSWei Song 1514792d376bSWei Song lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 1515792d376bSWei Song tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 1516792d376bSWei Song tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 1517792d376bSWei Song tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 1518792d376bSWei Song w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 1519792d376bSWei Song data->in_lsb[lsb_idx][nr] = tmp; 1520792d376bSWei Song 1521792d376bSWei Song tmp = (val >> 2) & 0xff; 1522792d376bSWei Song w83795_write(client, W83795_REG_IN[index][nr], tmp); 1523792d376bSWei Song data->in[index][nr] = tmp; 1524792d376bSWei Song 1525792d376bSWei Song mutex_unlock(&data->update_lock); 1526792d376bSWei Song return count; 1527792d376bSWei Song } 1528792d376bSWei Song 1529792d376bSWei Song 153000030af2SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 1531792d376bSWei Song static ssize_t 1532792d376bSWei Song show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 1533792d376bSWei Song { 1534792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1535792d376bSWei Song to_sensor_dev_attr_2(attr); 1536792d376bSWei Song int nr = sensor_attr->nr; 15371bb3450cSJean Delvare struct w83795_data *data = w83795_update_pwm_config(dev); 1538792d376bSWei Song u16 val = data->setup_pwm[nr]; 1539792d376bSWei Song 1540792d376bSWei Song switch (nr) { 1541792d376bSWei Song case SETUP_PWM_UPTIME: 1542792d376bSWei Song case SETUP_PWM_DOWNTIME: 1543792d376bSWei Song val = time_from_reg(val); 1544792d376bSWei Song break; 1545792d376bSWei Song } 1546792d376bSWei Song 1547792d376bSWei Song return sprintf(buf, "%d\n", val); 1548792d376bSWei Song } 1549792d376bSWei Song 1550792d376bSWei Song static ssize_t 1551792d376bSWei Song store_sf_setup(struct device *dev, struct device_attribute *attr, 1552792d376bSWei Song const char *buf, size_t count) 1553792d376bSWei Song { 1554792d376bSWei Song struct sensor_device_attribute_2 *sensor_attr = 1555792d376bSWei Song to_sensor_dev_attr_2(attr); 1556792d376bSWei Song int nr = sensor_attr->nr; 1557792d376bSWei Song struct i2c_client *client = to_i2c_client(dev); 1558792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 1559792d376bSWei Song unsigned long val; 1560792d376bSWei Song 1561792d376bSWei Song if (strict_strtoul(buf, 10, &val) < 0) 1562792d376bSWei Song return -EINVAL; 1563792d376bSWei Song 1564792d376bSWei Song switch (nr) { 1565792d376bSWei Song case SETUP_PWM_DEFAULT: 1566792d376bSWei Song val = SENSORS_LIMIT(val, 0, 0xff); 1567792d376bSWei Song break; 1568792d376bSWei Song case SETUP_PWM_UPTIME: 1569792d376bSWei Song case SETUP_PWM_DOWNTIME: 1570792d376bSWei Song val = time_to_reg(val); 1571792d376bSWei Song if (val == 0) 1572792d376bSWei Song return -EINVAL; 1573792d376bSWei Song break; 1574792d376bSWei Song } 1575792d376bSWei Song 1576792d376bSWei Song mutex_lock(&data->update_lock); 1577792d376bSWei Song data->setup_pwm[nr] = val; 1578792d376bSWei Song w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 1579792d376bSWei Song mutex_unlock(&data->update_lock); 1580792d376bSWei Song return count; 1581792d376bSWei Song } 158200030af2SJean Delvare #endif 1583792d376bSWei Song 1584792d376bSWei Song 1585792d376bSWei Song #define NOT_USED -1 1586792d376bSWei Song 15870e256018SJean Delvare /* Don't change the attribute order, _max and _min are accessed by index 15880e256018SJean Delvare * somewhere else in the code */ 158987df0dadSJean Delvare #define SENSOR_ATTR_IN(index) { \ 1590792d376bSWei Song SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 1591792d376bSWei Song IN_READ, index), \ 1592792d376bSWei Song SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 1593792d376bSWei Song store_in, IN_MAX, index), \ 1594792d376bSWei Song SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 1595792d376bSWei Song store_in, IN_LOW, index), \ 1596792d376bSWei Song SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 1597792d376bSWei Song NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 1598792d376bSWei Song SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 1599792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 160087df0dadSJean Delvare index + ((index > 14) ? 1 : 0)) } 1601792d376bSWei Song 160287df0dadSJean Delvare #define SENSOR_ATTR_FAN(index) { \ 1603792d376bSWei Song SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 1604792d376bSWei Song NULL, FAN_INPUT, index - 1), \ 1605792d376bSWei Song SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 1606792d376bSWei Song show_fan, store_fan_min, FAN_MIN, index - 1), \ 1607792d376bSWei Song SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 1608792d376bSWei Song NULL, ALARM_STATUS, index + 31), \ 1609792d376bSWei Song SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 161087df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 1611792d376bSWei Song 1612b5f6a90aSJean Delvare #define SENSOR_ATTR_PWM(index) { \ 1613792d376bSWei Song SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 1614792d376bSWei Song store_pwm, PWM_OUTPUT, index - 1), \ 1615792d376bSWei Song SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 1616792d376bSWei Song show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 1617792d376bSWei Song SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 1618792d376bSWei Song show_pwm, store_pwm, PWM_START, index - 1), \ 1619792d376bSWei Song SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 1620792d376bSWei Song show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 162101879a85SJean Delvare SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ 162201879a85SJean Delvare show_pwm, store_pwm, PWM_FREQ, index - 1), \ 1623792d376bSWei Song SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 1624b2cc528eSJean Delvare show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 1625d5ab845aSJean Delvare SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO, \ 1626d5ab845aSJean Delvare show_pwm_mode, NULL, NOT_USED, index - 1), \ 1627b2cc528eSJean Delvare SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 1628b2cc528eSJean Delvare show_fanin, store_fanin, FANIN_TARGET, index - 1) } 1629792d376bSWei Song 163087df0dadSJean Delvare #define SENSOR_ATTR_DTS(index) { \ 1631792d376bSWei Song SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 1632792d376bSWei Song show_dts_mode, NULL, NOT_USED, index - 7), \ 1633792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 1634792d376bSWei Song NULL, NOT_USED, index - 7), \ 1635a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ 1636792d376bSWei Song store_dts_ext, DTS_CRIT, NOT_USED), \ 1637a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1638792d376bSWei Song show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 1639a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 1640792d376bSWei Song store_dts_ext, DTS_WARN, NOT_USED), \ 1641a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1642792d376bSWei Song show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 1643792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1644792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 1645792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 164687df0dadSJean Delvare show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 1647792d376bSWei Song 164887df0dadSJean Delvare #define SENSOR_ATTR_TEMP(index) { \ 164939deb699SJean Delvare SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \ 1650792d376bSWei Song show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 1651792d376bSWei Song SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 1652792d376bSWei Song NULL, TEMP_READ, index - 1), \ 1653a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ 1654792d376bSWei Song store_temp, TEMP_CRIT, index - 1), \ 1655a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 1656792d376bSWei Song show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 1657a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 1658792d376bSWei Song store_temp, TEMP_WARN, index - 1), \ 1659a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 1660792d376bSWei Song show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 1661792d376bSWei Song SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 1662792d376bSWei Song show_alarm_beep, NULL, ALARM_STATUS, \ 1663792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1664792d376bSWei Song SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 1665792d376bSWei Song show_alarm_beep, store_beep, BEEP_ENABLE, \ 1666792d376bSWei Song index + (index > 4 ? 11 : 17)), \ 1667792d376bSWei Song SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 1668792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1669792d376bSWei Song TEMP_PWM_ENABLE, index - 1), \ 1670792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 1671792d376bSWei Song show_temp_pwm_enable, store_temp_pwm_enable, \ 1672792d376bSWei Song TEMP_PWM_FAN_MAP, index - 1), \ 1673792d376bSWei Song SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 1674792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 1675a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ 1676792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 1677a0ce402fSJean Delvare SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ 1678792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 1679792d376bSWei Song SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 1680792d376bSWei Song show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 1681792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 1682792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 1683792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 1684792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 1685792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 1686792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 1687792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 1688792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 1689792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 1690792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 1691792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 1692792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 1693792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 1694792d376bSWei Song show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 1695792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 1696792d376bSWei Song show_sf4_temp, store_sf4_temp, 0, index - 1), \ 1697792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 1698792d376bSWei Song show_sf4_temp, store_sf4_temp, 1, index - 1), \ 1699792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 1700792d376bSWei Song show_sf4_temp, store_sf4_temp, 2, index - 1), \ 1701792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 1702792d376bSWei Song show_sf4_temp, store_sf4_temp, 3, index - 1), \ 1703792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 1704792d376bSWei Song show_sf4_temp, store_sf4_temp, 4, index - 1), \ 1705792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 1706792d376bSWei Song show_sf4_temp, store_sf4_temp, 5, index - 1), \ 1707792d376bSWei Song SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 170887df0dadSJean Delvare show_sf4_temp, store_sf4_temp, 6, index - 1) } 1709792d376bSWei Song 1710792d376bSWei Song 171187df0dadSJean Delvare static struct sensor_device_attribute_2 w83795_in[][5] = { 1712792d376bSWei Song SENSOR_ATTR_IN(0), 1713792d376bSWei Song SENSOR_ATTR_IN(1), 1714792d376bSWei Song SENSOR_ATTR_IN(2), 1715792d376bSWei Song SENSOR_ATTR_IN(3), 1716792d376bSWei Song SENSOR_ATTR_IN(4), 1717792d376bSWei Song SENSOR_ATTR_IN(5), 1718792d376bSWei Song SENSOR_ATTR_IN(6), 1719792d376bSWei Song SENSOR_ATTR_IN(7), 1720792d376bSWei Song SENSOR_ATTR_IN(8), 1721792d376bSWei Song SENSOR_ATTR_IN(9), 1722792d376bSWei Song SENSOR_ATTR_IN(10), 1723792d376bSWei Song SENSOR_ATTR_IN(11), 1724792d376bSWei Song SENSOR_ATTR_IN(12), 1725792d376bSWei Song SENSOR_ATTR_IN(13), 1726792d376bSWei Song SENSOR_ATTR_IN(14), 1727792d376bSWei Song SENSOR_ATTR_IN(15), 1728792d376bSWei Song SENSOR_ATTR_IN(16), 1729792d376bSWei Song SENSOR_ATTR_IN(17), 1730792d376bSWei Song SENSOR_ATTR_IN(18), 1731792d376bSWei Song SENSOR_ATTR_IN(19), 1732792d376bSWei Song SENSOR_ATTR_IN(20), 1733792d376bSWei Song }; 1734792d376bSWei Song 173586ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_fan[][4] = { 1736792d376bSWei Song SENSOR_ATTR_FAN(1), 1737792d376bSWei Song SENSOR_ATTR_FAN(2), 1738792d376bSWei Song SENSOR_ATTR_FAN(3), 1739792d376bSWei Song SENSOR_ATTR_FAN(4), 1740792d376bSWei Song SENSOR_ATTR_FAN(5), 1741792d376bSWei Song SENSOR_ATTR_FAN(6), 1742792d376bSWei Song SENSOR_ATTR_FAN(7), 1743792d376bSWei Song SENSOR_ATTR_FAN(8), 1744792d376bSWei Song SENSOR_ATTR_FAN(9), 1745792d376bSWei Song SENSOR_ATTR_FAN(10), 1746792d376bSWei Song SENSOR_ATTR_FAN(11), 1747792d376bSWei Song SENSOR_ATTR_FAN(12), 1748792d376bSWei Song SENSOR_ATTR_FAN(13), 1749792d376bSWei Song SENSOR_ATTR_FAN(14), 1750792d376bSWei Song }; 1751792d376bSWei Song 1752edff2f8dSJean Delvare static const struct sensor_device_attribute_2 w83795_temp[][28] = { 1753792d376bSWei Song SENSOR_ATTR_TEMP(1), 1754792d376bSWei Song SENSOR_ATTR_TEMP(2), 1755792d376bSWei Song SENSOR_ATTR_TEMP(3), 1756792d376bSWei Song SENSOR_ATTR_TEMP(4), 1757792d376bSWei Song SENSOR_ATTR_TEMP(5), 1758792d376bSWei Song SENSOR_ATTR_TEMP(6), 1759792d376bSWei Song }; 1760792d376bSWei Song 176186ef4d2fSJean Delvare static const struct sensor_device_attribute_2 w83795_dts[][8] = { 1762792d376bSWei Song SENSOR_ATTR_DTS(7), 1763792d376bSWei Song SENSOR_ATTR_DTS(8), 1764792d376bSWei Song SENSOR_ATTR_DTS(9), 1765792d376bSWei Song SENSOR_ATTR_DTS(10), 1766792d376bSWei Song SENSOR_ATTR_DTS(11), 1767792d376bSWei Song SENSOR_ATTR_DTS(12), 1768792d376bSWei Song SENSOR_ATTR_DTS(13), 1769792d376bSWei Song SENSOR_ATTR_DTS(14), 1770792d376bSWei Song }; 1771792d376bSWei Song 1772d5ab845aSJean Delvare static const struct sensor_device_attribute_2 w83795_pwm[][8] = { 1773b5f6a90aSJean Delvare SENSOR_ATTR_PWM(1), 1774b5f6a90aSJean Delvare SENSOR_ATTR_PWM(2), 1775792d376bSWei Song SENSOR_ATTR_PWM(3), 1776792d376bSWei Song SENSOR_ATTR_PWM(4), 1777792d376bSWei Song SENSOR_ATTR_PWM(5), 1778792d376bSWei Song SENSOR_ATTR_PWM(6), 1779792d376bSWei Song SENSOR_ATTR_PWM(7), 1780792d376bSWei Song SENSOR_ATTR_PWM(8), 1781792d376bSWei Song }; 1782792d376bSWei Song 1783edff2f8dSJean Delvare static const struct sensor_device_attribute_2 w83795_tss[6] = { 1784edff2f8dSJean Delvare SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO, 1785edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 0), 1786edff2f8dSJean Delvare SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO, 1787edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 1), 1788edff2f8dSJean Delvare SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO, 1789edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 2), 1790edff2f8dSJean Delvare SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO, 1791edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 3), 1792edff2f8dSJean Delvare SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO, 1793edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 4), 1794edff2f8dSJean Delvare SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO, 1795edff2f8dSJean Delvare show_temp_src, store_temp_src, NOT_USED, 5), 1796edff2f8dSJean Delvare }; 1797edff2f8dSJean Delvare 179886ef4d2fSJean Delvare static const struct sensor_device_attribute_2 sda_single_files[] = { 179924377101SJean Delvare SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, 1800792d376bSWei Song store_chassis_clear, ALARM_STATUS, 46), 180124377101SJean Delvare SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep, 180224377101SJean Delvare store_beep, BEEP_ENABLE, 46), 180302728ffeSJean Delvare SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, 180402728ffeSJean Delvare store_beep, BEEP_ENABLE, 47), 180500030af2SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 1806792d376bSWei Song SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 1807792d376bSWei Song store_fanin, FANIN_TOL, NOT_USED), 1808792d376bSWei Song SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 1809792d376bSWei Song store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 1810792d376bSWei Song SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 1811792d376bSWei Song store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 1812792d376bSWei Song SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 1813792d376bSWei Song store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 181400030af2SJean Delvare #endif 1815792d376bSWei Song }; 1816792d376bSWei Song 1817792d376bSWei Song /* 1818792d376bSWei Song * Driver interface 1819792d376bSWei Song */ 1820792d376bSWei Song 1821792d376bSWei Song static void w83795_init_client(struct i2c_client *client) 1822792d376bSWei Song { 182301879a85SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 182401879a85SJean Delvare static const u16 clkin[4] = { /* in kHz */ 182501879a85SJean Delvare 14318, 24000, 33333, 48000 182601879a85SJean Delvare }; 182780646b95SJean Delvare u8 config; 182880646b95SJean Delvare 1829792d376bSWei Song if (reset) 1830792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 0x80); 1831792d376bSWei Song 183280646b95SJean Delvare /* Start monitoring if needed */ 183380646b95SJean Delvare config = w83795_read(client, W83795_REG_CONFIG); 183480646b95SJean Delvare if (!(config & W83795_REG_CONFIG_START)) { 183580646b95SJean Delvare dev_info(&client->dev, "Enabling monitoring operations\n"); 1836792d376bSWei Song w83795_write(client, W83795_REG_CONFIG, 183780646b95SJean Delvare config | W83795_REG_CONFIG_START); 183880646b95SJean Delvare } 183901879a85SJean Delvare 184001879a85SJean Delvare data->clkin = clkin[(config >> 3) & 0x3]; 184101879a85SJean Delvare dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); 1842792d376bSWei Song } 1843792d376bSWei Song 18442be381deSJean Delvare static int w83795_get_device_id(struct i2c_client *client) 18452be381deSJean Delvare { 18462be381deSJean Delvare int device_id; 18472be381deSJean Delvare 18482be381deSJean Delvare device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 18492be381deSJean Delvare 18502be381deSJean Delvare /* Special case for rev. A chips; can't be checked first because later 18512be381deSJean Delvare revisions emulate this for compatibility */ 18522be381deSJean Delvare if (device_id < 0 || (device_id & 0xf0) != 0x50) { 18532be381deSJean Delvare int alt_id; 18542be381deSJean Delvare 18552be381deSJean Delvare alt_id = i2c_smbus_read_byte_data(client, 18562be381deSJean Delvare W83795_REG_DEVICEID_A); 18572be381deSJean Delvare if (alt_id == 0x50) 18582be381deSJean Delvare device_id = alt_id; 18592be381deSJean Delvare } 18602be381deSJean Delvare 18612be381deSJean Delvare return device_id; 18622be381deSJean Delvare } 18632be381deSJean Delvare 1864792d376bSWei Song /* Return 0 if detection is successful, -ENODEV otherwise */ 1865792d376bSWei Song static int w83795_detect(struct i2c_client *client, 1866792d376bSWei Song struct i2c_board_info *info) 1867792d376bSWei Song { 18682be381deSJean Delvare int bank, vendor_id, device_id, expected, i2c_addr, config; 1869792d376bSWei Song struct i2c_adapter *adapter = client->adapter; 1870792d376bSWei Song unsigned short address = client->addr; 1871093d1a47SJean Delvare const char *chip_name; 1872792d376bSWei Song 1873792d376bSWei Song if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1874792d376bSWei Song return -ENODEV; 1875792d376bSWei Song bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 18762be381deSJean Delvare if (bank < 0 || (bank & 0x7c)) { 18772be381deSJean Delvare dev_dbg(&adapter->dev, 18782be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 18792be381deSJean Delvare address, "bank"); 18802be381deSJean Delvare return -ENODEV; 18812be381deSJean Delvare } 1882792d376bSWei Song 1883792d376bSWei Song /* Check Nuvoton vendor ID */ 18842be381deSJean Delvare vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 18852be381deSJean Delvare expected = bank & 0x80 ? 0x5c : 0xa3; 18862be381deSJean Delvare if (vendor_id != expected) { 18872be381deSJean Delvare dev_dbg(&adapter->dev, 18882be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 18892be381deSJean Delvare address, "vendor id"); 18902be381deSJean Delvare return -ENODEV; 18912be381deSJean Delvare } 18922be381deSJean Delvare 18932be381deSJean Delvare /* Check device ID */ 18942be381deSJean Delvare device_id = w83795_get_device_id(client) | 18952be381deSJean Delvare (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 18962be381deSJean Delvare if ((device_id >> 4) != 0x795) { 18972be381deSJean Delvare dev_dbg(&adapter->dev, 18982be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, check %s\n", 18992be381deSJean Delvare address, "device id\n"); 1900792d376bSWei Song return -ENODEV; 1901792d376bSWei Song } 1902792d376bSWei Song 1903792d376bSWei Song /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 1904792d376bSWei Song should match */ 19052be381deSJean Delvare if ((bank & 0x07) == 0) { 19062be381deSJean Delvare i2c_addr = i2c_smbus_read_byte_data(client, 19072be381deSJean Delvare W83795_REG_I2C_ADDR); 19082be381deSJean Delvare if ((i2c_addr & 0x7f) != address) { 19092be381deSJean Delvare dev_dbg(&adapter->dev, 19102be381deSJean Delvare "w83795: Detection failed at addr 0x%02hx, " 19112be381deSJean Delvare "check %s\n", address, "i2c addr"); 1912792d376bSWei Song return -ENODEV; 1913792d376bSWei Song } 1914792d376bSWei Song } 1915792d376bSWei Song 1916093d1a47SJean Delvare /* Check 795 chip type: 795G or 795ADG 1917093d1a47SJean Delvare Usually we don't write to chips during detection, but here we don't 1918093d1a47SJean Delvare quite have the choice; hopefully it's OK, we are about to return 1919093d1a47SJean Delvare success anyway */ 1920093d1a47SJean Delvare if ((bank & 0x07) != 0) 1921093d1a47SJean Delvare i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 1922093d1a47SJean Delvare bank & ~0x07); 19232be381deSJean Delvare config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 19242be381deSJean Delvare if (config & W83795_REG_CONFIG_CONFIG48) 1925093d1a47SJean Delvare chip_name = "w83795adg"; 19262be381deSJean Delvare else 1927093d1a47SJean Delvare chip_name = "w83795g"; 1928792d376bSWei Song 1929093d1a47SJean Delvare strlcpy(info->type, chip_name, I2C_NAME_SIZE); 19302be381deSJean Delvare dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 19312be381deSJean Delvare 'A' + (device_id & 0xf), address); 1932792d376bSWei Song 1933792d376bSWei Song return 0; 1934792d376bSWei Song } 1935792d376bSWei Song 19366f3dcde9SJean Delvare static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 19376f3dcde9SJean Delvare const struct device_attribute *)) 1938892514a6SJean Delvare { 1939892514a6SJean Delvare struct w83795_data *data = dev_get_drvdata(dev); 194087df0dadSJean Delvare int err, i, j; 1941892514a6SJean Delvare 1942892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 194387df0dadSJean Delvare if (!(data->has_in & (1 << i))) 1944892514a6SJean Delvare continue; 194587df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 194687df0dadSJean Delvare err = fn(dev, &w83795_in[i][j].dev_attr); 1947892514a6SJean Delvare if (err) 1948892514a6SJean Delvare return err; 1949892514a6SJean Delvare } 195087df0dadSJean Delvare } 1951892514a6SJean Delvare 1952892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 195387df0dadSJean Delvare if (!(data->has_fan & (1 << i))) 1954892514a6SJean Delvare continue; 195587df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 195687df0dadSJean Delvare err = fn(dev, &w83795_fan[i][j].dev_attr); 1957892514a6SJean Delvare if (err) 1958892514a6SJean Delvare return err; 1959892514a6SJean Delvare } 196087df0dadSJean Delvare } 1961892514a6SJean Delvare 1962edff2f8dSJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) { 1963edff2f8dSJean Delvare j = w83795_tss_useful(data, i); 1964edff2f8dSJean Delvare if (!j) 1965edff2f8dSJean Delvare continue; 1966edff2f8dSJean Delvare err = fn(dev, &w83795_tss[i].dev_attr); 1967edff2f8dSJean Delvare if (err) 1968edff2f8dSJean Delvare return err; 1969edff2f8dSJean Delvare } 1970edff2f8dSJean Delvare 1971892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 19726f3dcde9SJean Delvare err = fn(dev, &sda_single_files[i].dev_attr); 1973892514a6SJean Delvare if (err) 1974892514a6SJean Delvare return err; 1975892514a6SJean Delvare } 1976892514a6SJean Delvare 197700030af2SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 1978b5f6a90aSJean Delvare for (i = 0; i < data->has_pwm; i++) { 1979b5f6a90aSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { 1980b5f6a90aSJean Delvare err = fn(dev, &w83795_pwm[i][j].dev_attr); 1981892514a6SJean Delvare if (err) 1982892514a6SJean Delvare return err; 1983892514a6SJean Delvare } 1984892514a6SJean Delvare } 198500030af2SJean Delvare #endif 1986892514a6SJean Delvare 1987892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 198887df0dadSJean Delvare if (!(data->has_temp & (1 << i))) 1989892514a6SJean Delvare continue; 199000030af2SJean Delvare #ifdef CONFIG_SENSORS_W83795_FANCTRL 199187df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { 199200030af2SJean Delvare #else 199300030af2SJean Delvare for (j = 0; j < 8; j++) { 199400030af2SJean Delvare #endif 199587df0dadSJean Delvare err = fn(dev, &w83795_temp[i][j].dev_attr); 1996892514a6SJean Delvare if (err) 1997892514a6SJean Delvare return err; 1998892514a6SJean Delvare } 199987df0dadSJean Delvare } 2000892514a6SJean Delvare 2001eb02755aSJean Delvare if (data->enable_dts) { 2002892514a6SJean Delvare for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 200387df0dadSJean Delvare if (!(data->has_dts & (1 << i))) 2004892514a6SJean Delvare continue; 200587df0dadSJean Delvare for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 200687df0dadSJean Delvare err = fn(dev, &w83795_dts[i][j].dev_attr); 2007892514a6SJean Delvare if (err) 2008892514a6SJean Delvare return err; 2009892514a6SJean Delvare } 2010892514a6SJean Delvare } 201187df0dadSJean Delvare } 2012892514a6SJean Delvare 2013892514a6SJean Delvare return 0; 2014892514a6SJean Delvare } 2015892514a6SJean Delvare 20166f3dcde9SJean Delvare /* We need a wrapper that fits in w83795_handle_files */ 20176f3dcde9SJean Delvare static int device_remove_file_wrapper(struct device *dev, 20186f3dcde9SJean Delvare const struct device_attribute *attr) 20192fa09878SJean Delvare { 20206f3dcde9SJean Delvare device_remove_file(dev, attr); 20216f3dcde9SJean Delvare return 0; 20222fa09878SJean Delvare } 20232fa09878SJean Delvare 20240e256018SJean Delvare static void w83795_check_dynamic_in_limits(struct i2c_client *client) 20250e256018SJean Delvare { 20260e256018SJean Delvare struct w83795_data *data = i2c_get_clientdata(client); 20270e256018SJean Delvare u8 vid_ctl; 20280e256018SJean Delvare int i, err_max, err_min; 20290e256018SJean Delvare 20300e256018SJean Delvare vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); 20310e256018SJean Delvare 20320e256018SJean Delvare /* Return immediately if VRM isn't configured */ 20330e256018SJean Delvare if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) 20340e256018SJean Delvare return; 20350e256018SJean Delvare 20360e256018SJean Delvare data->has_dyn_in = (vid_ctl >> 3) & 0x07; 20370e256018SJean Delvare for (i = 0; i < 2; i++) { 20380e256018SJean Delvare if (!(data->has_dyn_in & (1 << i))) 20390e256018SJean Delvare continue; 20400e256018SJean Delvare 20410e256018SJean Delvare /* Voltage limits in dynamic mode, switch to read-only */ 20420e256018SJean Delvare err_max = sysfs_chmod_file(&client->dev.kobj, 20430e256018SJean Delvare &w83795_in[i][2].dev_attr.attr, 20440e256018SJean Delvare S_IRUGO); 20450e256018SJean Delvare err_min = sysfs_chmod_file(&client->dev.kobj, 20460e256018SJean Delvare &w83795_in[i][3].dev_attr.attr, 20470e256018SJean Delvare S_IRUGO); 20480e256018SJean Delvare if (err_max || err_min) 20490e256018SJean Delvare dev_warn(&client->dev, "Failed to set in%d limits " 20500e256018SJean Delvare "read-only (%d, %d)\n", i, err_max, err_min); 20510e256018SJean Delvare else 20520e256018SJean Delvare dev_info(&client->dev, "in%d limits set dynamically " 20530e256018SJean Delvare "from VID\n", i); 20540e256018SJean Delvare } 20550e256018SJean Delvare } 20560e256018SJean Delvare 205771caf46fSJean Delvare /* Check pins that can be used for either temperature or voltage monitoring */ 205871caf46fSJean Delvare static void w83795_apply_temp_config(struct w83795_data *data, u8 config, 205971caf46fSJean Delvare int temp_chan, int in_chan) 206071caf46fSJean Delvare { 206171caf46fSJean Delvare /* config is a 2-bit value */ 206271caf46fSJean Delvare switch (config) { 206371caf46fSJean Delvare case 0x2: /* Voltage monitoring */ 206471caf46fSJean Delvare data->has_in |= 1 << in_chan; 206571caf46fSJean Delvare break; 206671caf46fSJean Delvare case 0x1: /* Thermal diode */ 206771caf46fSJean Delvare if (temp_chan >= 4) 206871caf46fSJean Delvare break; 206971caf46fSJean Delvare data->temp_mode |= 1 << temp_chan; 207071caf46fSJean Delvare /* fall through */ 207171caf46fSJean Delvare case 0x3: /* Thermistor */ 207271caf46fSJean Delvare data->has_temp |= 1 << temp_chan; 207371caf46fSJean Delvare break; 207471caf46fSJean Delvare } 207571caf46fSJean Delvare } 207671caf46fSJean Delvare 2077792d376bSWei Song static int w83795_probe(struct i2c_client *client, 2078792d376bSWei Song const struct i2c_device_id *id) 2079792d376bSWei Song { 2080792d376bSWei Song int i; 2081792d376bSWei Song u8 tmp; 2082792d376bSWei Song struct device *dev = &client->dev; 2083792d376bSWei Song struct w83795_data *data; 208471caf46fSJean Delvare int err; 2085792d376bSWei Song 2086792d376bSWei Song data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); 2087792d376bSWei Song if (!data) { 2088792d376bSWei Song err = -ENOMEM; 2089792d376bSWei Song goto exit; 2090792d376bSWei Song } 2091792d376bSWei Song 2092792d376bSWei Song i2c_set_clientdata(client, data); 2093093d1a47SJean Delvare data->chip_type = id->driver_data; 2094792d376bSWei Song data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 2095792d376bSWei Song mutex_init(&data->update_lock); 2096792d376bSWei Song 2097792d376bSWei Song /* Initialize the chip */ 2098792d376bSWei Song w83795_init_client(client); 2099792d376bSWei Song 210071caf46fSJean Delvare /* Check which voltages and fans are present */ 210171caf46fSJean Delvare data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) 210271caf46fSJean Delvare | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); 210371caf46fSJean Delvare data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) 210471caf46fSJean Delvare | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); 2105792d376bSWei Song 210671caf46fSJean Delvare /* Check which analog temperatures and extra voltages are present */ 2107792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 2108792d376bSWei Song if (tmp & 0x20) 2109792d376bSWei Song data->enable_dts = 1; 211071caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); 211171caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 4, 15); 2112792d376bSWei Song tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 211371caf46fSJean Delvare w83795_apply_temp_config(data, tmp >> 6, 3, 20); 211471caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); 211571caf46fSJean Delvare w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); 211671caf46fSJean Delvare w83795_apply_temp_config(data, tmp & 0x3, 0, 17); 2117792d376bSWei Song 2118792d376bSWei Song /* Check DTS enable status */ 211971caf46fSJean Delvare if (data->enable_dts) { 2120792d376bSWei Song if (1 & w83795_read(client, W83795_REG_DTSC)) 2121792d376bSWei Song data->enable_dts |= 2; 2122792d376bSWei Song data->has_dts = w83795_read(client, W83795_REG_DTSE); 2123792d376bSWei Song } 2124792d376bSWei Song 212554891a3cSJean Delvare /* Report PECI Tbase values */ 212654891a3cSJean Delvare if (data->enable_dts == 1) { 212754891a3cSJean Delvare for (i = 0; i < 8; i++) { 212854891a3cSJean Delvare if (!(data->has_dts & (1 << i))) 212954891a3cSJean Delvare continue; 213054891a3cSJean Delvare tmp = w83795_read(client, W83795_REG_PECI_TBASE(i)); 213154891a3cSJean Delvare dev_info(&client->dev, 213254891a3cSJean Delvare "PECI agent %d Tbase temperature: %u\n", 213354891a3cSJean Delvare i + 1, (unsigned int)tmp & 0x7f); 213454891a3cSJean Delvare } 213554891a3cSJean Delvare } 213654891a3cSJean Delvare 2137792d376bSWei Song data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 2138792d376bSWei Song 2139792d376bSWei Song /* pwm and smart fan */ 2140792d376bSWei Song if (data->chip_type == w83795g) 2141792d376bSWei Song data->has_pwm = 8; 2142792d376bSWei Song else 2143792d376bSWei Song data->has_pwm = 2; 2144792d376bSWei Song 21456f3dcde9SJean Delvare err = w83795_handle_files(dev, device_create_file); 2146792d376bSWei Song if (err) 2147792d376bSWei Song goto exit_remove; 2148792d376bSWei Song 21490e256018SJean Delvare if (data->chip_type == w83795g) 21500e256018SJean Delvare w83795_check_dynamic_in_limits(client); 21510e256018SJean Delvare 2152792d376bSWei Song data->hwmon_dev = hwmon_device_register(dev); 2153792d376bSWei Song if (IS_ERR(data->hwmon_dev)) { 2154792d376bSWei Song err = PTR_ERR(data->hwmon_dev); 2155792d376bSWei Song goto exit_remove; 2156792d376bSWei Song } 2157792d376bSWei Song 2158792d376bSWei Song return 0; 2159792d376bSWei Song 2160792d376bSWei Song exit_remove: 21616f3dcde9SJean Delvare w83795_handle_files(dev, device_remove_file_wrapper); 2162792d376bSWei Song kfree(data); 2163792d376bSWei Song exit: 2164792d376bSWei Song return err; 2165792d376bSWei Song } 2166792d376bSWei Song 2167792d376bSWei Song static int w83795_remove(struct i2c_client *client) 2168792d376bSWei Song { 2169792d376bSWei Song struct w83795_data *data = i2c_get_clientdata(client); 2170792d376bSWei Song 2171792d376bSWei Song hwmon_device_unregister(data->hwmon_dev); 21726f3dcde9SJean Delvare w83795_handle_files(&client->dev, device_remove_file_wrapper); 2173792d376bSWei Song kfree(data); 2174792d376bSWei Song 2175792d376bSWei Song return 0; 2176792d376bSWei Song } 2177792d376bSWei Song 2178792d376bSWei Song 2179792d376bSWei Song static const struct i2c_device_id w83795_id[] = { 2180093d1a47SJean Delvare { "w83795g", w83795g }, 2181093d1a47SJean Delvare { "w83795adg", w83795adg }, 2182792d376bSWei Song { } 2183792d376bSWei Song }; 2184792d376bSWei Song MODULE_DEVICE_TABLE(i2c, w83795_id); 2185792d376bSWei Song 2186792d376bSWei Song static struct i2c_driver w83795_driver = { 2187792d376bSWei Song .driver = { 2188792d376bSWei Song .name = "w83795", 2189792d376bSWei Song }, 2190792d376bSWei Song .probe = w83795_probe, 2191792d376bSWei Song .remove = w83795_remove, 2192792d376bSWei Song .id_table = w83795_id, 2193792d376bSWei Song 2194792d376bSWei Song .class = I2C_CLASS_HWMON, 2195792d376bSWei Song .detect = w83795_detect, 2196792d376bSWei Song .address_list = normal_i2c, 2197792d376bSWei Song }; 2198792d376bSWei Song 2199792d376bSWei Song static int __init sensors_w83795_init(void) 2200792d376bSWei Song { 2201792d376bSWei Song return i2c_add_driver(&w83795_driver); 2202792d376bSWei Song } 2203792d376bSWei Song 2204792d376bSWei Song static void __exit sensors_w83795_exit(void) 2205792d376bSWei Song { 2206792d376bSWei Song i2c_del_driver(&w83795_driver); 2207792d376bSWei Song } 2208792d376bSWei Song 2209e3760b43SJean Delvare MODULE_AUTHOR("Wei Song, Jean Delvare <khali@linux-fr.org>"); 2210315bacfdSJean Delvare MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 2211792d376bSWei Song MODULE_LICENSE("GPL"); 2212792d376bSWei Song 2213792d376bSWei Song module_init(sensors_w83795_init); 2214792d376bSWei Song module_exit(sensors_w83795_exit); 2215