w83l786ng.c revision 33a7ab91d509fa33b4bcd3ce0038cc80298050da
185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* 201d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * w83l786ng.c - Linux kernel driver for hardware monitoring 301d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org> 401d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 501d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * This program is free software; you can redistribute it and/or modify 601d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * it under the terms of the GNU General Public License as published by 701d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * the Free Software Foundation - version 2. 801d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 901d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * This program is distributed in the hope that it will be useful, 1001d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 1101d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1201d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * GNU General Public License for more details. 1301d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 1401d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * You should have received a copy of the GNU General Public License 1501d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * along with this program; if not, write to the Free Software 1601d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 1701d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 02110-1301 USA. 1801d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck */ 1985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 2085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* 2101d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * Supports following chips: 2201d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 234101ece3a226e68a5335dd8a15c7ab8663972b81Jean Delvare * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA 2401d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no 2501d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck */ 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> 36dcd8f39230b9f724ba4f55f14ed2bb8119204385Jean Delvare#include <linux/jiffies.h> 3785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 3885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* Addresses to scan */ 3925e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffmanstatic const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END }; 4085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 4185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* Insmod parameters */ 4285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 4390ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool 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 56ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck#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; 892a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck rpm = clamp_val(rpm, 1, 1000000); 902a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); 9185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 9285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 93ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck#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 */ 982a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \ 992a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck : (val)) / 1000, 0, 0xff)) 100ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck#define TEMP_FROM_REG(val) (((val) & 0x80 ? \ 101ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck (val) - 0x100 : (val)) * 1000) 10285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 10301d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck/* 10401d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * The analog voltage inputs have 8mV LSB. Since the sysfs output is 10501d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * in mV as would be measured on the chip input pin, need to just 10601d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * multiply/divide by 8 to translate from/to register values. 10701d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck */ 1082a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck#define IN_TO_REG(val) (clamp_val((((val) + 4) / 8), 0, 255)) 10985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define IN_FROM_REG(val) ((val) * 8) 11085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 11185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define DIV_FROM_REG(val) (1 << (val)) 11285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 11385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic inline u8 11485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoDIV_TO_REG(long val) 11585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 11685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int i; 1172a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 1, 128) >> 1; 11885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 7; i++) { 11985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (val == 0) 12085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo break; 12185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo val >>= 1; 12285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 1237fe83ad877321f44c8141b8334bd2f6614deb739Frans Meulenbroeks return (u8)i; 12485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 12585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 12685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostruct w83l786ng_data { 12785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct device *hwmon_dev; 12885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct mutex update_lock; 12985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char valid; /* !=0 if following fields are valid */ 13085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long last_updated; /* In jiffies */ 13185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long last_nonvolatile; /* In jiffies, last time we update the 13201d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * nonvolatile registers */ 13385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 13485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 in[3]; 13585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 in_max[3]; 13685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 in_min[3]; 13785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan[2]; 13885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan_div[2]; 13985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan_min[2]; 14085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 temp_type[2]; 14185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 temp[2][3]; 14285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 pwm[2]; 14385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 pwm_mode[2]; /* 0->DC variable voltage 14401d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 1->PWM variable duty cycle */ 14585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 14685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 pwm_enable[2]; /* 1->manual 14701d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * 2->thermal cruise (also called SmartFan I) */ 14885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tolerance[2]; 14985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 15085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 15133468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvarestatic int w83l786ng_probe(struct i2c_client *client, 15233468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare const struct i2c_device_id *id); 153310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int w83l786ng_detect(struct i2c_client *client, 15433468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare struct i2c_board_info *info); 15533468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvarestatic int w83l786ng_remove(struct i2c_client *client); 15685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic void w83l786ng_init_client(struct i2c_client *client); 15785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct w83l786ng_data *w83l786ng_update_device(struct device *dev); 15885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 15933468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvarestatic const struct i2c_device_id w83l786ng_id[] = { 1601f86df49ddfd0067cce941187d57b2fd2f749a9eJean Delvare { "w83l786ng", 0 }, 16133468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare { } 16233468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare}; 16333468e7637c53b5516902422d66ca3d3fe64a9c3Jean DelvareMODULE_DEVICE_TABLE(i2c, w83l786ng_id); 16433468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare 16585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct i2c_driver w83l786ng_driver = { 16633468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare .class = I2C_CLASS_HWMON, 16785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .driver = { 16885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .name = "w83l786ng", 16985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo }, 17033468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare .probe = w83l786ng_probe, 17133468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare .remove = w83l786ng_remove, 17233468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare .id_table = w83l786ng_id, 17333468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare .detect = w83l786ng_detect, 174c3813d6af177fab19e322f3114b1f64fbcf08d71Jean Delvare .address_list = normal_i2c, 17585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 17685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 17785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic u8 17885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_read_value(struct i2c_client *client, u8 reg) 17985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 18085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return i2c_smbus_read_byte_data(client, reg); 18185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 18285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 18385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 18485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value) 18585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 18685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return i2c_smbus_write_byte_data(client, reg, value); 18785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 18885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 18985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* following are the sysfs callback functions */ 19085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define show_in_reg(reg) \ 19185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t \ 19285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_##reg(struct device *dev, struct device_attribute *attr, \ 193ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck char *buf) \ 19485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 19585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 19685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); \ 197ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ 19885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 19985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 20085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_in_reg(in) 20185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_in_reg(in_min) 20285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_in_reg(in_max) 20385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 20485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define store_in_reg(REG, reg) \ 20585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t \ 206ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeckstore_in_##reg(struct device *dev, struct device_attribute *attr, \ 207ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck const char *buf, size_t count) \ 20885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 20985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 21085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); \ 21185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); \ 212ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; \ 213ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err = kstrtoul(buf, 10, &val); \ 214ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) \ 215ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; \ 21685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); \ 21785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_##reg[nr] = IN_TO_REG(val); \ 21885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \ 21985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_##reg[nr]); \ 22085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); \ 22185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; \ 22285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 22385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 22485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_in_reg(MIN, min) 22585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_in_reg(MAX, max) 22685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 22785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_in_input[] = { 22885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), 22985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), 23085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), 23185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 23285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 23385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_in_min[] = { 23485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), 23585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), 23685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), 23785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 23885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 23985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_in_max[] = { 24085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), 24185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), 24285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), 24385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 24485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 24585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define show_fan_reg(reg) \ 24685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 24785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char *buf) \ 24885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 24985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 25085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); \ 251ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return sprintf(buf, "%d\n", \ 252ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \ 25385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 25485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 25585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_fan_reg(fan); 25685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_fan_reg(fan_min); 25785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 25885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 25985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_fan_min(struct device *dev, struct device_attribute *attr, 26085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 26185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 26285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 26385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 26485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 265ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; 266ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 267ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 268ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtoul(buf, 10, &val); 269ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 270ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 27185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 27285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 27385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 27485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), 27585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr]); 27685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 27785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 27885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 27985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 28085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 28185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 28285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_fan_div(struct device *dev, struct device_attribute *attr, 28385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo char *buf) 28485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 28585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 28685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); 28785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); 28885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 28985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 29001d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck/* 29101d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * Note: we save and restore the fan minimum here, because its value is 29201d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * determined in part by the fan divisor. This follows the principle of 29301d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * least surprise; the user doesn't expect the fan minimum to change just 29401d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck * because the divisor changed. 29501d9def5bae959de5d420a2fc09fcc58106513faGuenter Roeck */ 29685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 29785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_fan_div(struct device *dev, struct device_attribute *attr, 29885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 29985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 30085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 30185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 30285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 30385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 30485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo unsigned long min; 30585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tmp_fan_div; 30685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 fan_div_reg; 30785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 keep_mask = 0; 30885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 new_shift = 0; 30985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 310ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; 311ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 312ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 313ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtoul(buf, 10, &val); 314ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 315ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 316ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 31785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Save fan_min */ 31885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 31985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); 32085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 321ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck data->fan_div[nr] = DIV_TO_REG(val); 32285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 32385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo switch (nr) { 32485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo case 0: 32585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo keep_mask = 0xf8; 32685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo new_shift = 0; 32785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo break; 32885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo case 1: 32985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo keep_mask = 0x8f; 33085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo new_shift = 4; 33185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo break; 33285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 33385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 33485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo fan_div_reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV) 33585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo & keep_mask; 33685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 33785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask; 33885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 33985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_DIV, 34085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo fan_div_reg | tmp_fan_div); 34185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 34285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Restore fan_min */ 34385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 34485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), 34585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[nr]); 34685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 34785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 34885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 34985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 35085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 35185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_fan_input[] = { 35285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), 35385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), 35485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 35585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 35685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_fan_min[] = { 35785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, 35885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_min, 0), 35985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, 36085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_min, 1), 36185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 36285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 36385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_fan_div[] = { 36485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, 36585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_div, 0), 36685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, 36785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_fan_div, 1), 36885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 36985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 37085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 37185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* read/write the temperature, includes measured value and limits */ 37285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 37385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 37485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_temp(struct device *dev, struct device_attribute *attr, char *buf) 37585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 37685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct sensor_device_attribute_2 *sensor_attr = 37785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo to_sensor_dev_attr_2(attr); 37885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = sensor_attr->nr; 37985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int index = sensor_attr->index; 38085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); 38185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); 38285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 38385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 38485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 38585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_temp(struct device *dev, struct device_attribute *attr, 38685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 38785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 38885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct sensor_device_attribute_2 *sensor_attr = 38985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo to_sensor_dev_attr_2(attr); 39085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = sensor_attr->nr; 39185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int index = sensor_attr->index; 39285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 39385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 394ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck long val; 395ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 396ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 397ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtol(buf, 10, &val); 398ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 399ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 40085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 40185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 40285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->temp[nr][index] = TEMP_TO_REG(val); 40385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index], 40485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->temp[nr][index]); 40585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 40685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 407ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return count; 40885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 40985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 41085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute_2 sda_temp_input[] = { 41185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), 41285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0), 41385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 41485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 41585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute_2 sda_temp_max[] = { 41685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, 41785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 0, 1), 41885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, 41985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 1, 1), 42085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 42185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 42285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute_2 sda_temp_max_hyst[] = { 42385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, 42485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 0, 2), 42585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, 42685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_temp, store_temp, 1, 2), 42785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 42885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 42985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define show_pwm_reg(reg) \ 430ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeckstatic ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ 431ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck char *buf) \ 43285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ \ 43385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); \ 43485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; \ 43585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%d\n", data->reg[nr]); \ 43685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 43785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 43885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_pwm_reg(pwm_mode) 43985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_pwm_reg(pwm_enable) 44085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_pwm_reg(pwm) 44185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 44285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 44385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_pwm_mode(struct device *dev, struct device_attribute *attr, 44485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 44585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 44685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 44785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 44885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 44985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg; 450ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; 451ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 452ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 453ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtoul(buf, 10, &val); 454ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 455ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 45685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 45785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (val > 1) 45885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return -EINVAL; 45985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 46085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_mode[nr] = val; 46185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); 46285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg &= ~(1 << W83L786NG_PWM_MODE_SHIFT[nr]); 46385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!val) 46485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg |= 1 << W83L786NG_PWM_MODE_SHIFT[nr]; 46585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); 46685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 46785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 46885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 46985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 47085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 47185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_pwm(struct device *dev, struct device_attribute *attr, 47285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 47385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 47485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 47585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 47685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 477ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; 478ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 479ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 480ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtoul(buf, 10, &val); 481ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 482ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 4832a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val, 0, 255); 48433a7ab91d509fa33b4bcd3ce0038cc80298050daJean Delvare val = DIV_ROUND_CLOSEST(val, 0x11); 48585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 48685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 48733a7ab91d509fa33b4bcd3ce0038cc80298050daJean Delvare data->pwm[nr] = val * 0x11; 48833a7ab91d509fa33b4bcd3ce0038cc80298050daJean Delvare val |= w83l786ng_read_value(client, W83L786NG_REG_PWM[nr]) & 0xf0; 48985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val); 49085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 49185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 49285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 49385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 49485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 49585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_pwm_enable(struct device *dev, struct device_attribute *attr, 49685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 49785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 49885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 49985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 50085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 50185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg; 502ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; 503ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 50485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 505ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtoul(buf, 10, &val); 506ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 507ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 508ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck 509ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (!val || val > 2) /* only modes 1 and 2 are supported */ 51085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return -EINVAL; 51185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 51285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 51385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); 51485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_enable[nr] = val; 515cf7559bc053471f32373d71d04a9aa19e0b48d59Brian Carnes reg &= ~(0x03 << W83L786NG_PWM_ENABLE_SHIFT[nr]); 51685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr]; 51785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); 51885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 51985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 52085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 52185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 52285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_pwm[] = { 52385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), 52485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), 52585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 52685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 52785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_pwm_mode[] = { 52885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 52985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_mode, 0), 53085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, 53185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_mode, 1), 53285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 53385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 53485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_pwm_enable[] = { 53585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 53685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_enable, 0), 53785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, 53885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo store_pwm_enable, 1), 53985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 54085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 54185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo/* For Smart Fan I/Thermal Cruise and Smart Fan II */ 54285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 54385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loshow_tolerance(struct device *dev, struct device_attribute *attr, char *buf) 54485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 54585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 54685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = w83l786ng_update_device(dev); 54785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return sprintf(buf, "%ld\n", (long)data->tolerance[nr]); 54885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 54985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 55085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic ssize_t 55185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostore_tolerance(struct device *dev, struct device_attribute *attr, 55285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo const char *buf, size_t count) 55385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 55485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int nr = to_sensor_dev_attr(attr)->index; 55585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 55685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 55785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tol_tmp, tol_mask; 558ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck unsigned long val; 559ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck int err; 56085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 561ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = kstrtoul(buf, 10, &val); 562ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 563ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck return err; 56485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 56585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 56685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_mask = w83l786ng_read_value(client, 56785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0); 5682a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck tol_tmp = clamp_val(val, 0, 15); 56985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_tmp &= 0x0f; 57085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->tolerance[nr] = tol_tmp; 571ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (nr == 1) 57285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_tmp <<= 4; 57385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 57485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE, 57585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tol_mask | tol_tmp); 57685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 57785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return count; 57885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 57985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 58085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct sensor_device_attribute sda_tolerance[] = { 58185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, 58285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_tolerance, store_tolerance, 0), 58385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, 58485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo show_tolerance, store_tolerance, 1), 58585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 58685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 58785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 58885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define IN_UNIT_ATTRS(X) \ 58985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_in_input[X].dev_attr.attr, \ 59085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_in_min[X].dev_attr.attr, \ 59185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_in_max[X].dev_attr.attr 59285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 59385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define FAN_UNIT_ATTRS(X) \ 59485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_fan_input[X].dev_attr.attr, \ 59585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_fan_min[X].dev_attr.attr, \ 59685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_fan_div[X].dev_attr.attr 59785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 59885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define TEMP_UNIT_ATTRS(X) \ 59985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_temp_input[X].dev_attr.attr, \ 60085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_temp_max[X].dev_attr.attr, \ 60185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_temp_max_hyst[X].dev_attr.attr 60285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 60385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define PWM_UNIT_ATTRS(X) \ 60485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_pwm[X].dev_attr.attr, \ 60585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_pwm_mode[X].dev_attr.attr, \ 60685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_pwm_enable[X].dev_attr.attr 60785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 60885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo#define TOLERANCE_UNIT_ATTRS(X) \ 60985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo &sda_tolerance[X].dev_attr.attr 61085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 61185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct attribute *w83l786ng_attributes[] = { 61285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo IN_UNIT_ATTRS(0), 61385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo IN_UNIT_ATTRS(1), 61485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo IN_UNIT_ATTRS(2), 61585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo FAN_UNIT_ATTRS(0), 61685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo FAN_UNIT_ATTRS(1), 61785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TEMP_UNIT_ATTRS(0), 61885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TEMP_UNIT_ATTRS(1), 61985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo PWM_UNIT_ATTRS(0), 62085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo PWM_UNIT_ATTRS(1), 62185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TOLERANCE_UNIT_ATTRS(0), 62285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo TOLERANCE_UNIT_ATTRS(1), 62385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo NULL 62485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 62585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 62685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic const struct attribute_group w83l786ng_group = { 62785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo .attrs = w83l786ng_attributes, 62885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo}; 62985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 63085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 631310ec79210d754afe51e2e4a983e846b60179abdJean Delvarew83l786ng_detect(struct i2c_client *client, struct i2c_board_info *info) 63285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 63333468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare struct i2c_adapter *adapter = client->adapter; 63452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare u16 man_id; 63552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare u8 chip_id; 63685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 637ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 63833468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare return -ENODEV; 63985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 64052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* Detection */ 64152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if ((w83l786ng_read_value(client, W83L786NG_REG_CONFIG) & 0x80)) { 64252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare dev_dbg(&adapter->dev, "W83L786NG detection failed at 0x%02x\n", 64352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare client->addr); 64452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 64585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 64685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 64752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* Identification */ 64852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare man_id = (w83l786ng_read_value(client, W83L786NG_REG_MAN_ID1) << 8) + 64952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2); 65052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID); 65152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare 65252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (man_id != 0x5CA3 || /* Winbond */ 65352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare chip_id != 0x80) { /* W83L786NG */ 65452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare dev_dbg(&adapter->dev, 65552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare "Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n", 65652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare man_id, chip_id); 65752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 65885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 65985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 66033468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare strlcpy(info->type, "w83l786ng", I2C_NAME_SIZE); 66185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 66233468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare return 0; 66333468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare} 66433468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare 66533468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvarestatic int 66633468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvarew83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id) 66733468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare{ 66833468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare struct device *dev = &client->dev; 66933468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare struct w83l786ng_data *data; 67033468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare int i, err = 0; 67133468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare u8 reg_tmp; 67233468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare 673816864d9968814c23c12e6601ad7dd1dabb8f994Guenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct w83l786ng_data), 674816864d9968814c23c12e6601ad7dd1dabb8f994Guenter Roeck GFP_KERNEL); 675816864d9968814c23c12e6601ad7dd1dabb8f994Guenter Roeck if (!data) 676816864d9968814c23c12e6601ad7dd1dabb8f994Guenter Roeck return -ENOMEM; 67733468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare 67833468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare i2c_set_clientdata(client, data); 67933468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvare mutex_init(&data->update_lock); 68085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 68185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Initialize the chip */ 68285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_init_client(client); 68385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 68485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* A few vars need to be filled upon startup */ 68585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 68685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[i] = w83l786ng_read_value(client, 68785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_FAN_MIN(i)); 68885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 68985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 69085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the fan divisor */ 69185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); 69285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[0] = reg_tmp & 0x07; 69385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[1] = (reg_tmp >> 4) & 0x07; 69485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 69585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Register sysfs hooks */ 696ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group); 697ca3ccad827175fa47f4b20ea4c7072e1ddc33128Guenter Roeck if (err) 69885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_remove; 69985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 70085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->hwmon_dev = hwmon_device_register(dev); 70185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (IS_ERR(data->hwmon_dev)) { 70285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo err = PTR_ERR(data->hwmon_dev); 70385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo goto exit_remove; 70485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 70585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 70685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return 0; 70785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 70885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Unregister sysfs hooks */ 70985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 71085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Loexit_remove: 71185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); 71285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return err; 71385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 71485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 71585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic int 71633468e7637c53b5516902422d66ca3d3fe64a9c3Jean Delvarew83l786ng_remove(struct i2c_client *client) 71785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 71885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 71985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 72085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo hwmon_device_unregister(data->hwmon_dev); 72185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); 72285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 72385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return 0; 72485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 72585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 72685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic void 72785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Low83l786ng_init_client(struct i2c_client *client) 72885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 72985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 tmp; 73085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 73185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (reset) 73285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80); 73385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 73485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Start monitoring */ 73585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG); 73685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (!(tmp & 0x01)) 73785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01); 73885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 73985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 74085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lostatic struct w83l786ng_data *w83l786ng_update_device(struct device *dev) 74185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo{ 74285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct i2c_client *client = to_i2c_client(dev); 74385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo struct w83l786ng_data *data = i2c_get_clientdata(client); 74485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo int i, j; 74585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo u8 reg_tmp, pwmcfg; 74685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 74785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_lock(&data->update_lock); 74885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 74985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo || !data->valid) { 75085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo dev_dbg(&client->dev, "Updating w83l786ng data.\n"); 75185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 75285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the voltages measured value and limits */ 75385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 3; i++) { 75485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in[i] = w83l786ng_read_value(client, 75585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_IN(i)); 75685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_min[i] = w83l786ng_read_value(client, 75785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_IN_MIN(i)); 75885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->in_max[i] = w83l786ng_read_value(client, 75985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_IN_MAX(i)); 76085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 76185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 76285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the fan counts and limits */ 76385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 76485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan[i] = w83l786ng_read_value(client, 76585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_FAN(i)); 76685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_min[i] = w83l786ng_read_value(client, 76785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_FAN_MIN(i)); 76885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 76985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 77085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the fan divisor */ 77185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); 77285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[0] = reg_tmp & 0x07; 77385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->fan_div[1] = (reg_tmp >> 4) & 0x07; 77485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 77585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); 77685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 77785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_mode[i] = 77885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo ((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1) 77985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo ? 0 : 1; 78085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->pwm_enable[i] = 781cf7559bc053471f32373d71d04a9aa19e0b48d59Brian Carnes ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 3) + 1; 78233a7ab91d509fa33b4bcd3ce0038cc80298050daJean Delvare data->pwm[i] = 78333a7ab91d509fa33b4bcd3ce0038cc80298050daJean Delvare (w83l786ng_read_value(client, W83L786NG_REG_PWM[i]) 78433a7ab91d509fa33b4bcd3ce0038cc80298050daJean Delvare & 0x0f) * 0x11; 78585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 78685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 78785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 78885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update the temperature sensors */ 78985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (i = 0; i < 2; i++) { 79085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo for (j = 0; j < 3; j++) { 79185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->temp[i][j] = w83l786ng_read_value(client, 79285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo W83L786NG_REG_TEMP[i][j]); 79385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 79485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 79585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 79685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo /* Update Smart Fan I/II tolerance */ 79785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE); 79885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->tolerance[0] = reg_tmp & 0x0f; 79985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->tolerance[1] = (reg_tmp >> 4) & 0x0f; 80085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 80185f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->last_updated = jiffies; 80285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo data->valid = 1; 80385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 80485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo } 80585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 80685f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo mutex_unlock(&data->update_lock); 80785f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 80885f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo return data; 80985f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo} 81085f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 811f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(w83l786ng_driver); 81285f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin Lo 81385f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_AUTHOR("Kevin Lo"); 81485f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_DESCRIPTION("w83l786ng driver"); 81585f03bccd6e0e2ac6ccf017d4bcd5d74bb87a671Kevin LoMODULE_LICENSE("GPL"); 816