w83l786ng.c revision 85f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671
185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* 285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng.c - Linux kernel driver for hardware monitoring 385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org> 485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo This program is free software; you can redistribute it and/or modify 685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo it under the terms of the GNU General Public License as published by 785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo the Free Software Foundation - version 2. 885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo This program is distributed in the hope that it will be useful, 1085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo but WITHOUT ANY WARRANTY; without even the implied warranty of 1185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo GNU General Public License for more details. 1385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 1485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo You should have received a copy of the GNU General Public License 1585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo along with this program; if not, write to the Free Software 1685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 1785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 02110-1301 USA. 1885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo*/ 1985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 2085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* 2185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo Supports following chips: 2285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 2385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA 2485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no 2585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo*/ 2685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 2785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/module.h> 2885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/init.h> 2985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/slab.h> 3085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/i2c.h> 3185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/hwmon.h> 3285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/hwmon-vid.h> 3385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/hwmon-sysfs.h> 3485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/err.h> 3585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#include <linux/mutex.h> 3685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 3785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* Addresses to scan */ 3885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END }; 3985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 4085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* Insmod parameters */ 4185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoI2C_CLIENT_INSMOD_1(w83l786ng); 4285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 4385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int reset; 4485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lomodule_param(reset, bool, 0); 4585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); 4685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 4785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_IN_MIN(nr) (0x2C + (nr) * 2) 4885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_IN_MAX(nr) (0x2B + (nr) * 2) 4985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_IN(nr) ((nr) + 0x20) 5085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 5185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_FAN(nr) ((nr) + 0x28) 5285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_FAN_MIN(nr) ((nr) + 0x3B) 5385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 5485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_CONFIG 0x40 5585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_ALARM1 0x41 5685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_ALARM2 0x42 5785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_GPIO_EN 0x47 5885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_MAN_ID2 0x4C 5985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_MAN_ID1 0x4D 6085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_CHIP_ID 0x4E 6185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 6285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_DIODE 0x53 6385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_FAN_DIV 0x54 6485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_FAN_CFG 0x80 6585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 6685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define W83L786NG_REG_TOLERANCE 0x8D 6785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 6885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic const u8 W83L786NG_REG_TEMP[2][3] = { 6985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo { 0x25, /* TEMP 0 in DataSheet */ 7085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 0x35, /* TEMP 0 Over in DataSheet */ 7185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 0x36 }, /* TEMP 0 Hyst in DataSheet */ 7285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo { 0x26, /* TEMP 1 in DataSheet */ 7385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 0x37, /* TEMP 1 Over in DataSheet */ 7485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 0x38 } /* TEMP 1 Hyst in DataSheet */ 7585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 7685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 7785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic const u8 W83L786NG_PWM_MODE_SHIFT[] = {6, 7}; 7885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic const u8 W83L786NG_PWM_ENABLE_SHIFT[] = {2, 4}; 7985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 8085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* FAN Duty Cycle, be used to control */ 8185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic const u8 W83L786NG_REG_PWM[] = {0x81, 0x87}; 8285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 8385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 8485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic inline u8 8585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoFAN_TO_REG(long rpm, int div) 8685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 8785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (rpm == 0) 8885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return 255; 8985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo rpm = SENSORS_LIMIT(rpm, 1, 1000000); 9085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); 9185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 9285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 9385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ 9485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo ((val) == 255 ? 0 : \ 9585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 1350000 / ((val) * (div)))) 9685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 9785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* for temp */ 9885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ 9985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo : (val)) / 1000, 0, 0xff)) 10085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) 10185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 10285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* The analog voltage inputs have 8mV LSB. Since the sysfs output is 10385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo in mV as would be measured on the chip input pin, need to just 10485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo multiply/divide by 8 to translate from/to register values. */ 10585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255)) 10685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define IN_FROM_REG(val) ((val) * 8) 10785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 10885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define DIV_FROM_REG(val) (1 << (val)) 10985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 11085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic inline u8 11185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoDIV_TO_REG(long val) 11285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 11385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int i; 11485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo val = SENSORS_LIMIT(val, 1, 128) >> 1; 11585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 7; i++) { 11685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (val == 0) 11785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo break; 11885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo val >>= 1; 11985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 12085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return ((u8) i); 12185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 12285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 12385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostruct w83l786ng_data { 12485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client client; 12585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct device *hwmon_dev; 12685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct mutex update_lock; 12785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char valid; /* !=0 if following fields are valid */ 12885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long last_updated; /* In jiffies */ 12985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long last_nonvolatile; /* In jiffies, last time we update the 13085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo nonvolatile registers */ 13185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 13285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 in[3]; 13385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 in_max[3]; 13485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 in_min[3]; 13585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan[2]; 13685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan_div[2]; 13785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan_min[2]; 13885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 temp_type[2]; 13985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 temp[2][3]; 14085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 pwm[2]; 14185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 pwm_mode[2]; /* 0->DC variable voltage 14285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 1->PWM variable duty cycle */ 14385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 14485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 pwm_enable[2]; /* 1->manual 14585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 2->thermal cruise (also called SmartFan I) */ 14685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tolerance[2]; 14785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 14885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 14985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int w83l786ng_attach_adapter(struct i2c_adapter *adapter); 15085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind); 15185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int w83l786ng_detach_client(struct i2c_client *client); 15285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic void w83l786ng_init_client(struct i2c_client *client); 15385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct w83l786ng_data *w83l786ng_update_device(struct device *dev); 15485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 15585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct i2c_driver w83l786ng_driver = { 15685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .driver = { 15785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .name = "w83l786ng", 15885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo }, 15985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .attach_adapter = w83l786ng_attach_adapter, 16085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .detach_client = w83l786ng_detach_client, 16185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 16285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 16385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic u8 16485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_read_value(struct i2c_client *client, u8 reg) 16585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 16685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return i2c_smbus_read_byte_data(client, reg); 16785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 16885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 16985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 17085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value) 17185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 17285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return i2c_smbus_write_byte_data(client, reg, value); 17385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 17485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 17585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* following are the sysfs callback functions */ 17685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define show_in_reg(reg) \ 17785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t \ 17885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_##reg(struct device *dev, struct device_attribute *attr, \ 17985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char *buf) \ 18085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 18185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 18285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); \ 18385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \ 18485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 18585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 18685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_in_reg(in) 18785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_in_reg(in_min) 18885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_in_reg(in_max) 18985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 19085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define store_in_reg(REG, reg) \ 19185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t \ 19285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_in_##reg (struct device *dev, struct device_attribute *attr, \ 19385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) \ 19485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 19585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 19685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); \ 19785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); \ 19885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long val = simple_strtoul(buf, NULL, 10); \ 19985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); \ 20085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_##reg[nr] = IN_TO_REG(val); \ 20185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \ 20285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_##reg[nr]); \ 20385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); \ 20485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; \ 20585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 20685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 20785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_in_reg(MIN, min) 20885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_in_reg(MAX, max) 20985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 21085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_in_input[] = { 21185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), 21285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), 21385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), 21485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 21585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 21685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_in_min[] = { 21785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), 21885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), 21985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), 22085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 22185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 22285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_in_max[] = { 22385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), 22485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), 22585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), 22685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 22785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 22885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define show_fan_reg(reg) \ 22985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 23085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char *buf) \ 23185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 23285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 23385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); \ 23485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf,"%d\n", \ 23585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \ 23685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 23785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 23885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_fan_reg(fan); 23985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_fan_reg(fan_min); 24085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 24185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 24285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_fan_min(struct device *dev, struct device_attribute *attr, 24385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 24485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 24585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 24685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 24785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 24885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u32 val; 24985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 25085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo val = simple_strtoul(buf, NULL, 10); 25185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 25285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 25385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), 25485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr]); 25585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 25685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 25785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 25885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 25985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 26085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 26185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_fan_div(struct device *dev, struct device_attribute *attr, 26285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char *buf) 26385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 26485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 26585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); 26685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); 26785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 26885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 26985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* Note: we save and restore the fan minimum here, because its value is 27085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo determined in part by the fan divisor. This follows the principle of 27185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo least surprise; the user doesn't expect the fan minimum to change just 27285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo because the divisor changed. */ 27385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 27485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_fan_div(struct device *dev, struct device_attribute *attr, 27585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 27685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 27785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 27885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 27985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 28085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 28185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long min; 28285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tmp_fan_div; 28385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan_div_reg; 28485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 keep_mask = 0; 28585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 new_shift = 0; 28685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 28785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Save fan_min */ 28885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 28985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); 29085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 29185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); 29285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 29385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo switch (nr) { 29485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo case 0: 29585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo keep_mask = 0xf8; 29685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo new_shift = 0; 29785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo break; 29885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo case 1: 29985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo keep_mask = 0x8f; 30085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo new_shift = 4; 30185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo break; 30285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 30385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 30485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo fan_div_reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV) 30585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo & keep_mask; 30685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 30785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask; 30885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 30985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_DIV, 31085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo fan_div_reg | tmp_fan_div); 31185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 31285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Restore fan_min */ 31385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 31485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), 31585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr]); 31685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 31785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 31885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 31985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 32085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 32185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_fan_input[] = { 32285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), 32385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), 32485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 32585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 32685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_fan_min[] = { 32785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, 32885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_min, 0), 32985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, 33085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_min, 1), 33185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 33285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 33385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_fan_div[] = { 33485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, 33585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_div, 0), 33685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, 33785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_div, 1), 33885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 33985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 34085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 34185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* read/write the temperature, includes measured value and limits */ 34285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 34385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 34485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_temp(struct device *dev, struct device_attribute *attr, char *buf) 34585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 34685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct sensor_device_attribute_2 *sensor_attr = 34785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo to_sensor_dev_attr_2(attr); 34885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = sensor_attr->nr; 34985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int index = sensor_attr->index; 35085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); 35185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); 35285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 35385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 35485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 35585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_temp(struct device *dev, struct device_attribute *attr, 35685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 35785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 35885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct sensor_device_attribute_2 *sensor_attr = 35985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo to_sensor_dev_attr_2(attr); 36085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = sensor_attr->nr; 36185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int index = sensor_attr->index; 36285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 36385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 36485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo s32 val; 36585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 36685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo val = simple_strtol(buf, NULL, 10); 36785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 36885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->temp[nr][index] = TEMP_TO_REG(val); 36985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index], 37085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->temp[nr][index]); 37185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 37285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 37385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 37485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 37585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 37685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute_2 sda_temp_input[] = { 37785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), 37885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0), 37985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 38085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 38185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute_2 sda_temp_max[] = { 38285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, 38385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 0, 1), 38485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, 38585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 1, 1), 38685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 38785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 38885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute_2 sda_temp_max_hyst[] = { 38985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, 39085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 0, 2), 39185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, 39285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 1, 2), 39385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 39485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 39585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define show_pwm_reg(reg) \ 39685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ 39785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char *buf) \ 39885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 39985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); \ 40085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 40185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%d\n", data->reg[nr]); \ 40285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 40385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 40485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_pwm_reg(pwm_mode) 40585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_pwm_reg(pwm_enable) 40685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_pwm_reg(pwm) 40785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 40885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 40985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_pwm_mode(struct device *dev, struct device_attribute *attr, 41085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 41185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 41285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 41385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 41485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 41585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u32 val = simple_strtoul(buf, NULL, 10); 41685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg; 41785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 41885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (val > 1) 41985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return -EINVAL; 42085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 42185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_mode[nr] = val; 42285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); 42385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg &= ~(1 << W83L786NG_PWM_MODE_SHIFT[nr]); 42485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!val) 42585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg |= 1 << W83L786NG_PWM_MODE_SHIFT[nr]; 42685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); 42785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 42885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 42985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 43085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 43185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 43285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_pwm(struct device *dev, struct device_attribute *attr, 43385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 43485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 43585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 43685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 43785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 43885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); 43985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 44085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 44185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm[nr] = val; 44285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val); 44385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 44485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 44585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 44685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 44785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 44885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_pwm_enable(struct device *dev, struct device_attribute *attr, 44985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 45085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 45185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 45285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 45385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 45485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u32 val = simple_strtoul(buf, NULL, 10); 45585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 45685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg; 45785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 45885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!val || (val > 2)) /* only modes 1 and 2 are supported */ 45985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return -EINVAL; 46085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 46185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 46285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); 46385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_enable[nr] = val; 46485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg &= ~(0x02 << W83L786NG_PWM_ENABLE_SHIFT[nr]); 46585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr]; 46685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); 46785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 46885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 46985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 47085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 47185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_pwm[] = { 47285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), 47385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), 47485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 47585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 47685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_pwm_mode[] = { 47785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 47885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_mode, 0), 47985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 48085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_mode, 1), 48185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 48285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 48385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_pwm_enable[] = { 48485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 48585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_enable, 0), 48685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 48785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_enable, 1), 48885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 48985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 49085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* For Smart Fan I/Thermal Cruise and Smart Fan II */ 49185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 49285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_tolerance(struct device *dev, struct device_attribute *attr, char *buf) 49385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 49485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 49585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); 49685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%ld\n", (long)data->tolerance[nr]); 49785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 49885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 49985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 50085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_tolerance(struct device *dev, struct device_attribute *attr, 50185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 50285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 50385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 50485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 50585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 50685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u32 val; 50785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tol_tmp, tol_mask; 50885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 50985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo val = simple_strtoul(buf, NULL, 10); 51085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 51185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 51285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_mask = w83l786ng_read_value(client, 51385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0); 51485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_tmp = SENSORS_LIMIT(val, 0, 15); 51585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_tmp &= 0x0f; 51685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->tolerance[nr] = tol_tmp; 51785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (nr == 1) { 51885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_tmp <<= 4; 51985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 52085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 52185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE, 52285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_mask | tol_tmp); 52385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 52485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 52585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 52685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 52785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_tolerance[] = { 52885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, 52985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_tolerance, store_tolerance, 0), 53085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, 53185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_tolerance, store_tolerance, 1), 53285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 53385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 53485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 53585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define IN_UNIT_ATTRS(X) \ 53685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_in_input[X].dev_attr.attr, \ 53785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_in_min[X].dev_attr.attr, \ 53885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_in_max[X].dev_attr.attr 53985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 54085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define FAN_UNIT_ATTRS(X) \ 54185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_fan_input[X].dev_attr.attr, \ 54285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_fan_min[X].dev_attr.attr, \ 54385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_fan_div[X].dev_attr.attr 54485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 54585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define TEMP_UNIT_ATTRS(X) \ 54685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_temp_input[X].dev_attr.attr, \ 54785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_temp_max[X].dev_attr.attr, \ 54885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_temp_max_hyst[X].dev_attr.attr 54985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 55085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define PWM_UNIT_ATTRS(X) \ 55185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_pwm[X].dev_attr.attr, \ 55285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_pwm_mode[X].dev_attr.attr, \ 55385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_pwm_enable[X].dev_attr.attr 55485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 55585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define TOLERANCE_UNIT_ATTRS(X) \ 55685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_tolerance[X].dev_attr.attr 55785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 55885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct attribute *w83l786ng_attributes[] = { 55985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo IN_UNIT_ATTRS(0), 56085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo IN_UNIT_ATTRS(1), 56185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo IN_UNIT_ATTRS(2), 56285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo FAN_UNIT_ATTRS(0), 56385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo FAN_UNIT_ATTRS(1), 56485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TEMP_UNIT_ATTRS(0), 56585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TEMP_UNIT_ATTRS(1), 56685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo PWM_UNIT_ATTRS(0), 56785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo PWM_UNIT_ATTRS(1), 56885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TOLERANCE_UNIT_ATTRS(0), 56985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TOLERANCE_UNIT_ATTRS(1), 57085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo NULL 57185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 57285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 57385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic const struct attribute_group w83l786ng_group = { 57485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .attrs = w83l786ng_attributes, 57585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 57685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 57785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 57885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_attach_adapter(struct i2c_adapter *adapter) 57985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 58085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!(adapter->class & I2C_CLASS_HWMON)) 58185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return 0; 58285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return i2c_probe(adapter, &addr_data, w83l786ng_detect); 58385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 58485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 58585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 58685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_detect(struct i2c_adapter *adapter, int address, int kind) 58785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 58885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client; 58985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct device *dev; 59085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data; 59185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int i, err = 0; 59285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg_tmp; 59385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 59485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 59585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit; 59685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 59785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 59885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* OK. For now, we presume we have a valid client. We now create the 59985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo client structure, even though we cannot fill it completely yet. 60085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo But it allows us to access w83l786ng_{read,write}_value. */ 60185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 60285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!(data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL))) { 60385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo err = -ENOMEM; 60485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit; 60585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 60685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 60785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo client = &data->client; 60885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo dev = &client->dev; 60985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo i2c_set_clientdata(client, data); 61085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo client->addr = address; 61185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo client->adapter = adapter; 61285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo client->driver = &w83l786ng_driver; 61385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 61485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* 61585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * Now we do the remaining detection. A negative kind means that 61685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * the driver was loaded with no force parameter (default), so we 61785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * must both detect and identify the chip (actually there is only 61885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * one possible kind of chip for now, W83L786NG). A zero kind means 61985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * that the driver was loaded with the force parameter, the detection 62085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * step shall be skipped. A positive kind means that the driver 62185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * was loaded with the force parameter and a given kind of chip is 62285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * requested, so both the detection and the identification steps 62385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo * are skipped. 62485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo */ 62585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (kind < 0) { /* detection */ 62685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (((w83l786ng_read_value(client, 62785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_CONFIG) & 0x80) != 0x00)) { 62885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo dev_dbg(&adapter->dev, 62985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo "W83L786NG detection failed at 0x%02x.\n", 63085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo address); 63185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_free; 63285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 63385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 63485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 63585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (kind <= 0) { /* identification */ 63685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u16 man_id; 63785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 chip_id; 63885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 63985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo man_id = (w83l786ng_read_value(client, 64085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_MAN_ID1) << 8) + 64185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2); 64285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID); 64385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 64485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (man_id == 0x5CA3) { /* Winbond */ 64585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (chip_id == 0x80) { /* W83L786NG */ 64685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo kind = w83l786ng; 64785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 64885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 64985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 65085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (kind <= 0) { /* identification failed */ 65185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo dev_info(&adapter->dev, 65285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo "Unsupported chip (man_id=0x%04X, " 65385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo "chip_id=0x%02X).\n", man_id, chip_id); 65485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_free; 65585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 65685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 65785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 65885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Fill in the remaining client fields and put into the global list */ 65985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo strlcpy(client->name, "w83l786ng", I2C_NAME_SIZE); 66085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_init(&data->update_lock); 66185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 66285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Tell the I2C layer a new client has arrived */ 66385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if ((err = i2c_attach_client(client))) 66485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_free; 66585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 66685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Initialize the chip */ 66785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_init_client(client); 66885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 66985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* A few vars need to be filled upon startup */ 67085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 67185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[i] = w83l786ng_read_value(client, 67285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_FAN_MIN(i)); 67385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 67485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 67585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the fan divisor */ 67685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); 67785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[0] = reg_tmp & 0x07; 67885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[1] = (reg_tmp >> 4) & 0x07; 67985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 68085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Register sysfs hooks */ 68185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if ((err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group))) 68285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_remove; 68385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 68485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->hwmon_dev = hwmon_device_register(dev); 68585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (IS_ERR(data->hwmon_dev)) { 68685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo err = PTR_ERR(data->hwmon_dev); 68785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_remove; 68885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 68985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 69085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return 0; 69185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 69285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Unregister sysfs hooks */ 69385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 69485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loexit_remove: 69585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); 69685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo i2c_detach_client(client); 69785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loexit_free: 69885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo kfree(data); 69985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loexit: 70085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return err; 70185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 70285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 70385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 70485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_detach_client(struct i2c_client *client) 70585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 70685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 70785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int err; 70885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 70985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo hwmon_device_unregister(data->hwmon_dev); 71085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); 71185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 71285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if ((err = i2c_detach_client(client))) 71385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return err; 71485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 71585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo kfree(data); 71685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 71785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return 0; 71885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 71985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 72085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic void 72185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_init_client(struct i2c_client *client) 72285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 72385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tmp; 72485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 72585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (reset) 72685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80); 72785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 72885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Start monitoring */ 72985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG); 73085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!(tmp & 0x01)) 73185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01); 73285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 73385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 73485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct w83l786ng_data *w83l786ng_update_device(struct device *dev) 73585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 73685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 73785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 73885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int i, j; 73985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg_tmp, pwmcfg; 74085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 74185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 74285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 74385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo || !data->valid) { 74485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo dev_dbg(&client->dev, "Updating w83l786ng data.\n"); 74585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 74685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the voltages measured value and limits */ 74785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 3; i++) { 74885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in[i] = w83l786ng_read_value(client, 74985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_IN(i)); 75085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_min[i] = w83l786ng_read_value(client, 75185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_IN_MIN(i)); 75285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_max[i] = w83l786ng_read_value(client, 75385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_IN_MAX(i)); 75485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 75585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 75685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the fan counts and limits */ 75785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 75885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan[i] = w83l786ng_read_value(client, 75985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_FAN(i)); 76085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[i] = w83l786ng_read_value(client, 76185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_FAN_MIN(i)); 76285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 76385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 76485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the fan divisor */ 76585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); 76685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[0] = reg_tmp & 0x07; 76785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[1] = (reg_tmp >> 4) & 0x07; 76885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 76985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); 77085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 77185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_mode[i] = 77285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo ((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1) 77385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo ? 0 : 1; 77485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_enable[i] = 77585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 2) + 1; 77685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm[i] = w83l786ng_read_value(client, 77785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_PWM[i]); 77885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 77985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 78085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 78185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the temperature sensors */ 78285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 78385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (j = 0; j < 3; j++) { 78485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->temp[i][j] = w83l786ng_read_value(client, 78585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_TEMP[i][j]); 78685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 78785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 78885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 78985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update Smart Fan I/II tolerance */ 79085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE); 79185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->tolerance[0] = reg_tmp & 0x0f; 79285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->tolerance[1] = (reg_tmp >> 4) & 0x0f; 79385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 79485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->last_updated = jiffies; 79585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->valid = 1; 79685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 79785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 79885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 79985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 80085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 80185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return data; 80285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 80385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 80485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int __init 80585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Losensors_w83l786ng_init(void) 80685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 80785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return i2c_add_driver(&w83l786ng_driver); 80885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 80985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 81085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic void __exit 81185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Losensors_w83l786ng_exit(void) 81285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 81385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo i2c_del_driver(&w83l786ng_driver); 81485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 81585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 81685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_AUTHOR("Kevin Lo"); 81785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_DESCRIPTION("w83l786ng driver"); 81885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_LICENSE("GPL"); 81985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 82085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lomodule_init(sensors_w83l786ng_init); 82185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lomodule_exit(sensors_w83l786ng_exit); 822