From 792d376b4f3f6af302d40373fa864f8b8e691c53 Mon Sep 17 00:00:00 2001 From: Wei Song Date: Thu, 28 Oct 2010 20:31:44 +0200 Subject: hwmon: New driver for the W83795G/ADG monitoring chips There is still much work needed, but I wanted to give Wei the credit he deserves. I've merged some of my own fixes already, to make gcc and checkpatch happy. Individual fixes and improvements from me will follow. [JD: Fix build errors] [JD: Coding style cleanups] [JD: Get rid of forward declarations] [JD: Drop VID support] [JD: Drop fault output control feature] [JD: Use lowercase for inline function names] [JD: Use strict variants of the strtol/ul functions] [JD: Shorten the read and write function names] Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 2138 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2138 insertions(+) create mode 100644 drivers/hwmon/w83795.c (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c new file mode 100644 index 000000000000..c6984c817067 --- /dev/null +++ b/drivers/hwmon/w83795.c @@ -0,0 +1,2138 @@ +/* + * w83795.c - Linux kernel driver for hardware monitoring + * Copyright (C) 2008 Nuvoton Technology Corp. + * Wei Song + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation - version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp #dts wchipid vendid i2c ISA + * w83795g 21 14 8 6 8 0x79 0x5ca3 yes no + * w83795adg 18 14 2 6 8 0x79 0x5ca3 yes no + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; + +enum chips { w83795 }; + + +static int reset; +module_param(reset, bool, 0); +MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); + + +#define W83795_REG_BANKSEL 0x00 +#define W83795_REG_VENDORID 0xfd +#define W83795_REG_CHIPID 0xfe +#define W83795_REG_DEVICEID 0xfb + +#define W83795_REG_I2C_ADDR 0xfc +#define W83795_REG_CONFIG 0x01 +#define W83795_REG_CONFIG_CONFIG48 0x04 + +/* Multi-Function Pin Ctrl Registers */ +#define W83795_REG_VOLT_CTRL1 0x02 +#define W83795_REG_VOLT_CTRL2 0x03 +#define W83795_REG_TEMP_CTRL1 0x04 +#define W83795_REG_TEMP_CTRL2 0x05 +#define W83795_REG_FANIN_CTRL1 0x06 +#define W83795_REG_FANIN_CTRL2 0x07 +#define W83795_REG_VMIGB_CTRL 0x08 + +#define TEMP_CTRL_DISABLE 0 +#define TEMP_CTRL_TD 1 +#define TEMP_CTRL_VSEN 2 +#define TEMP_CTRL_TR 3 +#define TEMP_CTRL_SHIFT 4 +#define TEMP_CTRL_HASIN_SHIFT 5 +/* temp mode may effect VSEN17-12 (in20-15) */ +static u16 W83795_REG_TEMP_CTRL[][6] = { + /* Disable, TD, VSEN, TR, register shift value, has_in shift num */ + {0x00, 0x01, 0x02, 0x03, 0, 17}, /* TR1 */ + {0x00, 0x04, 0x08, 0x0C, 2, 18}, /* TR2 */ + {0x00, 0x10, 0x20, 0x30, 4, 19}, /* TR3 */ + {0x00, 0x40, 0x80, 0xC0, 6, 20}, /* TR4 */ + {0x00, 0x00, 0x02, 0x03, 0, 15}, /* TR5 */ + {0x00, 0x00, 0x08, 0x0C, 2, 16}, /* TR6 */ +}; + +#define TEMP_READ 0 +#define TEMP_CRIT 1 +#define TEMP_CRIT_HYST 2 +#define TEMP_WARN 3 +#define TEMP_WARN_HYST 4 +/* only crit and crit_hyst affect real-time alarm status + * current crit crit_hyst warn warn_hyst */ +static u16 W83795_REG_TEMP[][5] = { + {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ + {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ + {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ + {0x24, 0xa2, 0xa3, 0xa4, 0xa5}, /* TD4/TR4 */ + {0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, /* TR5 */ + {0x20, 0xaa, 0xab, 0xac, 0xad}, /* TR6 */ +}; + +#define IN_READ 0 +#define IN_MAX 1 +#define IN_LOW 2 +static const u16 W83795_REG_IN[][3] = { + /* Current, HL, LL */ + {0x10, 0x70, 0x71}, /* VSEN1 */ + {0x11, 0x72, 0x73}, /* VSEN2 */ + {0x12, 0x74, 0x75}, /* VSEN3 */ + {0x13, 0x76, 0x77}, /* VSEN4 */ + {0x14, 0x78, 0x79}, /* VSEN5 */ + {0x15, 0x7a, 0x7b}, /* VSEN6 */ + {0x16, 0x7c, 0x7d}, /* VSEN7 */ + {0x17, 0x7e, 0x7f}, /* VSEN8 */ + {0x18, 0x80, 0x81}, /* VSEN9 */ + {0x19, 0x82, 0x83}, /* VSEN10 */ + {0x1A, 0x84, 0x85}, /* VSEN11 */ + {0x1B, 0x86, 0x87}, /* VTT */ + {0x1C, 0x88, 0x89}, /* 3VDD */ + {0x1D, 0x8a, 0x8b}, /* 3VSB */ + {0x1E, 0x8c, 0x8d}, /* VBAT */ + {0x1F, 0xa6, 0xa7}, /* VSEN12 */ + {0x20, 0xaa, 0xab}, /* VSEN13 */ + {0x21, 0x96, 0x97}, /* VSEN14 */ + {0x22, 0x9a, 0x9b}, /* VSEN15 */ + {0x23, 0x9e, 0x9f}, /* VSEN16 */ + {0x24, 0xa2, 0xa3}, /* VSEN17 */ +}; +#define W83795_REG_VRLSB 0x3C +#define VRLSB_SHIFT 6 + +static const u8 W83795_REG_IN_HL_LSB[] = { + 0x8e, /* VSEN1-4 */ + 0x90, /* VSEN5-8 */ + 0x92, /* VSEN9-11 */ + 0x94, /* VTT, 3VDD, 3VSB, 3VBAT */ + 0xa8, /* VSEN12 */ + 0xac, /* VSEN13 */ + 0x98, /* VSEN14 */ + 0x9c, /* VSEN15 */ + 0xa0, /* VSEN16 */ + 0xa4, /* VSEN17 */ +}; + +#define IN_LSB_REG(index, type) \ + (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ + : (W83795_REG_IN_HL_LSB[(index)] + 1)) + +#define IN_LSB_REG_NUM 10 + +#define IN_LSB_SHIFT 0 +#define IN_LSB_IDX 1 +static const u8 IN_LSB_SHIFT_IDX[][2] = { + /* High/Low LSB shift, LSB No. */ + {0x00, 0x00}, /* VSEN1 */ + {0x02, 0x00}, /* VSEN2 */ + {0x04, 0x00}, /* VSEN3 */ + {0x06, 0x00}, /* VSEN4 */ + {0x00, 0x01}, /* VSEN5 */ + {0x02, 0x01}, /* VSEN6 */ + {0x04, 0x01}, /* VSEN7 */ + {0x06, 0x01}, /* VSEN8 */ + {0x00, 0x02}, /* VSEN9 */ + {0x02, 0x02}, /* VSEN10 */ + {0x04, 0x02}, /* VSEN11 */ + {0x00, 0x03}, /* VTT */ + {0x02, 0x03}, /* 3VDD */ + {0x04, 0x03}, /* 3VSB */ + {0x06, 0x03}, /* VBAT */ + {0x06, 0x04}, /* VSEN12 */ + {0x06, 0x05}, /* VSEN13 */ + {0x06, 0x06}, /* VSEN14 */ + {0x06, 0x07}, /* VSEN15 */ + {0x06, 0x08}, /* VSEN16 */ + {0x06, 0x09}, /* VSEN17 */ +}; + + +/* 3VDD, 3VSB, VBAT * 0.006 */ +#define REST_VLT_BEGIN 12 /* the 13th volt to 15th */ +#define REST_VLT_END 14 /* the 13th volt to 15th */ + +#define W83795_REG_FAN(index) (0x2E + (index)) +#define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) +#define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) +#define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ + (((index) % 1) ? 4 : 0) +#define W83795_REG_FAN_CTRL_SHIFT(index) \ + (((index) > 7) ? ((index) - 8) : (index)) + +#define W83795_REG_VID_CTRL 0x6A + +#define ALARM_BEEP_REG_NUM 6 +#define W83795_REG_ALARM(index) (0x41 + (index)) +#define W83795_REG_BEEP(index) (0x50 + (index)) + +#define W83795_REG_CLR_CHASSIS 0x4D + + +#define W83795_REG_TEMP_NUM 6 +#define W83795_REG_FCMS1 0x201 +#define W83795_REG_FCMS2 0x208 +#define W83795_REG_TFMR(index) (0x202 + (index)) +#define W83795_REG_FOMC 0x20F +#define W83795_REG_FOPFP(index) (0x218 + (index)) + +#define W83795_REG_TSS(index) (0x209 + (index)) + +#define PWM_OUTPUT 0 +#define PWM_START 1 +#define PWM_NONSTOP 2 +#define PWM_STOP_TIME 3 +#define PWM_DIV 4 +#define W83795_REG_PWM(index, nr) \ + (((nr) == 0 ? 0x210 : \ + (nr) == 1 ? 0x220 : \ + (nr) == 2 ? 0x228 : \ + (nr) == 3 ? 0x230 : 0x218) + (index)) + +#define W83795_REG_FOPFP_DIV(index) \ + (((index) < 8) ? ((index) + 1) : \ + ((index) == 8) ? 12 : \ + (16 << ((index) - 9))) + +#define W83795_REG_FTSH(index) (0x240 + (index) * 2) +#define W83795_REG_FTSL(index) (0x241 + (index) * 2) +#define W83795_REG_TFTS 0x250 + +#define TEMP_PWM_TTTI 0 +#define TEMP_PWM_CTFS 1 +#define TEMP_PWM_HCT 2 +#define TEMP_PWM_HOT 3 +#define W83795_REG_TTTI(index) (0x260 + (index)) +#define W83795_REG_CTFS(index) (0x268 + (index)) +#define W83795_REG_HT(index) (0x270 + (index)) + +#define SF4_TEMP 0 +#define SF4_PWM 1 +#define W83795_REG_SF4_TEMP(temp_num, index) \ + (0x280 + 0x10 * (temp_num) + (index)) +#define W83795_REG_SF4_PWM(temp_num, index) \ + (0x288 + 0x10 * (temp_num) + (index)) + +#define W83795_REG_DTSC 0x301 +#define W83795_REG_DTSE 0x302 +#define W83795_REG_DTS(index) (0x26 + (index)) + +#define DTS_CRIT 0 +#define DTS_CRIT_HYST 1 +#define DTS_WARN 2 +#define DTS_WARN_HYST 3 +#define W83795_REG_DTS_EXT(index) (0xB2 + (index)) + +#define SETUP_PWM_DEFAULT 0 +#define SETUP_PWM_UPTIME 1 +#define SETUP_PWM_DOWNTIME 2 +#define W83795_REG_SETUP_PWM(index) (0x20C + (index)) + +static inline u16 in_from_reg(u8 index, u16 val) +{ + if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) + return val * 6; + else + return val * 2; +} + +static inline u16 in_to_reg(u8 index, u16 val) +{ + if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) + return val / 6; + else + return val / 2; +} + +static inline unsigned long fan_from_reg(u16 val) +{ + if ((val >= 0xff0) || (val == 0)) + return 0; + return 1350000UL / val; +} + +static inline u16 fan_to_reg(long rpm) +{ + if (rpm <= 0) + return 0x0fff; + return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); +} + +static inline unsigned long time_from_reg(u8 reg) +{ + return reg * 100; +} + +static inline u8 time_to_reg(unsigned long val) +{ + return SENSORS_LIMIT((val + 50) / 100, 0, 0xff); +} + +static inline long temp_from_reg(s8 reg) +{ + return reg * 1000; +} + +static inline s8 temp_to_reg(long val, s8 min, s8 max) +{ + return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); +} + + +enum chip_types {w83795g, w83795adg}; + +struct w83795_data { + struct device *hwmon_dev; + struct mutex update_lock; + unsigned long last_updated; /* In jiffies */ + enum chip_types chip_type; + + u8 bank; + + u32 has_in; /* Enable monitor VIN or not */ + u16 in[21][3]; /* Register value, read/high/low */ + u8 in_lsb[10][3]; /* LSB Register value, high/low */ + u8 has_gain; /* has gain: in17-20 * 8 */ + + u16 has_fan; /* Enable fan14-1 or not */ + u16 fan[14]; /* Register value combine */ + u16 fan_min[14]; /* Register value combine */ + + u8 has_temp; /* Enable monitor temp6-1 or not */ + u8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ + u8 temp_read_vrlsb[6]; + u8 temp_mode; /* bit 0: TR mode, bit 1: TD mode */ + u8 temp_src[3]; /* Register value */ + + u8 enable_dts; /* Enable PECI and SB-TSI, + * bit 0: =1 enable, =0 disable, + * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ + u8 has_dts; /* Enable monitor DTS temp */ + u8 dts[8]; /* Register value */ + u8 dts_read_vrlsb[8]; /* Register value */ + u8 dts_ext[4]; /* Register value */ + + u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, + * no config register, only affected by chip + * type */ + u8 pwm[8][5]; /* Register value, output, start, non stop, stop + * time, div */ + u8 pwm_fcms[2]; /* Register value */ + u8 pwm_tfmr[6]; /* Register value */ + u8 pwm_fomc; /* Register value */ + + u16 target_speed[8]; /* Register value, target speed for speed + * cruise */ + u8 tol_speed; /* tolerance of target speed */ + u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ + u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ + + u8 setup_pwm[3]; /* Register value */ + + u8 alarms[6]; /* Register value */ + u8 beeps[6]; /* Register value */ + u8 beep_enable; + + char valid; +}; + +/* + * Hardware access + */ + +/* Ignore the possibility that somebody change bank outside the driver + * Must be called with data->update_lock held, except during initialization */ +static u8 w83795_read(struct i2c_client *client, u16 reg) +{ + struct w83795_data *data = i2c_get_clientdata(client); + u8 res = 0xff; + u8 new_bank = reg >> 8; + + new_bank |= data->bank & 0xfc; + if (data->bank != new_bank) { + if (i2c_smbus_write_byte_data + (client, W83795_REG_BANKSEL, new_bank) >= 0) + data->bank = new_bank; + else { + dev_err(&client->dev, + "set bank to %d failed, fall back " + "to bank %d, read reg 0x%x error\n", + new_bank, data->bank, reg); + res = 0x0; /* read 0x0 from the chip */ + goto END; + } + } + res = i2c_smbus_read_byte_data(client, reg & 0xff); +END: + return res; +} + +/* Must be called with data->update_lock held, except during initialization */ +static int w83795_write(struct i2c_client *client, u16 reg, u8 value) +{ + struct w83795_data *data = i2c_get_clientdata(client); + int res; + u8 new_bank = reg >> 8; + + new_bank |= data->bank & 0xfc; + if (data->bank != new_bank) { + res = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, + new_bank); + if (res >= 0) + data->bank = new_bank; + else { + dev_err(&client->dev, + "set bank to %d failed, fall back " + "to bank %d, write reg 0x%x error\n", + new_bank, data->bank, reg); + goto END; + } + } + + res = i2c_smbus_write_byte_data(client, reg & 0xff, value); +END: + return res; +} + +static struct w83795_data *w83795_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + u16 tmp; + int i; + + mutex_lock(&data->update_lock); + + if (!(time_after(jiffies, data->last_updated + HZ * 2) + || !data->valid)) + goto END; + + /* Update the voltages value */ + for (i = 0; i < ARRAY_SIZE(data->in); i++) { + if (!(data->has_in & (1 << i))) + continue; + tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; + tmp |= (w83795_read(client, W83795_REG_VRLSB) + >> VRLSB_SHIFT) & 0x03; + data->in[i][IN_READ] = tmp; + } + + /* Update fan */ + for (i = 0; i < ARRAY_SIZE(data->fan); i++) { + if (!(data->has_fan & (1 << i))) + continue; + data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; + data->fan[i] |= + (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F; + } + + /* Update temperature */ + for (i = 0; i < ARRAY_SIZE(data->temp); i++) { + /* even stop monitor, register still keep value, just read out + * it */ + if (!(data->has_temp & (1 << i))) { + data->temp[i][TEMP_READ] = 0; + data->temp_read_vrlsb[i] = 0; + continue; + } + data->temp[i][TEMP_READ] = + w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); + data->temp_read_vrlsb[i] = + w83795_read(client, W83795_REG_VRLSB); + } + + /* Update dts temperature */ + if (data->enable_dts != 0) { + for (i = 0; i < ARRAY_SIZE(data->dts); i++) { + if (!(data->has_dts & (1 << i))) + continue; + data->dts[i] = + w83795_read(client, W83795_REG_DTS(i)); + data->dts_read_vrlsb[i] = + w83795_read(client, W83795_REG_VRLSB); + } + } + + /* Update pwm output */ + for (i = 0; i < data->has_pwm; i++) { + data->pwm[i][PWM_OUTPUT] = + w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); + } + + /* update alarm */ + for (i = 0; i < ALARM_BEEP_REG_NUM; i++) + data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); + + data->last_updated = jiffies; + data->valid = 1; + +END: + mutex_unlock(&data->update_lock); + return data; +} + +/* + * Sysfs attributes + */ + +#define ALARM_STATUS 0 +#define BEEP_ENABLE 1 +static ssize_t +show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83795_data *data = w83795_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index >> 3; + int bit = sensor_attr->index & 0x07; + u8 val; + + if (ALARM_STATUS == nr) { + val = (data->alarms[index] >> (bit)) & 1; + } else { /* BEEP_ENABLE */ + val = (data->beeps[index] >> (bit)) & 1; + } + + return sprintf(buf, "%u\n", val); +} + +static ssize_t +store_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index >> 3; + int shift = sensor_attr->index & 0x07; + u8 beep_bit = 1 << shift; + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + if (val != 0 && val != 1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); + data->beeps[index] &= ~beep_bit; + data->beeps[index] |= val << shift; + w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t +show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + return sprintf(buf, "%u\n", data->beep_enable); +} + +static ssize_t +store_beep_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + unsigned long val; + u8 tmp; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + if (val != 0 && val != 1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->beep_enable = val; + tmp = w83795_read(client, W83795_REG_BEEP(5)); + tmp &= 0x7f; + tmp |= val << 7; + w83795_write(client, W83795_REG_BEEP(5), tmp); + mutex_unlock(&data->update_lock); + + return count; +} + +/* Write any value to clear chassis alarm */ +static ssize_t +store_chassis_clear(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + u8 val; + + mutex_lock(&data->update_lock); + val = w83795_read(client, W83795_REG_CLR_CHASSIS); + val |= 0x80; + w83795_write(client, W83795_REG_CLR_CHASSIS, val); + mutex_unlock(&data->update_lock); + return count; +} + +#define FAN_INPUT 0 +#define FAN_MIN 1 +static ssize_t +show_fan(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct w83795_data *data = w83795_update_device(dev); + u16 val; + + if (FAN_INPUT == nr) + val = data->fan[index] & 0x0fff; + else + val = data->fan_min[index] & 0x0fff; + + return sprintf(buf, "%lu\n", fan_from_reg(val)); +} + +static ssize_t +store_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + val = fan_to_reg(val); + + mutex_lock(&data->update_lock); + data->fan_min[index] = val; + w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); + val &= 0x0f; + if (index % 1) { + val <<= 4; + val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) + & 0x0f; + } else { + val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) + & 0xf0; + } + w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t +show_pwm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83795_data *data = w83795_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + u16 val; + + switch (nr) { + case PWM_STOP_TIME: + val = time_from_reg(data->pwm[index][nr]); + break; + case PWM_DIV: + val = W83795_REG_FOPFP_DIV(data->pwm[index][nr] & 0x0f); + break; + default: + val = data->pwm[index][nr]; + break; + } + + return sprintf(buf, "%u\n", val); +} + +static ssize_t +store_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + unsigned long val; + int i; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + switch (nr) { + case PWM_STOP_TIME: + val = time_to_reg(val); + break; + case PWM_DIV: + for (i = 0; i < 16; i++) { + if (W83795_REG_FOPFP_DIV(i) == val) { + val = i; + break; + } + } + if (i >= 16) + goto err_end; + val |= w83795_read(client, W83795_REG_PWM(index, nr)) & 0x80; + break; + default: + val = SENSORS_LIMIT(val, 0, 0xff); + break; + } + w83795_write(client, W83795_REG_PWM(index, nr), val); + data->pwm[index][nr] = val & 0xff; + mutex_unlock(&data->update_lock); + return count; +err_end: + mutex_unlock(&data->update_lock); + return -EINVAL; +} + +static ssize_t +show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + int index = sensor_attr->index; + u8 tmp; + + if (1 == (data->pwm_fcms[0] & (1 << index))) { + tmp = 2; + goto out; + } + for (tmp = 0; tmp < 6; tmp++) { + if (data->pwm_tfmr[tmp] & (1 << index)) { + tmp = 3; + goto out; + } + } + if (data->pwm_fomc & (1 << index)) + tmp = 0; + else + tmp = 1; + +out: + return sprintf(buf, "%u\n", tmp); +} + +static ssize_t +store_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + unsigned long val; + int i; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + if (val > 2) + return -EINVAL; + + mutex_lock(&data->update_lock); + switch (val) { + case 0: + case 1: + data->pwm_fcms[0] &= ~(1 << index); + w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); + for (i = 0; i < 6; i++) { + data->pwm_tfmr[i] &= ~(1 << index); + w83795_write(client, W83795_REG_TFMR(i), + data->pwm_tfmr[i]); + } + data->pwm_fomc |= 1 << index; + data->pwm_fomc ^= val << index; + w83795_write(client, W83795_REG_FOMC, data->pwm_fomc); + break; + case 2: + data->pwm_fcms[0] |= (1 << index); + w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); + break; + } + mutex_unlock(&data->update_lock); + return count; + + mutex_unlock(&data->update_lock); + return -EINVAL; +} + +static ssize_t +show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + int index = sensor_attr->index; + u8 val = index / 2; + u8 tmp = data->temp_src[val]; + + if (index % 1) + val = 4; + else + val = 0; + tmp >>= val; + tmp &= 0x0f; + + return sprintf(buf, "%u\n", tmp); +} + +static ssize_t +store_temp_src(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + unsigned long tmp; + u8 val = index / 2; + + if (strict_strtoul(buf, 10, &tmp) < 0) + return -EINVAL; + tmp = SENSORS_LIMIT(tmp, 0, 15); + + mutex_lock(&data->update_lock); + if (index % 1) { + tmp <<= 4; + data->temp_src[val] &= 0x0f; + } else { + data->temp_src[val] &= 0xf0; + } + data->temp_src[val] |= tmp; + w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); + mutex_unlock(&data->update_lock); + + return count; +} + +#define TEMP_PWM_ENABLE 0 +#define TEMP_PWM_FAN_MAP 1 +static ssize_t +show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + u8 tmp = 0xff; + + switch (nr) { + case TEMP_PWM_ENABLE: + tmp = (data->pwm_fcms[1] >> index) & 1; + if (tmp) + tmp = 4; + else + tmp = 3; + break; + case TEMP_PWM_FAN_MAP: + tmp = data->pwm_tfmr[index]; + break; + } + + return sprintf(buf, "%u\n", tmp); +} + +static ssize_t +store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + unsigned long tmp; + + if (strict_strtoul(buf, 10, &tmp) < 0) + return -EINVAL; + + switch (nr) { + case TEMP_PWM_ENABLE: + if ((tmp != 3) && (tmp != 4)) + return -EINVAL; + tmp -= 3; + mutex_lock(&data->update_lock); + data->pwm_fcms[1] &= ~(1 << index); + data->pwm_fcms[1] |= tmp << index; + w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); + mutex_unlock(&data->update_lock); + break; + case TEMP_PWM_FAN_MAP: + mutex_lock(&data->update_lock); + tmp = SENSORS_LIMIT(tmp, 0, 0xff); + w83795_write(client, W83795_REG_TFMR(index), tmp); + data->pwm_tfmr[index] = tmp; + mutex_unlock(&data->update_lock); + break; + } + return count; +} + +#define FANIN_TARGET 0 +#define FANIN_TOL 1 +static ssize_t +show_fanin(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + u16 tmp = 0; + + switch (nr) { + case FANIN_TARGET: + tmp = fan_from_reg(data->target_speed[index]); + break; + case FANIN_TOL: + tmp = data->tol_speed; + break; + } + + return sprintf(buf, "%u\n", tmp); +} + +static ssize_t +store_fanin(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + switch (nr) { + case FANIN_TARGET: + val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); + w83795_write(client, W83795_REG_FTSH(index), (val >> 4) & 0xff); + w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); + data->target_speed[index] = val; + break; + case FANIN_TOL: + val = SENSORS_LIMIT(val, 0, 0x3f); + w83795_write(client, W83795_REG_TFTS, val); + data->tol_speed = val; + break; + } + mutex_unlock(&data->update_lock); + + return count; +} + + +static ssize_t +show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + long tmp = temp_from_reg(data->pwm_temp[index][nr]); + + return sprintf(buf, "%ld\n", tmp); +} + +static ssize_t +store_temp_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + unsigned long val; + u8 tmp; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + val /= 1000; + + mutex_lock(&data->update_lock); + switch (nr) { + case TEMP_PWM_TTTI: + val = SENSORS_LIMIT(val, 0, 0x7f); + w83795_write(client, W83795_REG_TTTI(index), val); + break; + case TEMP_PWM_CTFS: + val = SENSORS_LIMIT(val, 0, 0x7f); + w83795_write(client, W83795_REG_CTFS(index), val); + break; + case TEMP_PWM_HCT: + val = SENSORS_LIMIT(val, 0, 0x0f); + tmp = w83795_read(client, W83795_REG_HT(index)); + tmp &= 0x0f; + tmp |= (val << 4) & 0xf0; + w83795_write(client, W83795_REG_HT(index), tmp); + break; + case TEMP_PWM_HOT: + val = SENSORS_LIMIT(val, 0, 0x0f); + tmp = w83795_read(client, W83795_REG_HT(index)); + tmp &= 0xf0; + tmp |= val & 0x0f; + w83795_write(client, W83795_REG_HT(index), tmp); + break; + } + data->pwm_temp[index][nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t +show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + + return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); +} + +static ssize_t +store_sf4_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); + data->sf4_reg[index][SF4_PWM][nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t +show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + + return sprintf(buf, "%u\n", + (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); +} + +static ssize_t +store_sf4_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + val /= 1000; + + mutex_lock(&data->update_lock); + w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); + data->sf4_reg[index][SF4_TEMP][nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + + +static ssize_t +show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct w83795_data *data = w83795_update_device(dev); + long temp = temp_from_reg(data->temp[index][nr] & 0x7f); + + if (TEMP_READ == nr) + temp += ((data->temp_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) + * 250; + if (data->temp[index][nr] & 0x80) + temp = -temp; + return sprintf(buf, "%ld\n", temp); +} + +static ssize_t +store_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + long tmp; + + if (strict_strtol(buf, 10, &tmp) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->temp[index][nr] = temp_to_reg(tmp, -128, 127); + w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); + mutex_unlock(&data->update_lock); + return count; +} + + +static ssize_t +show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + u8 tmp; + + if (data->enable_dts == 0) + return sprintf(buf, "%d\n", 0); + + if ((data->has_dts >> index) & 0x01) { + if (data->enable_dts & 2) + tmp = 5; + else + tmp = 6; + } else { + tmp = 0; + } + + return sprintf(buf, "%d\n", tmp); +} + +static ssize_t +show_dts(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + struct w83795_data *data = w83795_update_device(dev); + long temp = temp_from_reg(data->dts[index] & 0x7f); + + temp += ((data->dts_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250; + if (data->dts[index] & 0x80) + temp = -temp; + return sprintf(buf, "%ld\n", temp); +} + +static ssize_t +show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + long temp = temp_from_reg(data->dts_ext[nr] & 0x7f); + + if (data->dts_ext[nr] & 0x80) + temp = -temp; + return sprintf(buf, "%ld\n", temp); +} + +static ssize_t +store_dts_ext(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + long tmp; + + if (strict_strtol(buf, 10, &tmp) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); + w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); + mutex_unlock(&data->update_lock); + return count; +} + + +/* + Type 3: Thermal diode + Type 4: Thermistor + + Temp5-6, default TR + Temp1-4, default TD +*/ + +static ssize_t +show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + u8 tmp; + + if (data->has_temp >> index & 0x01) { + if (data->temp_mode >> index & 0x01) + tmp = 3; + else + tmp = 4; + } else { + tmp = 0; + } + + return sprintf(buf, "%d\n", tmp); +} + +static ssize_t +store_temp_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int index = sensor_attr->index; + unsigned long val; + u8 tmp; + u32 mask; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + if ((val != 4) && (val != 3)) + return -EINVAL; + if ((index > 3) && (val == 3)) + return -EINVAL; + + mutex_lock(&data->update_lock); + if (val == 3) { + val = TEMP_CTRL_TD; + data->has_temp |= 1 << index; + data->temp_mode |= 1 << index; + } else if (val == 4) { + val = TEMP_CTRL_TR; + data->has_temp |= 1 << index; + tmp = 1 << index; + data->temp_mode &= ~tmp; + } + + if (index > 3) + tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); + else + tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); + + mask = 0x03 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_SHIFT]; + tmp &= ~mask; + tmp |= W83795_REG_TEMP_CTRL[index][val]; + + mask = 1 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_HASIN_SHIFT]; + data->has_in &= ~mask; + + if (index > 3) + w83795_write(client, W83795_REG_TEMP_CTRL1, tmp); + else + w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); + + mutex_unlock(&data->update_lock); + return count; +} + + +/* show/store VIN */ +static ssize_t +show_in(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct w83795_data *data = w83795_update_device(dev); + u16 val = data->in[index][nr]; + u8 lsb_idx; + + switch (nr) { + case IN_READ: + /* calculate this value again by sensors as sensors3.conf */ + if ((index >= 17) && + ((data->has_gain >> (index - 17)) & 1)) + val *= 8; + break; + case IN_MAX: + case IN_LOW: + lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; + val <<= 2; + val |= (data->in_lsb[lsb_idx][nr] >> + IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; + if ((index >= 17) && + ((data->has_gain >> (index - 17)) & 1)) + val *= 8; + break; + } + val = in_from_reg(index, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t +store_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + unsigned long val; + u8 tmp; + u8 lsb_idx; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + val = in_to_reg(index, val); + + if ((index >= 17) && + ((data->has_gain >> (index - 17)) & 1)) + val /= 8; + val = SENSORS_LIMIT(val, 0, 0x3FF); + mutex_lock(&data->update_lock); + + lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; + tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); + tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); + tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; + w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); + data->in_lsb[lsb_idx][nr] = tmp; + + tmp = (val >> 2) & 0xff; + w83795_write(client, W83795_REG_IN[index][nr], tmp); + data->in[index][nr] = tmp; + + mutex_unlock(&data->update_lock); + return count; +} + + +static ssize_t +show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + u16 val = data->setup_pwm[nr]; + + switch (nr) { + case SETUP_PWM_UPTIME: + case SETUP_PWM_DOWNTIME: + val = time_from_reg(val); + break; + } + + return sprintf(buf, "%d\n", val); +} + +static ssize_t +store_sf_setup(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + struct i2c_client *client = to_i2c_client(dev); + struct w83795_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + switch (nr) { + case SETUP_PWM_DEFAULT: + val = SENSORS_LIMIT(val, 0, 0xff); + break; + case SETUP_PWM_UPTIME: + case SETUP_PWM_DOWNTIME: + val = time_to_reg(val); + if (val == 0) + return -EINVAL; + break; + } + + mutex_lock(&data->update_lock); + data->setup_pwm[nr] = val; + w83795_write(client, W83795_REG_SETUP_PWM(nr), val); + mutex_unlock(&data->update_lock); + return count; +} + + +#define NOT_USED -1 + +#define SENSOR_ATTR_IN(index) \ + SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ + IN_READ, index), \ + SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ + store_in, IN_MAX, index), \ + SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ + store_in, IN_LOW, index), \ + SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ + NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ + SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ + show_alarm_beep, store_beep, BEEP_ENABLE, \ + index + ((index > 14) ? 1 : 0)) + +#define SENSOR_ATTR_FAN(index) \ + SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ + NULL, FAN_INPUT, index - 1), \ + SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ + show_fan, store_fan_min, FAN_MIN, index - 1), \ + SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ + NULL, ALARM_STATUS, index + 31), \ + SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ + show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) + +#define SENSOR_ATTR_PWM(index) \ + SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ + store_pwm, PWM_OUTPUT, index - 1), \ + SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ + show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ + SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ + show_pwm, store_pwm, PWM_START, index - 1), \ + SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ + show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ + SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \ + show_pwm, store_pwm, PWM_DIV, index - 1), \ + SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ + show_pwm_enable, store_pwm_enable, NOT_USED, index - 1) + +#define SENSOR_ATTR_FANIN_TARGET(index) \ + SENSOR_ATTR_2(speed_cruise##index##_target, S_IWUSR | S_IRUGO, \ + show_fanin, store_fanin, FANIN_TARGET, index - 1) + +#define SENSOR_ATTR_DTS(index) \ + SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ + show_dts_mode, NULL, NOT_USED, index - 7), \ + SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ + NULL, NOT_USED, index - 7), \ + SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ + store_dts_ext, DTS_CRIT, NOT_USED), \ + SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ + show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ + SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_dts_ext, \ + store_dts_ext, DTS_WARN, NOT_USED), \ + SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ + show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ + SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ + show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ + SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ + show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) + +#define SENSOR_ATTR_TEMP(index) \ + SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \ + show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ + SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ + NULL, TEMP_READ, index - 1), \ + SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ + store_temp, TEMP_CRIT, index - 1), \ + SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ + SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \ + store_temp, TEMP_WARN, index - 1), \ + SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ + show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ + SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ + show_alarm_beep, NULL, ALARM_STATUS, \ + index + (index > 4 ? 11 : 17)), \ + SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ + show_alarm_beep, store_beep, BEEP_ENABLE, \ + index + (index > 4 ? 11 : 17)), \ + SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \ + show_temp_src, store_temp_src, NOT_USED, index - 1), \ + SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ + show_temp_pwm_enable, store_temp_pwm_enable, \ + TEMP_PWM_ENABLE, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ + show_temp_pwm_enable, store_temp_pwm_enable, \ + TEMP_PWM_FAN_MAP, index - 1), \ + SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ + show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ + SENSOR_ATTR_2(temp##index##_crit, S_IWUSR | S_IRUGO, \ + show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ + SENSOR_ATTR_2(temp##index##_crit_hyst, S_IWUSR | S_IRUGO, \ + show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ + SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ + show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ + show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 0, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 1, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 2, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 3, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 4, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 5, index - 1), \ + SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ + show_sf4_temp, store_sf4_temp, 6, index - 1) + + +static struct sensor_device_attribute_2 w83795_in[] = { + SENSOR_ATTR_IN(0), + SENSOR_ATTR_IN(1), + SENSOR_ATTR_IN(2), + SENSOR_ATTR_IN(3), + SENSOR_ATTR_IN(4), + SENSOR_ATTR_IN(5), + SENSOR_ATTR_IN(6), + SENSOR_ATTR_IN(7), + SENSOR_ATTR_IN(8), + SENSOR_ATTR_IN(9), + SENSOR_ATTR_IN(10), + SENSOR_ATTR_IN(11), + SENSOR_ATTR_IN(12), + SENSOR_ATTR_IN(13), + SENSOR_ATTR_IN(14), + SENSOR_ATTR_IN(15), + SENSOR_ATTR_IN(16), + SENSOR_ATTR_IN(17), + SENSOR_ATTR_IN(18), + SENSOR_ATTR_IN(19), + SENSOR_ATTR_IN(20), +}; + +static struct sensor_device_attribute_2 w83795_fan[] = { + SENSOR_ATTR_FAN(1), + SENSOR_ATTR_FAN(2), + SENSOR_ATTR_FAN(3), + SENSOR_ATTR_FAN(4), + SENSOR_ATTR_FAN(5), + SENSOR_ATTR_FAN(6), + SENSOR_ATTR_FAN(7), + SENSOR_ATTR_FAN(8), + SENSOR_ATTR_FAN(9), + SENSOR_ATTR_FAN(10), + SENSOR_ATTR_FAN(11), + SENSOR_ATTR_FAN(12), + SENSOR_ATTR_FAN(13), + SENSOR_ATTR_FAN(14), +}; + +static struct sensor_device_attribute_2 w83795_temp[] = { + SENSOR_ATTR_TEMP(1), + SENSOR_ATTR_TEMP(2), + SENSOR_ATTR_TEMP(3), + SENSOR_ATTR_TEMP(4), + SENSOR_ATTR_TEMP(5), + SENSOR_ATTR_TEMP(6), +}; + +static struct sensor_device_attribute_2 w83795_dts[] = { + SENSOR_ATTR_DTS(7), + SENSOR_ATTR_DTS(8), + SENSOR_ATTR_DTS(9), + SENSOR_ATTR_DTS(10), + SENSOR_ATTR_DTS(11), + SENSOR_ATTR_DTS(12), + SENSOR_ATTR_DTS(13), + SENSOR_ATTR_DTS(14), +}; + +static struct sensor_device_attribute_2 w83795_static[] = { + SENSOR_ATTR_FANIN_TARGET(1), + SENSOR_ATTR_FANIN_TARGET(2), + SENSOR_ATTR_FANIN_TARGET(3), + SENSOR_ATTR_FANIN_TARGET(4), + SENSOR_ATTR_FANIN_TARGET(5), + SENSOR_ATTR_FANIN_TARGET(6), + SENSOR_ATTR_FANIN_TARGET(7), + SENSOR_ATTR_FANIN_TARGET(8), + SENSOR_ATTR_PWM(1), + SENSOR_ATTR_PWM(2), +}; + +/* all registers existed in 795g than 795adg, + * like PWM3 - PWM8 */ +static struct sensor_device_attribute_2 w83795_left_reg[] = { + SENSOR_ATTR_PWM(3), + SENSOR_ATTR_PWM(4), + SENSOR_ATTR_PWM(5), + SENSOR_ATTR_PWM(6), + SENSOR_ATTR_PWM(7), + SENSOR_ATTR_PWM(8), +}; + +static struct sensor_device_attribute_2 sda_single_files[] = { + SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, + store_chassis_clear, ALARM_STATUS, 46), + SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, + store_beep_enable, NOT_USED, NOT_USED), + SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, + store_fanin, FANIN_TOL, NOT_USED), + SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, + store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), + SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, + store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), + SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, + store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), +}; + +/* + * Driver interface + */ + +static void w83795_init_client(struct i2c_client *client) +{ + if (reset) + w83795_write(client, W83795_REG_CONFIG, 0x80); + + /* Start monitoring */ + w83795_write(client, W83795_REG_CONFIG, + w83795_read(client, W83795_REG_CONFIG) | 0x01); +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int w83795_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + u8 tmp, bank; + struct i2c_adapter *adapter = client->adapter; + unsigned short address = client->addr; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); + + tmp = bank & 0x80 ? 0x5c : 0xa3; + /* Check Nuvoton vendor ID */ + if (tmp != i2c_smbus_read_byte_data(client, + W83795_REG_VENDORID)) { + pr_debug("w83795: Detection failed at check " + "vendor id\n"); + return -ENODEV; + } + + /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR + should match */ + if ((bank & 0x07) == 0 + && (i2c_smbus_read_byte_data(client, W83795_REG_I2C_ADDR) & 0x7f) != + address) { + pr_debug("w83795: Detection failed at check " + "i2c addr\n"); + return -ENODEV; + } + + /* Determine the chip type now */ + if (0x79 != i2c_smbus_read_byte_data(client, + W83795_REG_CHIPID)) { + pr_debug("w83795: Detection failed at check " + "chip id\n"); + return -ENODEV; + } + +#if 0 + /* Check 795 chip type: 795G or 795ADG */ + if (W83795_REG_CONFIG_CONFIG48 & + w83795_read(client, W83795_REG_CONFIG)) { + data->chip_type = w83795adg; + } else { + data->chip_type = w83795g; + } +#endif + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(info->type, "w83795", I2C_NAME_SIZE); + + return 0; +} + +static int w83795_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i; + u8 tmp; + struct device *dev = &client->dev; + struct w83795_data *data; + int err = 0; + + data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); + mutex_init(&data->update_lock); + + /* Initialize the chip */ + w83795_init_client(client); + + /* Check 795 chip type: 795G or 795ADG */ + if (W83795_REG_CONFIG_CONFIG48 & + w83795_read(client, W83795_REG_CONFIG)) { + data->chip_type = w83795adg; + } else { + data->chip_type = w83795g; + } + + data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1); + data->has_in |= w83795_read(client, W83795_REG_VOLT_CTRL2) << 8; + /* VSEN11-9 not for 795adg */ + if (data->chip_type == w83795adg) + data->has_in &= 0xf8ff; + data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1); + data->has_fan |= w83795_read(client, W83795_REG_FANIN_CTRL2) << 8; + + /* VDSEN12-17 and TR1-6, TD1-4 use same register */ + tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); + if (tmp & 0x20) + data->enable_dts = 1; + else + data->enable_dts = 0; + data->has_temp = 0; + data->temp_mode = 0; + if (tmp & 0x08) { + if (tmp & 0x04) + data->has_temp |= 0x20; + else + data->has_in |= 0x10000; + } + if (tmp & 0x02) { + if (tmp & 0x01) + data->has_temp |= 0x10; + else + data->has_in |= 0x8000; + } + tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); + if (tmp & 0x40) { + data->has_temp |= 0x08; + if (!(tmp & 0x80)) + data->temp_mode |= 0x08; + } else if (tmp & 0x80) { + data->has_in |= 0x100000; + } + if (tmp & 0x10) { + data->has_temp |= 0x04; + if (!(tmp & 0x20)) + data->temp_mode |= 0x04; + } else if (tmp & 0x20) { + data->has_in |= 0x80000; + } + if (tmp & 0x04) { + data->has_temp |= 0x02; + if (!(tmp & 0x08)) + data->temp_mode |= 0x02; + } else if (tmp & 0x08) { + data->has_in |= 0x40000; + } + if (tmp & 0x01) { + data->has_temp |= 0x01; + if (!(tmp & 0x02)) + data->temp_mode |= 0x01; + } else if (tmp & 0x02) { + data->has_in |= 0x20000; + } + + /* Check DTS enable status */ + if (data->enable_dts == 0) { + data->has_dts = 0; + } else { + if (1 & w83795_read(client, W83795_REG_DTSC)) + data->enable_dts |= 2; + data->has_dts = w83795_read(client, W83795_REG_DTSE); + } + + /* First update the voltages measured value and limits */ + for (i = 0; i < ARRAY_SIZE(data->in); i++) { + if (!(data->has_in & (1 << i))) + continue; + data->in[i][IN_MAX] = + w83795_read(client, W83795_REG_IN[i][IN_MAX]); + data->in[i][IN_LOW] = + w83795_read(client, W83795_REG_IN[i][IN_LOW]); + tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; + tmp |= (w83795_read(client, W83795_REG_VRLSB) + >> VRLSB_SHIFT) & 0x03; + data->in[i][IN_READ] = tmp; + } + for (i = 0; i < IN_LSB_REG_NUM; i++) { + data->in_lsb[i][IN_MAX] = + w83795_read(client, IN_LSB_REG(i, IN_MAX)); + data->in_lsb[i][IN_LOW] = + w83795_read(client, IN_LSB_REG(i, IN_LOW)); + } + data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; + + /* First update fan and limits */ + for (i = 0; i < ARRAY_SIZE(data->fan); i++) { + if (!(data->has_fan & (1 << i))) + continue; + data->fan_min[i] = + w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; + data->fan_min[i] |= + (w83795_read(client, W83795_REG_FAN_MIN_LSB(i) >> + W83795_REG_FAN_MIN_LSB_SHIFT(i))) & 0x0F; + data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; + data->fan[i] |= + (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F; + } + + /* temperature and limits */ + for (i = 0; i < ARRAY_SIZE(data->temp); i++) { + if (!(data->has_temp & (1 << i))) + continue; + data->temp[i][TEMP_CRIT] = + w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT]); + data->temp[i][TEMP_CRIT_HYST] = + w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT_HYST]); + data->temp[i][TEMP_WARN] = + w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN]); + data->temp[i][TEMP_WARN_HYST] = + w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]); + data->temp[i][TEMP_READ] = + w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); + data->temp_read_vrlsb[i] = + w83795_read(client, W83795_REG_VRLSB); + } + + /* dts temperature and limits */ + if (data->enable_dts != 0) { + data->dts_ext[DTS_CRIT] = + w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT)); + data->dts_ext[DTS_CRIT_HYST] = + w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT_HYST)); + data->dts_ext[DTS_WARN] = + w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN)); + data->dts_ext[DTS_WARN_HYST] = + w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN_HYST)); + for (i = 0; i < ARRAY_SIZE(data->dts); i++) { + if (!(data->has_dts & (1 << i))) + continue; + data->dts[i] = w83795_read(client, W83795_REG_DTS(i)); + data->dts_read_vrlsb[i] = + w83795_read(client, W83795_REG_VRLSB); + } + } + + /* First update temp source selction */ + for (i = 0; i < 3; i++) + data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); + + /* pwm and smart fan */ + if (data->chip_type == w83795g) + data->has_pwm = 8; + else + data->has_pwm = 2; + data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); + data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); + /* w83795adg only support pwm2-0 */ + for (i = 0; i < W83795_REG_TEMP_NUM; i++) + data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); + data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); + for (i = 0; i < data->has_pwm; i++) { + for (tmp = 0; tmp < 5; tmp++) { + data->pwm[i][tmp] = + w83795_read(client, W83795_REG_PWM(i, tmp)); + } + } + for (i = 0; i < 8; i++) { + data->target_speed[i] = + w83795_read(client, W83795_REG_FTSH(i)) << 4; + data->target_speed[i] |= + w83795_read(client, W83795_REG_FTSL(i)) >> 4; + } + data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; + + for (i = 0; i < W83795_REG_TEMP_NUM; i++) { + data->pwm_temp[i][TEMP_PWM_TTTI] = + w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; + data->pwm_temp[i][TEMP_PWM_CTFS] = + w83795_read(client, W83795_REG_CTFS(i)); + tmp = w83795_read(client, W83795_REG_HT(i)); + data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; + data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; + } + for (i = 0; i < W83795_REG_TEMP_NUM; i++) { + for (tmp = 0; tmp < 7; tmp++) { + data->sf4_reg[i][SF4_TEMP][tmp] = + w83795_read(client, + W83795_REG_SF4_TEMP(i, tmp)); + data->sf4_reg[i][SF4_PWM][tmp] = + w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); + } + } + + /* Setup PWM Register */ + for (i = 0; i < 3; i++) { + data->setup_pwm[i] = + w83795_read(client, W83795_REG_SETUP_PWM(i)); + } + + /* alarm and beep */ + for (i = 0; i < ALARM_BEEP_REG_NUM; i++) { + data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); + data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); + } + data->beep_enable = + (w83795_read(client, W83795_REG_BEEP(5)) >> 7) & 0x01; + + /* Register sysfs hooks */ + for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { + if (!(data->has_in & (1 << (i / 6)))) + continue; + err = device_create_file(dev, &w83795_in[i].dev_attr); + if (err) + goto exit_remove; + } + + for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { + if (!(data->has_fan & (1 << (i / 5)))) + continue; + err = device_create_file(dev, &w83795_fan[i].dev_attr); + if (err) + goto exit_remove; + } + + for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { + err = device_create_file(dev, &sda_single_files[i].dev_attr); + if (err) + goto exit_remove; + } + + for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { + if (!(data->has_temp & (1 << (i / 29)))) + continue; + err = device_create_file(dev, &w83795_temp[i].dev_attr); + if (err) + goto exit_remove; + } + + if (data->enable_dts != 0) { + for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { + if (!(data->has_dts & (1 << (i / 8)))) + continue; + err = device_create_file(dev, &w83795_dts[i].dev_attr); + if (err) + goto exit_remove; + } + } + + if (data->chip_type == w83795g) { + for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) { + err = device_create_file(dev, + &w83795_left_reg[i].dev_attr); + if (err) + goto exit_remove; + } + } + + for (i = 0; i < ARRAY_SIZE(w83795_static); i++) { + err = device_create_file(dev, &w83795_static[i].dev_attr); + if (err) + goto exit_remove; + } + + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + + /* Unregister sysfs hooks */ +exit_remove: + for (i = 0; i < ARRAY_SIZE(w83795_in); i++) + device_remove_file(dev, &w83795_in[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) + device_remove_file(dev, &w83795_fan[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) + device_remove_file(dev, &sda_single_files[i].dev_attr); + + if (data->chip_type == w83795g) { + for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) + device_remove_file(dev, &w83795_left_reg[i].dev_attr); + } + + for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) + device_remove_file(dev, &w83795_temp[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) + device_remove_file(dev, &w83795_dts[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_static); i++) + device_remove_file(dev, &w83795_static[i].dev_attr); + + kfree(data); +exit: + return err; +} + +static int w83795_remove(struct i2c_client *client) +{ + struct w83795_data *data = i2c_get_clientdata(client); + struct device *dev = &client->dev; + int i; + + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(w83795_in); i++) + device_remove_file(dev, &w83795_in[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) + device_remove_file(dev, &w83795_fan[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) + device_remove_file(dev, &sda_single_files[i].dev_attr); + + if (data->chip_type == w83795g) { + for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) + device_remove_file(dev, &w83795_left_reg[i].dev_attr); + } + + for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) + device_remove_file(dev, &w83795_temp[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) + device_remove_file(dev, &w83795_dts[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_static); i++) + device_remove_file(dev, &w83795_static[i].dev_attr); + + kfree(data); + + return 0; +} + + +static const struct i2c_device_id w83795_id[] = { + { "w83795", w83795 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, w83795_id); + +static struct i2c_driver w83795_driver = { + .driver = { + .name = "w83795", + }, + .probe = w83795_probe, + .remove = w83795_remove, + .id_table = w83795_id, + + .class = I2C_CLASS_HWMON, + .detect = w83795_detect, + .address_list = normal_i2c, +}; + +static int __init sensors_w83795_init(void) +{ + return i2c_add_driver(&w83795_driver); +} + +static void __exit sensors_w83795_exit(void) +{ + i2c_del_driver(&w83795_driver); +} + +MODULE_AUTHOR("Wei Song"); +MODULE_DESCRIPTION("w83795 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83795_init); +module_exit(sensors_w83795_exit); -- cgit v1.2.3 From 315bacfdbe5a77309c256b296f30bee13d59462b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Misc cleanups * Improve driver description. * Drop unused macro. * Drop unreachable code. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index c6984c817067..7b93ac296d03 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -183,8 +183,6 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) #define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ (((index) % 1) ? 4 : 0) -#define W83795_REG_FAN_CTRL_SHIFT(index) \ - (((index) > 7) ? ((index) - 8) : (index)) #define W83795_REG_VID_CTRL 0x6A @@ -793,9 +791,6 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, } mutex_unlock(&data->update_lock); return count; - - mutex_unlock(&data->update_lock); - return -EINVAL; } static ssize_t @@ -2131,7 +2126,7 @@ static void __exit sensors_w83795_exit(void) } MODULE_AUTHOR("Wei Song"); -MODULE_DESCRIPTION("w83795 driver"); +MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); MODULE_LICENSE("GPL"); module_init(sensors_w83795_init); -- cgit v1.2.3 From 093d1a4794cc23dd221019eb1cdf42b16b48abcc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Drop duplicate enum Enum chips and chip_types are redundant, get rid of the former. Fix the detection code to properly identify the chip variant and name the client accordingly. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 7b93ac296d03..d7e1d3693a20 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -38,8 +38,6 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -enum chips { w83795 }; - static int reset; module_param(reset, bool, 0); @@ -1686,6 +1684,7 @@ static int w83795_detect(struct i2c_client *client, u8 tmp, bank; struct i2c_adapter *adapter = client->adapter; unsigned short address = client->addr; + const char *chip_name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -1718,18 +1717,21 @@ static int w83795_detect(struct i2c_client *client, return -ENODEV; } -#if 0 - /* Check 795 chip type: 795G or 795ADG */ + /* Check 795 chip type: 795G or 795ADG + Usually we don't write to chips during detection, but here we don't + quite have the choice; hopefully it's OK, we are about to return + success anyway */ + if ((bank & 0x07) != 0) + i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, + bank & ~0x07); if (W83795_REG_CONFIG_CONFIG48 & - w83795_read(client, W83795_REG_CONFIG)) { - data->chip_type = w83795adg; + i2c_smbus_read_byte_data(client, W83795_REG_CONFIG)) { + chip_name = "w83795adg"; } else { - data->chip_type = w83795g; + chip_name = "w83795g"; } -#endif - /* Fill in the remaining client fields and put into the global list */ - strlcpy(info->type, "w83795", I2C_NAME_SIZE); + strlcpy(info->type, chip_name, I2C_NAME_SIZE); return 0; } @@ -1750,20 +1752,13 @@ static int w83795_probe(struct i2c_client *client, } i2c_set_clientdata(client, data); + data->chip_type = id->driver_data; data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); mutex_init(&data->update_lock); /* Initialize the chip */ w83795_init_client(client); - /* Check 795 chip type: 795G or 795ADG */ - if (W83795_REG_CONFIG_CONFIG48 & - w83795_read(client, W83795_REG_CONFIG)) { - data->chip_type = w83795adg; - } else { - data->chip_type = w83795g; - } - data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1); data->has_in |= w83795_read(client, W83795_REG_VOLT_CTRL2) << 8; /* VSEN11-9 not for 795adg */ @@ -2097,7 +2092,8 @@ static int w83795_remove(struct i2c_client *client) static const struct i2c_device_id w83795_id[] = { - { "w83795", w83795 }, + { "w83795g", w83795g }, + { "w83795adg", w83795adg }, { } }; MODULE_DEVICE_TABLE(i2c, w83795_id); -- cgit v1.2.3 From b2469f422f9ee2054359c4ec609c3bdb1f2d52f5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Refactor bank selection Move the bank selection code to a separate function, to avoid duplicating it in read and write functions. Improve error reporting on register access error. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 93 +++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 43 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index d7e1d3693a20..c7f6b1fd0899 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -360,60 +360,67 @@ struct w83795_data { /* * Hardware access + * We assume that nobdody can change the bank outside the driver. */ -/* Ignore the possibility that somebody change bank outside the driver - * Must be called with data->update_lock held, except during initialization */ -static u8 w83795_read(struct i2c_client *client, u16 reg) +/* Must be called with data->update_lock held, except during initialization */ +static int w83795_set_bank(struct i2c_client *client, u8 bank) { struct w83795_data *data = i2c_get_clientdata(client); - u8 res = 0xff; - u8 new_bank = reg >> 8; - - new_bank |= data->bank & 0xfc; - if (data->bank != new_bank) { - if (i2c_smbus_write_byte_data - (client, W83795_REG_BANKSEL, new_bank) >= 0) - data->bank = new_bank; - else { - dev_err(&client->dev, - "set bank to %d failed, fall back " - "to bank %d, read reg 0x%x error\n", - new_bank, data->bank, reg); - res = 0x0; /* read 0x0 from the chip */ - goto END; - } + int err; + + /* If the same bank is already set, nothing to do */ + if ((data->bank & 0x07) == bank) + return 0; + + /* Change to new bank, preserve all other bits */ + bank |= data->bank & ~0x07; + err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); + if (err < 0) { + dev_err(&client->dev, + "Failed to set bank to %d, err %d\n", + (int)bank, err); + return err; } - res = i2c_smbus_read_byte_data(client, reg & 0xff); -END: - return res; + data->bank = bank; + + return 0; } /* Must be called with data->update_lock held, except during initialization */ -static int w83795_write(struct i2c_client *client, u16 reg, u8 value) +static u8 w83795_read(struct i2c_client *client, u16 reg) { - struct w83795_data *data = i2c_get_clientdata(client); - int res; - u8 new_bank = reg >> 8; - - new_bank |= data->bank & 0xfc; - if (data->bank != new_bank) { - res = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, - new_bank); - if (res >= 0) - data->bank = new_bank; - else { - dev_err(&client->dev, - "set bank to %d failed, fall back " - "to bank %d, write reg 0x%x error\n", - new_bank, data->bank, reg); - goto END; - } + int err; + + err = w83795_set_bank(client, reg >> 8); + if (err < 0) + return 0x00; /* Arbitrary */ + + err = i2c_smbus_read_byte_data(client, reg & 0xff); + if (err < 0) { + dev_err(&client->dev, + "Failed to read from register 0x%03x, err %d\n", + (int)reg, err); + return 0x00; /* Arbitrary */ } + return err; +} - res = i2c_smbus_write_byte_data(client, reg & 0xff, value); -END: - return res; +/* Must be called with data->update_lock held, except during initialization */ +static int w83795_write(struct i2c_client *client, u16 reg, u8 value) +{ + int err; + + err = w83795_set_bank(client, reg >> 8); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(client, reg & 0xff, value); + if (err < 0) + dev_err(&client->dev, + "Failed to write to register 0x%03x, err %d\n", + (int)reg, err); + return err; } static struct w83795_data *w83795_update_device(struct device *dev) -- cgit v1.2.3 From 2be381de0f1e5e0324e8b373e7a84fc9d25d05d3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Improve detection routine Check for additional identification registers. Improve debugging messages on failed detection. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 80 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 23 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index c7f6b1fd0899..6596303566e1 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -48,6 +48,7 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); #define W83795_REG_VENDORID 0xfd #define W83795_REG_CHIPID 0xfe #define W83795_REG_DEVICEID 0xfb +#define W83795_REG_DEVICEID_A 0xff #define W83795_REG_I2C_ADDR 0xfc #define W83795_REG_CONFIG 0x01 @@ -1684,11 +1685,31 @@ static void w83795_init_client(struct i2c_client *client) w83795_read(client, W83795_REG_CONFIG) | 0x01); } +static int w83795_get_device_id(struct i2c_client *client) +{ + int device_id; + + device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); + + /* Special case for rev. A chips; can't be checked first because later + revisions emulate this for compatibility */ + if (device_id < 0 || (device_id & 0xf0) != 0x50) { + int alt_id; + + alt_id = i2c_smbus_read_byte_data(client, + W83795_REG_DEVICEID_A); + if (alt_id == 0x50) + device_id = alt_id; + } + + return device_id; +} + /* Return 0 if detection is successful, -ENODEV otherwise */ static int w83795_detect(struct i2c_client *client, struct i2c_board_info *info) { - u8 tmp, bank; + int bank, vendor_id, device_id, expected, i2c_addr, config; struct i2c_adapter *adapter = client->adapter; unsigned short address = client->addr; const char *chip_name; @@ -1696,32 +1717,44 @@ static int w83795_detect(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); + if (bank < 0 || (bank & 0x7c)) { + dev_dbg(&adapter->dev, + "w83795: Detection failed at addr 0x%02hx, check %s\n", + address, "bank"); + return -ENODEV; + } - tmp = bank & 0x80 ? 0x5c : 0xa3; /* Check Nuvoton vendor ID */ - if (tmp != i2c_smbus_read_byte_data(client, - W83795_REG_VENDORID)) { - pr_debug("w83795: Detection failed at check " - "vendor id\n"); + vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); + expected = bank & 0x80 ? 0x5c : 0xa3; + if (vendor_id != expected) { + dev_dbg(&adapter->dev, + "w83795: Detection failed at addr 0x%02hx, check %s\n", + address, "vendor id"); return -ENODEV; } - /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR - should match */ - if ((bank & 0x07) == 0 - && (i2c_smbus_read_byte_data(client, W83795_REG_I2C_ADDR) & 0x7f) != - address) { - pr_debug("w83795: Detection failed at check " - "i2c addr\n"); + /* Check device ID */ + device_id = w83795_get_device_id(client) | + (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); + if ((device_id >> 4) != 0x795) { + dev_dbg(&adapter->dev, + "w83795: Detection failed at addr 0x%02hx, check %s\n", + address, "device id\n"); return -ENODEV; } - /* Determine the chip type now */ - if (0x79 != i2c_smbus_read_byte_data(client, - W83795_REG_CHIPID)) { - pr_debug("w83795: Detection failed at check " - "chip id\n"); - return -ENODEV; + /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR + should match */ + if ((bank & 0x07) == 0) { + i2c_addr = i2c_smbus_read_byte_data(client, + W83795_REG_I2C_ADDR); + if ((i2c_addr & 0x7f) != address) { + dev_dbg(&adapter->dev, + "w83795: Detection failed at addr 0x%02hx, " + "check %s\n", address, "i2c addr"); + return -ENODEV; + } } /* Check 795 chip type: 795G or 795ADG @@ -1731,14 +1764,15 @@ static int w83795_detect(struct i2c_client *client, if ((bank & 0x07) != 0) i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank & ~0x07); - if (W83795_REG_CONFIG_CONFIG48 & - i2c_smbus_read_byte_data(client, W83795_REG_CONFIG)) { + config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); + if (config & W83795_REG_CONFIG_CONFIG48) chip_name = "w83795adg"; - } else { + else chip_name = "w83795g"; - } strlcpy(info->type, chip_name, I2C_NAME_SIZE); + dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, + 'A' + (device_id & 0xf), address); return 0; } -- cgit v1.2.3 From 2fa09878ba1dc458b8cb6e9c8fbc8f2e5401d2b2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Move files removal to a separate function Sysfs files must be removed on device removal but also when device registration fails. Move the code to a separate function to avoid code redundancy. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 81 +++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 50 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 6596303566e1..00d539a74d0c 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1777,6 +1777,35 @@ static int w83795_detect(struct i2c_client *client, return 0; } +static void w83795_remove_files(struct device *dev) +{ + struct w83795_data *data = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(w83795_in); i++) + device_remove_file(dev, &w83795_in[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) + device_remove_file(dev, &w83795_fan[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) + device_remove_file(dev, &sda_single_files[i].dev_attr); + + if (data->chip_type == w83795g) { + for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) + device_remove_file(dev, &w83795_left_reg[i].dev_attr); + } + + for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) + device_remove_file(dev, &w83795_temp[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) + device_remove_file(dev, &w83795_dts[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83795_static); i++) + device_remove_file(dev, &w83795_static[i].dev_attr); +} + static int w83795_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2065,31 +2094,8 @@ static int w83795_probe(struct i2c_client *client, return 0; - /* Unregister sysfs hooks */ exit_remove: - for (i = 0; i < ARRAY_SIZE(w83795_in); i++) - device_remove_file(dev, &w83795_in[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) - device_remove_file(dev, &w83795_fan[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) - device_remove_file(dev, &sda_single_files[i].dev_attr); - - if (data->chip_type == w83795g) { - for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) - device_remove_file(dev, &w83795_left_reg[i].dev_attr); - } - - for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) - device_remove_file(dev, &w83795_temp[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) - device_remove_file(dev, &w83795_dts[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_static); i++) - device_remove_file(dev, &w83795_static[i].dev_attr); - + w83795_remove_files(dev); kfree(data); exit: return err; @@ -2098,34 +2104,9 @@ exit: static int w83795_remove(struct i2c_client *client) { struct w83795_data *data = i2c_get_clientdata(client); - struct device *dev = &client->dev; - int i; hwmon_device_unregister(data->hwmon_dev); - - for (i = 0; i < ARRAY_SIZE(w83795_in); i++) - device_remove_file(dev, &w83795_in[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) - device_remove_file(dev, &w83795_fan[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) - device_remove_file(dev, &sda_single_files[i].dev_attr); - - if (data->chip_type == w83795g) { - for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) - device_remove_file(dev, &w83795_left_reg[i].dev_attr); - } - - for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) - device_remove_file(dev, &w83795_temp[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) - device_remove_file(dev, &w83795_dts[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_static); i++) - device_remove_file(dev, &w83795_static[i].dev_attr); - + w83795_remove_files(&client->dev); kfree(data); return 0; -- cgit v1.2.3 From 892514a6372d49ffe9749fb86cc587b4dce90733 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Move file creation to a separate function too Function w83795_probe() is way too big, move file creation to a separate function to make it more readable. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 121 +++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 55 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 00d539a74d0c..309e2e5a187e 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1777,6 +1777,69 @@ static int w83795_detect(struct i2c_client *client, return 0; } +static int w83795_create_files(struct device *dev) +{ + struct w83795_data *data = dev_get_drvdata(dev); + int err, i; + + for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { + if (!(data->has_in & (1 << (i / 6)))) + continue; + err = device_create_file(dev, &w83795_in[i].dev_attr); + if (err) + return err; + } + + for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { + if (!(data->has_fan & (1 << (i / 5)))) + continue; + err = device_create_file(dev, &w83795_fan[i].dev_attr); + if (err) + return err; + } + + for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { + err = device_create_file(dev, &sda_single_files[i].dev_attr); + if (err) + return err; + } + + if (data->chip_type == w83795g) { + for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) { + err = device_create_file(dev, + &w83795_left_reg[i].dev_attr); + if (err) + return err; + } + } + + for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { + if (!(data->has_temp & (1 << (i / 29)))) + continue; + err = device_create_file(dev, &w83795_temp[i].dev_attr); + if (err) + return err; + } + + if (data->enable_dts != 0) { + for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { + if (!(data->has_dts & (1 << (i / 8)))) + continue; + err = device_create_file(dev, &w83795_dts[i].dev_attr); + if (err) + return err; + } + } + + for (i = 0; i < ARRAY_SIZE(w83795_static); i++) { + err = device_create_file(dev, &w83795_static[i].dev_attr); + if (err) + return err; + } + + return 0; +} + static void w83795_remove_files(struct device *dev) { struct w83795_data *data = dev_get_drvdata(dev); @@ -2030,61 +2093,9 @@ static int w83795_probe(struct i2c_client *client, data->beep_enable = (w83795_read(client, W83795_REG_BEEP(5)) >> 7) & 0x01; - /* Register sysfs hooks */ - for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { - if (!(data->has_in & (1 << (i / 6)))) - continue; - err = device_create_file(dev, &w83795_in[i].dev_attr); - if (err) - goto exit_remove; - } - - for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { - if (!(data->has_fan & (1 << (i / 5)))) - continue; - err = device_create_file(dev, &w83795_fan[i].dev_attr); - if (err) - goto exit_remove; - } - - for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { - err = device_create_file(dev, &sda_single_files[i].dev_attr); - if (err) - goto exit_remove; - } - - for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { - if (!(data->has_temp & (1 << (i / 29)))) - continue; - err = device_create_file(dev, &w83795_temp[i].dev_attr); - if (err) - goto exit_remove; - } - - if (data->enable_dts != 0) { - for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { - if (!(data->has_dts & (1 << (i / 8)))) - continue; - err = device_create_file(dev, &w83795_dts[i].dev_attr); - if (err) - goto exit_remove; - } - } - - if (data->chip_type == w83795g) { - for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) { - err = device_create_file(dev, - &w83795_left_reg[i].dev_attr); - if (err) - goto exit_remove; - } - } - - for (i = 0; i < ARRAY_SIZE(w83795_static); i++) { - err = device_create_file(dev, &w83795_static[i].dev_attr); - if (err) - goto exit_remove; - } + err = w83795_create_files(dev); + if (err) + goto exit_remove; data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { -- cgit v1.2.3 From 6f3dcde9c6dcbbe781a2a98900552bcb989733e3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Merge w83795_create_files and w83795_remove_files Functions w83795_create_files and w83795_remove_files iterate over the same set of files, just calling a different function. Merge them into a single function which takes the action as a parameter. This saves code, and also ensure that file creation and deletion are in sync. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 55 ++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 309e2e5a187e..ca8b0aec53e6 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1777,7 +1777,8 @@ static int w83795_detect(struct i2c_client *client, return 0; } -static int w83795_create_files(struct device *dev) +static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, + const struct device_attribute *)) { struct w83795_data *data = dev_get_drvdata(dev); int err, i; @@ -1785,7 +1786,7 @@ static int w83795_create_files(struct device *dev) for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { if (!(data->has_in & (1 << (i / 6)))) continue; - err = device_create_file(dev, &w83795_in[i].dev_attr); + err = fn(dev, &w83795_in[i].dev_attr); if (err) return err; } @@ -1793,21 +1794,20 @@ static int w83795_create_files(struct device *dev) for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { if (!(data->has_fan & (1 << (i / 5)))) continue; - err = device_create_file(dev, &w83795_fan[i].dev_attr); + err = fn(dev, &w83795_fan[i].dev_attr); if (err) return err; } for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { - err = device_create_file(dev, &sda_single_files[i].dev_attr); + err = fn(dev, &sda_single_files[i].dev_attr); if (err) return err; } if (data->chip_type == w83795g) { for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) { - err = device_create_file(dev, - &w83795_left_reg[i].dev_attr); + err = fn(dev, &w83795_left_reg[i].dev_attr); if (err) return err; } @@ -1816,7 +1816,7 @@ static int w83795_create_files(struct device *dev) for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { if (!(data->has_temp & (1 << (i / 29)))) continue; - err = device_create_file(dev, &w83795_temp[i].dev_attr); + err = fn(dev, &w83795_temp[i].dev_attr); if (err) return err; } @@ -1825,14 +1825,14 @@ static int w83795_create_files(struct device *dev) for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { if (!(data->has_dts & (1 << (i / 8)))) continue; - err = device_create_file(dev, &w83795_dts[i].dev_attr); + err = fn(dev, &w83795_dts[i].dev_attr); if (err) return err; } } for (i = 0; i < ARRAY_SIZE(w83795_static); i++) { - err = device_create_file(dev, &w83795_static[i].dev_attr); + err = fn(dev, &w83795_static[i].dev_attr); if (err) return err; } @@ -1840,33 +1840,12 @@ static int w83795_create_files(struct device *dev) return 0; } -static void w83795_remove_files(struct device *dev) +/* We need a wrapper that fits in w83795_handle_files */ +static int device_remove_file_wrapper(struct device *dev, + const struct device_attribute *attr) { - struct w83795_data *data = dev_get_drvdata(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(w83795_in); i++) - device_remove_file(dev, &w83795_in[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) - device_remove_file(dev, &w83795_fan[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) - device_remove_file(dev, &sda_single_files[i].dev_attr); - - if (data->chip_type == w83795g) { - for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) - device_remove_file(dev, &w83795_left_reg[i].dev_attr); - } - - for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) - device_remove_file(dev, &w83795_temp[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) - device_remove_file(dev, &w83795_dts[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(w83795_static); i++) - device_remove_file(dev, &w83795_static[i].dev_attr); + device_remove_file(dev, attr); + return 0; } static int w83795_probe(struct i2c_client *client, @@ -2093,7 +2072,7 @@ static int w83795_probe(struct i2c_client *client, data->beep_enable = (w83795_read(client, W83795_REG_BEEP(5)) >> 7) & 0x01; - err = w83795_create_files(dev); + err = w83795_handle_files(dev, device_create_file); if (err) goto exit_remove; @@ -2106,7 +2085,7 @@ static int w83795_probe(struct i2c_client *client, return 0; exit_remove: - w83795_remove_files(dev); + w83795_handle_files(dev, device_remove_file_wrapper); kfree(data); exit: return err; @@ -2117,7 +2096,7 @@ static int w83795_remove(struct i2c_client *client) struct w83795_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); - w83795_remove_files(&client->dev); + w83795_handle_files(&client->dev, device_remove_file_wrapper); kfree(data); return 0; -- cgit v1.2.3 From 87df0dad3e024538d2d0d2ce786230e639c2ea8b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:45 +0200 Subject: hwmon: (w83795) Use 2D arrays for many device attributes Use 2D arrays for in, fan, temp and dts device attributes. Using linear arrays is too risky as we have to skip some groups depending on the device model and configuration. Adding or removing an attribute would let the driver build silently but then it would crash at runtime. With 2D arrays, the consistency checking happens at build time, which is much safer. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 66 ++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 29 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index ca8b0aec53e6..393f1025f6c8 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1447,7 +1447,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, #define NOT_USED -1 -#define SENSOR_ATTR_IN(index) \ +#define SENSOR_ATTR_IN(index) { \ SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ IN_READ, index), \ SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ @@ -1458,9 +1458,9 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ show_alarm_beep, store_beep, BEEP_ENABLE, \ - index + ((index > 14) ? 1 : 0)) + index + ((index > 14) ? 1 : 0)) } -#define SENSOR_ATTR_FAN(index) \ +#define SENSOR_ATTR_FAN(index) { \ SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ NULL, FAN_INPUT, index - 1), \ SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ @@ -1468,7 +1468,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ NULL, ALARM_STATUS, index + 31), \ SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ - show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) + show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } #define SENSOR_ATTR_PWM(index) \ SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ @@ -1488,7 +1488,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(speed_cruise##index##_target, S_IWUSR | S_IRUGO, \ show_fanin, store_fanin, FANIN_TARGET, index - 1) -#define SENSOR_ATTR_DTS(index) \ +#define SENSOR_ATTR_DTS(index) { \ SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ show_dts_mode, NULL, NOT_USED, index - 7), \ SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ @@ -1504,9 +1504,9 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ - show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) + show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } -#define SENSOR_ATTR_TEMP(index) \ +#define SENSOR_ATTR_TEMP(index) { \ SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \ show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ @@ -1568,10 +1568,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ show_sf4_temp, store_sf4_temp, 5, index - 1), \ SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ - show_sf4_temp, store_sf4_temp, 6, index - 1) + show_sf4_temp, store_sf4_temp, 6, index - 1) } -static struct sensor_device_attribute_2 w83795_in[] = { +static struct sensor_device_attribute_2 w83795_in[][5] = { SENSOR_ATTR_IN(0), SENSOR_ATTR_IN(1), SENSOR_ATTR_IN(2), @@ -1595,7 +1595,7 @@ static struct sensor_device_attribute_2 w83795_in[] = { SENSOR_ATTR_IN(20), }; -static struct sensor_device_attribute_2 w83795_fan[] = { +static struct sensor_device_attribute_2 w83795_fan[][4] = { SENSOR_ATTR_FAN(1), SENSOR_ATTR_FAN(2), SENSOR_ATTR_FAN(3), @@ -1612,7 +1612,7 @@ static struct sensor_device_attribute_2 w83795_fan[] = { SENSOR_ATTR_FAN(14), }; -static struct sensor_device_attribute_2 w83795_temp[] = { +static struct sensor_device_attribute_2 w83795_temp[][29] = { SENSOR_ATTR_TEMP(1), SENSOR_ATTR_TEMP(2), SENSOR_ATTR_TEMP(3), @@ -1621,7 +1621,7 @@ static struct sensor_device_attribute_2 w83795_temp[] = { SENSOR_ATTR_TEMP(6), }; -static struct sensor_device_attribute_2 w83795_dts[] = { +static struct sensor_device_attribute_2 w83795_dts[][8] = { SENSOR_ATTR_DTS(7), SENSOR_ATTR_DTS(8), SENSOR_ATTR_DTS(9), @@ -1781,22 +1781,26 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, const struct device_attribute *)) { struct w83795_data *data = dev_get_drvdata(dev); - int err, i; + int err, i, j; for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { - if (!(data->has_in & (1 << (i / 6)))) + if (!(data->has_in & (1 << i))) continue; - err = fn(dev, &w83795_in[i].dev_attr); - if (err) - return err; + for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { + err = fn(dev, &w83795_in[i][j].dev_attr); + if (err) + return err; + } } for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { - if (!(data->has_fan & (1 << (i / 5)))) + if (!(data->has_fan & (1 << i))) continue; - err = fn(dev, &w83795_fan[i].dev_attr); - if (err) - return err; + for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { + err = fn(dev, &w83795_fan[i][j].dev_attr); + if (err) + return err; + } } for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { @@ -1814,20 +1818,24 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, } for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { - if (!(data->has_temp & (1 << (i / 29)))) + if (!(data->has_temp & (1 << i))) continue; - err = fn(dev, &w83795_temp[i].dev_attr); - if (err) - return err; + for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { + err = fn(dev, &w83795_temp[i][j].dev_attr); + if (err) + return err; + } } if (data->enable_dts != 0) { for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { - if (!(data->has_dts & (1 << (i / 8)))) + if (!(data->has_dts & (1 << i))) continue; - err = fn(dev, &w83795_dts[i].dev_attr); - if (err) - return err; + for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { + err = fn(dev, &w83795_dts[i][j].dev_attr); + if (err) + return err; + } } } -- cgit v1.2.3 From b5f6a90a0bbedc07a0b0b82b83aa716c7203fcd2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Move PWM attributes to a dedidated array Use a dedicated 2D array for PWM attributes. This way, PWM attributes are handled the same way as other attributes, this is more consistent. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 393f1025f6c8..76e89c7bc465 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1470,7 +1470,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } -#define SENSOR_ATTR_PWM(index) \ +#define SENSOR_ATTR_PWM(index) { \ SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ store_pwm, PWM_OUTPUT, index - 1), \ SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ @@ -1482,7 +1482,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \ show_pwm, store_pwm, PWM_DIV, index - 1), \ SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ - show_pwm_enable, store_pwm_enable, NOT_USED, index - 1) + show_pwm_enable, store_pwm_enable, NOT_USED, index - 1) } #define SENSOR_ATTR_FANIN_TARGET(index) \ SENSOR_ATTR_2(speed_cruise##index##_target, S_IWUSR | S_IRUGO, \ @@ -1641,13 +1641,11 @@ static struct sensor_device_attribute_2 w83795_static[] = { SENSOR_ATTR_FANIN_TARGET(6), SENSOR_ATTR_FANIN_TARGET(7), SENSOR_ATTR_FANIN_TARGET(8), - SENSOR_ATTR_PWM(1), - SENSOR_ATTR_PWM(2), }; -/* all registers existed in 795g than 795adg, - * like PWM3 - PWM8 */ -static struct sensor_device_attribute_2 w83795_left_reg[] = { +static struct sensor_device_attribute_2 w83795_pwm[][6] = { + SENSOR_ATTR_PWM(1), + SENSOR_ATTR_PWM(2), SENSOR_ATTR_PWM(3), SENSOR_ATTR_PWM(4), SENSOR_ATTR_PWM(5), @@ -1809,9 +1807,9 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, return err; } - if (data->chip_type == w83795g) { - for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) { - err = fn(dev, &w83795_left_reg[i].dev_attr); + for (i = 0; i < data->has_pwm; i++) { + for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { + err = fn(dev, &w83795_pwm[i][j].dev_attr); if (err) return err; } -- cgit v1.2.3 From b2cc528e5838d744892b30c5104bd872a439088f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Only create fan[1-8]_target files when needed Only create fan[1-8]_target files when the fan in question can be controlled (PWM output is present.) Also name these files according to the standard. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 76e89c7bc465..00d64b0c200f 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1482,11 +1482,9 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \ show_pwm, store_pwm, PWM_DIV, index - 1), \ SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ - show_pwm_enable, store_pwm_enable, NOT_USED, index - 1) } - -#define SENSOR_ATTR_FANIN_TARGET(index) \ - SENSOR_ATTR_2(speed_cruise##index##_target, S_IWUSR | S_IRUGO, \ - show_fanin, store_fanin, FANIN_TARGET, index - 1) + show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ + SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ + show_fanin, store_fanin, FANIN_TARGET, index - 1) } #define SENSOR_ATTR_DTS(index) { \ SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ @@ -1632,18 +1630,7 @@ static struct sensor_device_attribute_2 w83795_dts[][8] = { SENSOR_ATTR_DTS(14), }; -static struct sensor_device_attribute_2 w83795_static[] = { - SENSOR_ATTR_FANIN_TARGET(1), - SENSOR_ATTR_FANIN_TARGET(2), - SENSOR_ATTR_FANIN_TARGET(3), - SENSOR_ATTR_FANIN_TARGET(4), - SENSOR_ATTR_FANIN_TARGET(5), - SENSOR_ATTR_FANIN_TARGET(6), - SENSOR_ATTR_FANIN_TARGET(7), - SENSOR_ATTR_FANIN_TARGET(8), -}; - -static struct sensor_device_attribute_2 w83795_pwm[][6] = { +static struct sensor_device_attribute_2 w83795_pwm[][7] = { SENSOR_ATTR_PWM(1), SENSOR_ATTR_PWM(2), SENSOR_ATTR_PWM(3), @@ -1837,12 +1824,6 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, } } - for (i = 0; i < ARRAY_SIZE(w83795_static); i++) { - err = fn(dev, &w83795_static[i].dev_attr); - if (err) - return err; - } - return 0; } -- cgit v1.2.3 From 86ef4d2fd5921ff0bcfd1c0d88403a08862087bc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Add const markers Attribute structures can be made const. Same for the I2C address list. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 00d64b0c200f..b45416011c2a 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -36,7 +36,9 @@ #include /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { + 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END +}; static int reset; @@ -70,7 +72,7 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); #define TEMP_CTRL_SHIFT 4 #define TEMP_CTRL_HASIN_SHIFT 5 /* temp mode may effect VSEN17-12 (in20-15) */ -static u16 W83795_REG_TEMP_CTRL[][6] = { +static const u16 W83795_REG_TEMP_CTRL[][6] = { /* Disable, TD, VSEN, TR, register shift value, has_in shift num */ {0x00, 0x01, 0x02, 0x03, 0, 17}, /* TR1 */ {0x00, 0x04, 0x08, 0x0C, 2, 18}, /* TR2 */ @@ -87,7 +89,7 @@ static u16 W83795_REG_TEMP_CTRL[][6] = { #define TEMP_WARN_HYST 4 /* only crit and crit_hyst affect real-time alarm status * current crit crit_hyst warn warn_hyst */ -static u16 W83795_REG_TEMP[][5] = { +static const u16 W83795_REG_TEMP[][5] = { {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ @@ -1593,7 +1595,7 @@ static struct sensor_device_attribute_2 w83795_in[][5] = { SENSOR_ATTR_IN(20), }; -static struct sensor_device_attribute_2 w83795_fan[][4] = { +static const struct sensor_device_attribute_2 w83795_fan[][4] = { SENSOR_ATTR_FAN(1), SENSOR_ATTR_FAN(2), SENSOR_ATTR_FAN(3), @@ -1610,7 +1612,7 @@ static struct sensor_device_attribute_2 w83795_fan[][4] = { SENSOR_ATTR_FAN(14), }; -static struct sensor_device_attribute_2 w83795_temp[][29] = { +static const struct sensor_device_attribute_2 w83795_temp[][29] = { SENSOR_ATTR_TEMP(1), SENSOR_ATTR_TEMP(2), SENSOR_ATTR_TEMP(3), @@ -1619,7 +1621,7 @@ static struct sensor_device_attribute_2 w83795_temp[][29] = { SENSOR_ATTR_TEMP(6), }; -static struct sensor_device_attribute_2 w83795_dts[][8] = { +static const struct sensor_device_attribute_2 w83795_dts[][8] = { SENSOR_ATTR_DTS(7), SENSOR_ATTR_DTS(8), SENSOR_ATTR_DTS(9), @@ -1630,7 +1632,7 @@ static struct sensor_device_attribute_2 w83795_dts[][8] = { SENSOR_ATTR_DTS(14), }; -static struct sensor_device_attribute_2 w83795_pwm[][7] = { +static const struct sensor_device_attribute_2 w83795_pwm[][7] = { SENSOR_ATTR_PWM(1), SENSOR_ATTR_PWM(2), SENSOR_ATTR_PWM(3), @@ -1641,7 +1643,7 @@ static struct sensor_device_attribute_2 w83795_pwm[][7] = { SENSOR_ATTR_PWM(8), }; -static struct sensor_device_attribute_2 sda_single_files[] = { +static const struct sensor_device_attribute_2 sda_single_files[] = { SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, store_chassis_clear, ALARM_STATUS, 46), SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, -- cgit v1.2.3 From 80646b95863ba282330d07290c79254c2f002139 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Only start monitoring if needed This saves an SMBus write if monitoring was already enabled. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index b45416011c2a..62deffcc64a3 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -55,6 +55,7 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); #define W83795_REG_I2C_ADDR 0xfc #define W83795_REG_CONFIG 0x01 #define W83795_REG_CONFIG_CONFIG48 0x04 +#define W83795_REG_CONFIG_START 0x01 /* Multi-Function Pin Ctrl Registers */ #define W83795_REG_VOLT_CTRL1 0x02 @@ -1664,12 +1665,18 @@ static const struct sensor_device_attribute_2 sda_single_files[] = { static void w83795_init_client(struct i2c_client *client) { + u8 config; + if (reset) w83795_write(client, W83795_REG_CONFIG, 0x80); - /* Start monitoring */ - w83795_write(client, W83795_REG_CONFIG, - w83795_read(client, W83795_REG_CONFIG) | 0x01); + /* Start monitoring if needed */ + config = w83795_read(client, W83795_REG_CONFIG); + if (!(config & W83795_REG_CONFIG_START)) { + dev_info(&client->dev, "Enabling monitoring operations\n"); + w83795_write(client, W83795_REG_CONFIG, + config | W83795_REG_CONFIG_START); + } } static int w83795_get_device_id(struct i2c_client *client) -- cgit v1.2.3 From 6f9dfd85f7b14dd3ea87106909dc54def08947b1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Fix in17-in20 gain factor Gain bit set means 1x gain and cleared means 8x gain, not the other way around. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 62deffcc64a3..77b4f7859df9 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1335,7 +1335,7 @@ show_in(struct device *dev, struct device_attribute *attr, char *buf) case IN_READ: /* calculate this value again by sensors as sensors3.conf */ if ((index >= 17) && - ((data->has_gain >> (index - 17)) & 1)) + !((data->has_gain >> (index - 17)) & 1)) val *= 8; break; case IN_MAX: @@ -1345,7 +1345,7 @@ show_in(struct device *dev, struct device_attribute *attr, char *buf) val |= (data->in_lsb[lsb_idx][nr] >> IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; if ((index >= 17) && - ((data->has_gain >> (index - 17)) & 1)) + !((data->has_gain >> (index - 17)) & 1)) val *= 8; break; } @@ -1373,7 +1373,7 @@ store_in(struct device *dev, struct device_attribute *attr, val = in_to_reg(index, val); if ((index >= 17) && - ((data->has_gain >> (index - 17)) & 1)) + !((data->has_gain >> (index - 17)) & 1)) val /= 8; val = SENSORS_LIMIT(val, 0, 0x3FF); mutex_lock(&data->update_lock); -- cgit v1.2.3 From 71caf46fbf39207a324a16ddb6d8ef37c05777b9 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Clean up probe function * The data structure is zalloc'd, so no need to set individual fields to 0 explicitly. * Refactor the handling of pins that can be used for either temperature or voltage monitoring. * Misc other clean-ups. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 91 +++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 57 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 77b4f7859df9..b797b9ce2907 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1844,6 +1844,26 @@ static int device_remove_file_wrapper(struct device *dev, return 0; } +/* Check pins that can be used for either temperature or voltage monitoring */ +static void w83795_apply_temp_config(struct w83795_data *data, u8 config, + int temp_chan, int in_chan) +{ + /* config is a 2-bit value */ + switch (config) { + case 0x2: /* Voltage monitoring */ + data->has_in |= 1 << in_chan; + break; + case 0x1: /* Thermal diode */ + if (temp_chan >= 4) + break; + data->temp_mode |= 1 << temp_chan; + /* fall through */ + case 0x3: /* Thermistor */ + data->has_temp |= 1 << temp_chan; + break; + } +} + static int w83795_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1851,7 +1871,7 @@ static int w83795_probe(struct i2c_client *client, u8 tmp; struct device *dev = &client->dev; struct w83795_data *data; - int err = 0; + int err; data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL); if (!data) { @@ -1867,68 +1887,26 @@ static int w83795_probe(struct i2c_client *client, /* Initialize the chip */ w83795_init_client(client); - data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1); - data->has_in |= w83795_read(client, W83795_REG_VOLT_CTRL2) << 8; - /* VSEN11-9 not for 795adg */ - if (data->chip_type == w83795adg) - data->has_in &= 0xf8ff; - data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1); - data->has_fan |= w83795_read(client, W83795_REG_FANIN_CTRL2) << 8; + /* Check which voltages and fans are present */ + data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) + | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); + data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) + | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); - /* VDSEN12-17 and TR1-6, TD1-4 use same register */ + /* Check which analog temperatures and extra voltages are present */ tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); if (tmp & 0x20) data->enable_dts = 1; - else - data->enable_dts = 0; - data->has_temp = 0; - data->temp_mode = 0; - if (tmp & 0x08) { - if (tmp & 0x04) - data->has_temp |= 0x20; - else - data->has_in |= 0x10000; - } - if (tmp & 0x02) { - if (tmp & 0x01) - data->has_temp |= 0x10; - else - data->has_in |= 0x8000; - } + w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); + w83795_apply_temp_config(data, tmp & 0x3, 4, 15); tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); - if (tmp & 0x40) { - data->has_temp |= 0x08; - if (!(tmp & 0x80)) - data->temp_mode |= 0x08; - } else if (tmp & 0x80) { - data->has_in |= 0x100000; - } - if (tmp & 0x10) { - data->has_temp |= 0x04; - if (!(tmp & 0x20)) - data->temp_mode |= 0x04; - } else if (tmp & 0x20) { - data->has_in |= 0x80000; - } - if (tmp & 0x04) { - data->has_temp |= 0x02; - if (!(tmp & 0x08)) - data->temp_mode |= 0x02; - } else if (tmp & 0x08) { - data->has_in |= 0x40000; - } - if (tmp & 0x01) { - data->has_temp |= 0x01; - if (!(tmp & 0x02)) - data->temp_mode |= 0x01; - } else if (tmp & 0x02) { - data->has_in |= 0x20000; - } + w83795_apply_temp_config(data, tmp >> 6, 3, 20); + w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); + w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); + w83795_apply_temp_config(data, tmp & 0x3, 0, 17); /* Check DTS enable status */ - if (data->enable_dts == 0) { - data->has_dts = 0; - } else { + if (data->enable_dts) { if (1 & w83795_read(client, W83795_REG_DTSC)) data->enable_dts |= 2; data->has_dts = w83795_read(client, W83795_REG_DTSE); @@ -2017,7 +1995,6 @@ static int w83795_probe(struct i2c_client *client, data->has_pwm = 2; data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); - /* w83795adg only support pwm2-0 */ for (i = 0; i < W83795_REG_TEMP_NUM; i++) data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); -- cgit v1.2.3 From 6c82b2f3fb31e43a9b898769afd2151ca64986a4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Fix LSB reading of fan speeds Misplaced parentheses caused the wrong register value to be read, resulting in random LSB for fan speed values and limits. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index b797b9ce2907..24e44245e548 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -272,7 +272,7 @@ static inline u16 in_to_reg(u8 index, u16 val) static inline unsigned long fan_from_reg(u16 val) { - if ((val >= 0xff0) || (val == 0)) + if ((val == 0xfff) || (val == 0)) return 0; return 1350000UL / val; } @@ -456,7 +456,7 @@ static struct w83795_data *w83795_update_device(struct device *dev) continue; data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; data->fan[i] |= - (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F; + (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; } /* Update temperature */ @@ -1940,11 +1940,11 @@ static int w83795_probe(struct i2c_client *client, data->fan_min[i] = w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; data->fan_min[i] |= - (w83795_read(client, W83795_REG_FAN_MIN_LSB(i) >> - W83795_REG_FAN_MIN_LSB_SHIFT(i))) & 0x0F; + (w83795_read(client, W83795_REG_FAN_MIN_LSB(i)) >> + W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; data->fan[i] |= - (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F; + (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; } /* temperature and limits */ -- cgit v1.2.3 From 0e256018b0f35d1b22ca37e1d0e207f7ba3d0076 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:46 +0200 Subject: hwmon: (w83795) Add support for dynamic in0-2 limits The W83795G can be configured to set the in0, in1 and/or in2 voltage limits dynamically based on VID input pins. Switch the respective sysfs attributes to read-only. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 24e44245e548..458fb297f696 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -316,6 +316,7 @@ struct w83795_data { u8 bank; u32 has_in; /* Enable monitor VIN or not */ + u8 has_dyn_in; /* Only in2-0 can have this */ u16 in[21][3]; /* Register value, read/high/low */ u8 in_lsb[10][3]; /* LSB Register value, high/low */ u8 has_gain; /* has gain: in17-20 * 8 */ @@ -450,6 +451,23 @@ static struct w83795_data *w83795_update_device(struct device *dev) data->in[i][IN_READ] = tmp; } + /* in0-2 can have dynamic limits (W83795G only) */ + if (data->has_dyn_in) { + u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); + u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); + + for (i = 0; i < 3; i++) { + if (!(data->has_dyn_in & (1 << i))) + continue; + data->in[i][IN_MAX] = + w83795_read(client, W83795_REG_IN[i][IN_MAX]); + data->in[i][IN_LOW] = + w83795_read(client, W83795_REG_IN[i][IN_LOW]); + data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; + data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; + } + } + /* Update fan */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { if (!(data->has_fan & (1 << i))) @@ -1450,6 +1468,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, #define NOT_USED -1 +/* Don't change the attribute order, _max and _min are accessed by index + * somewhere else in the code */ #define SENSOR_ATTR_IN(index) { \ SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ IN_READ, index), \ @@ -1844,6 +1864,39 @@ static int device_remove_file_wrapper(struct device *dev, return 0; } +static void w83795_check_dynamic_in_limits(struct i2c_client *client) +{ + struct w83795_data *data = i2c_get_clientdata(client); + u8 vid_ctl; + int i, err_max, err_min; + + vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); + + /* Return immediately if VRM isn't configured */ + if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) + return; + + data->has_dyn_in = (vid_ctl >> 3) & 0x07; + for (i = 0; i < 2; i++) { + if (!(data->has_dyn_in & (1 << i))) + continue; + + /* Voltage limits in dynamic mode, switch to read-only */ + err_max = sysfs_chmod_file(&client->dev.kobj, + &w83795_in[i][2].dev_attr.attr, + S_IRUGO); + err_min = sysfs_chmod_file(&client->dev.kobj, + &w83795_in[i][3].dev_attr.attr, + S_IRUGO); + if (err_max || err_min) + dev_warn(&client->dev, "Failed to set in%d limits " + "read-only (%d, %d)\n", i, err_max, err_min); + else + dev_info(&client->dev, "in%d limits set dynamically " + "from VID\n", i); + } +} + /* Check pins that can be used for either temperature or voltage monitoring */ static void w83795_apply_temp_config(struct w83795_data *data, u8 config, int temp_chan, int in_chan) @@ -2049,6 +2102,9 @@ static int w83795_probe(struct i2c_client *client, if (err) goto exit_remove; + if (data->chip_type == w83795g) + w83795_check_dynamic_in_limits(client); + data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); -- cgit v1.2.3 From 01879a855fb6bdb3fb820344a7a145de8a5cdbda Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Fix PWM duty cycle frequency attributes The PWM duty cycle frequenty attributes are improperly named (fanN_div instead of pwmN_div) and contain raw values instead of actual frequencies. Rename them and fix their contents. Also improve the logic when the user asks for a new frequency, to always pick the closest supported frequency. The algorithm could certainly be optimized, but the operation is infrequent enough that I don't think it's worth the effort. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 90 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 28 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 458fb297f696..58c61f11ed66 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -200,7 +200,6 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define W83795_REG_FCMS2 0x208 #define W83795_REG_TFMR(index) (0x202 + (index)) #define W83795_REG_FOMC 0x20F -#define W83795_REG_FOPFP(index) (0x218 + (index)) #define W83795_REG_TSS(index) (0x209 + (index)) @@ -208,18 +207,13 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define PWM_START 1 #define PWM_NONSTOP 2 #define PWM_STOP_TIME 3 -#define PWM_DIV 4 +#define PWM_FREQ 4 #define W83795_REG_PWM(index, nr) \ (((nr) == 0 ? 0x210 : \ (nr) == 1 ? 0x220 : \ (nr) == 2 ? 0x228 : \ (nr) == 3 ? 0x230 : 0x218) + (index)) -#define W83795_REG_FOPFP_DIV(index) \ - (((index) < 8) ? ((index) + 1) : \ - ((index) == 8) ? 12 : \ - (16 << ((index) - 9))) - #define W83795_REG_FTSH(index) (0x240 + (index) * 2) #define W83795_REG_FTSL(index) (0x241 + (index) * 2) #define W83795_REG_TFTS 0x250 @@ -304,6 +298,50 @@ static inline s8 temp_to_reg(long val, s8 min, s8 max) return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); } +static const u16 pwm_freq_cksel0[16] = { + 1024, 512, 341, 256, 205, 171, 146, 128, + 85, 64, 32, 16, 8, 4, 2, 1 +}; + +static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) +{ + unsigned long base_clock; + + if (reg & 0x80) { + base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); + return base_clock / ((reg & 0x7f) + 1); + } else + return pwm_freq_cksel0[reg & 0x0f]; +} + +static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) +{ + unsigned long base_clock; + u8 reg0, reg1; + unsigned long best0, best1; + + /* Best fit for cksel = 0 */ + for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { + if (val > (pwm_freq_cksel0[reg0] + + pwm_freq_cksel0[reg0 + 1]) / 2) + break; + } + if (val < 375) /* cksel = 1 can't beat this */ + return reg0; + best0 = pwm_freq_cksel0[reg0]; + + /* Best fit for cksel = 1 */ + base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); + reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); + best1 = base_clock / reg1; + reg1 = 0x80 | (reg1 - 1); + + /* Choose the closest one */ + if (abs(val - best0) > abs(val - best1)) + return reg1; + else + return reg0; +} enum chip_types {w83795g, w83795adg}; @@ -343,7 +381,8 @@ struct w83795_data { * no config register, only affected by chip * type */ u8 pwm[8][5]; /* Register value, output, start, non stop, stop - * time, div */ + * time, freq */ + u16 clkin; /* CLKIN frequency in kHz */ u8 pwm_fcms[2]; /* Register value */ u8 pwm_tfmr[6]; /* Register value */ u8 pwm_fomc; /* Register value */ @@ -688,14 +727,14 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf) to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; - u16 val; + unsigned int val; switch (nr) { case PWM_STOP_TIME: val = time_from_reg(data->pwm[index][nr]); break; - case PWM_DIV: - val = W83795_REG_FOPFP_DIV(data->pwm[index][nr] & 0x0f); + case PWM_FREQ: + val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); break; default: val = data->pwm[index][nr]; @@ -716,7 +755,6 @@ store_pwm(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->nr; int index = sensor_attr->index; unsigned long val; - int i; if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; @@ -726,28 +764,17 @@ store_pwm(struct device *dev, struct device_attribute *attr, case PWM_STOP_TIME: val = time_to_reg(val); break; - case PWM_DIV: - for (i = 0; i < 16; i++) { - if (W83795_REG_FOPFP_DIV(i) == val) { - val = i; - break; - } - } - if (i >= 16) - goto err_end; - val |= w83795_read(client, W83795_REG_PWM(index, nr)) & 0x80; + case PWM_FREQ: + val = pwm_freq_to_reg(val, data->clkin); break; default: val = SENSORS_LIMIT(val, 0, 0xff); break; } w83795_write(client, W83795_REG_PWM(index, nr), val); - data->pwm[index][nr] = val & 0xff; + data->pwm[index][nr] = val; mutex_unlock(&data->update_lock); return count; -err_end: - mutex_unlock(&data->update_lock); - return -EINVAL; } static ssize_t @@ -1502,8 +1529,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, show_pwm, store_pwm, PWM_START, index - 1), \ SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ - SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \ - show_pwm, store_pwm, PWM_DIV, index - 1), \ + SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ + show_pwm, store_pwm, PWM_FREQ, index - 1), \ SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ @@ -1685,6 +1712,10 @@ static const struct sensor_device_attribute_2 sda_single_files[] = { static void w83795_init_client(struct i2c_client *client) { + struct w83795_data *data = i2c_get_clientdata(client); + static const u16 clkin[4] = { /* in kHz */ + 14318, 24000, 33333, 48000 + }; u8 config; if (reset) @@ -1697,6 +1728,9 @@ static void w83795_init_client(struct i2c_client *client) w83795_write(client, W83795_REG_CONFIG, config | W83795_REG_CONFIG_START); } + + data->clkin = clkin[(config >> 3) & 0x3]; + dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); } static int w83795_get_device_id(struct i2c_client *client) -- cgit v1.2.3 From a0ce402fb006bd694436be8c8522fbe5e6823ac1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Rename temperature limit attributes Follow the standard for temperature limit attribute naming, so that libsensors will pick the values. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 58c61f11ed66..5ce276b67528 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1541,13 +1541,13 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, show_dts_mode, NULL, NOT_USED, index - 7), \ SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ NULL, NOT_USED, index - 7), \ - SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ + SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ store_dts_ext, DTS_CRIT, NOT_USED), \ - SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ + SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ - SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_dts_ext, \ + SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ store_dts_ext, DTS_WARN, NOT_USED), \ - SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ + SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ @@ -1559,13 +1559,13 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ NULL, TEMP_READ, index - 1), \ - SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ + SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ store_temp, TEMP_CRIT, index - 1), \ - SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ + SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ - SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \ + SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ store_temp, TEMP_WARN, index - 1), \ - SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \ + SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ show_alarm_beep, NULL, ALARM_STATUS, \ @@ -1583,9 +1583,9 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, TEMP_PWM_FAN_MAP, index - 1), \ SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ - SENSOR_ATTR_2(temp##index##_crit, S_IWUSR | S_IRUGO, \ + SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ - SENSOR_ATTR_2(temp##index##_crit_hyst, S_IWUSR | S_IRUGO, \ + SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ -- cgit v1.2.3 From dd127f5ccd7c61eb7ee215120a7809eb67c1ed7f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Properly handle negative temperatures The temperature registers hold regular 2's complement values, no need to add any arithmetics. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 5ce276b67528..f4b7cb45ebcb 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -295,7 +295,7 @@ static inline long temp_from_reg(s8 reg) static inline s8 temp_to_reg(long val, s8 min, s8 max) { - return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); + return SENSORS_LIMIT(val / 1000, min, max); } static const u16 pwm_freq_cksel0[16] = { @@ -364,7 +364,7 @@ struct w83795_data { u16 fan_min[14]; /* Register value combine */ u8 has_temp; /* Enable monitor temp6-1 or not */ - u8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ + s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ u8 temp_read_vrlsb[6]; u8 temp_mode; /* bit 0: TR mode, bit 1: TD mode */ u8 temp_src[3]; /* Register value */ @@ -373,9 +373,9 @@ struct w83795_data { * bit 0: =1 enable, =0 disable, * bit 1: =1 AMD SB-TSI, =0 Intel PECI */ u8 has_dts; /* Enable monitor DTS temp */ - u8 dts[8]; /* Register value */ + s8 dts[8]; /* Register value */ u8 dts_read_vrlsb[8]; /* Register value */ - u8 dts_ext[4]; /* Register value */ + s8 dts_ext[4]; /* Register value */ u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, * no config register, only affected by chip @@ -1170,13 +1170,11 @@ show_temp(struct device *dev, struct device_attribute *attr, char *buf) int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83795_data *data = w83795_update_device(dev); - long temp = temp_from_reg(data->temp[index][nr] & 0x7f); + long temp = temp_from_reg(data->temp[index][nr]); if (TEMP_READ == nr) temp += ((data->temp_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250; - if (data->temp[index][nr] & 0x80) - temp = -temp; return sprintf(buf, "%ld\n", temp); } @@ -1235,11 +1233,9 @@ show_dts(struct device *dev, struct device_attribute *attr, char *buf) to_sensor_dev_attr_2(attr); int index = sensor_attr->index; struct w83795_data *data = w83795_update_device(dev); - long temp = temp_from_reg(data->dts[index] & 0x7f); + long temp = temp_from_reg(data->dts[index]); temp += ((data->dts_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250; - if (data->dts[index] & 0x80) - temp = -temp; return sprintf(buf, "%ld\n", temp); } @@ -1251,10 +1247,8 @@ show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) int nr = sensor_attr->nr; struct i2c_client *client = to_i2c_client(dev); struct w83795_data *data = i2c_get_clientdata(client); - long temp = temp_from_reg(data->dts_ext[nr] & 0x7f); + long temp = temp_from_reg(data->dts_ext[nr]); - if (data->dts_ext[nr] & 0x80) - temp = -temp; return sprintf(buf, "%ld\n", temp); } -- cgit v1.2.3 From 54891a3c135b30ca0718dbf81f78260795a5b2fe Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Report PECI agent Tbase values On systems with PECI, report PECI agent Tbase temperature values. This is informative only. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index f4b7cb45ebcb..b360696f241d 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -236,6 +236,7 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define W83795_REG_DTSC 0x301 #define W83795_REG_DTSE 0x302 #define W83795_REG_DTS(index) (0x26 + (index)) +#define W83795_REG_PECI_TBASE(index) (0x320 + (index)) #define DTS_CRIT 0 #define DTS_CRIT_HYST 1 @@ -1993,6 +1994,18 @@ static int w83795_probe(struct i2c_client *client, data->has_dts = w83795_read(client, W83795_REG_DTSE); } + /* Report PECI Tbase values */ + if (data->enable_dts == 1) { + for (i = 0; i < 8; i++) { + if (!(data->has_dts & (1 << i))) + continue; + tmp = w83795_read(client, W83795_REG_PECI_TBASE(i)); + dev_info(&client->dev, + "PECI agent %d Tbase temperature: %u\n", + i + 1, (unsigned int)tmp & 0x7f); + } + } + /* First update the voltages measured value and limits */ for (i = 0; i < ARRAY_SIZE(data->in); i++) { if (!(data->has_in & (1 << i))) -- cgit v1.2.3 From 02728ffef9c2cf067e654e832b8c282a8a4d0b16 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Rework beep_enable implementation Handle beep_enable just like all other beep bits. It doesn't need anything special, so let's avoid redundant code. This also saves a duplicate register read at initialization time. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index b360696f241d..fd70a7b46295 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -398,7 +398,6 @@ struct w83795_data { u8 alarms[6]; /* Register value */ u8 beeps[6]; /* Register value */ - u8 beep_enable; char valid; }; @@ -616,39 +615,6 @@ store_beep(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t -show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); - return sprintf(buf, "%u\n", data->beep_enable); -} - -static ssize_t -store_beep_enable(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); - unsigned long val; - u8 tmp; - - if (strict_strtoul(buf, 10, &val) < 0) - return -EINVAL; - if (val != 0 && val != 1) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->beep_enable = val; - tmp = w83795_read(client, W83795_REG_BEEP(5)); - tmp &= 0x7f; - tmp |= val << 7; - w83795_write(client, W83795_REG_BEEP(5), tmp); - mutex_unlock(&data->update_lock); - - return count; -} - /* Write any value to clear chassis alarm */ static ssize_t store_chassis_clear(struct device *dev, @@ -1689,8 +1655,8 @@ static const struct sensor_device_attribute_2 w83795_pwm[][7] = { static const struct sensor_device_attribute_2 sda_single_files[] = { SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, store_chassis_clear, ALARM_STATUS, 46), - SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, - store_beep_enable, NOT_USED, NOT_USED), + SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, + store_beep, BEEP_ENABLE, 47), SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, store_fanin, FANIN_TOL, NOT_USED), SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, @@ -2136,8 +2102,6 @@ static int w83795_probe(struct i2c_client *client, data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); } - data->beep_enable = - (w83795_read(client, W83795_REG_BEEP(5)) >> 7) & 0x01; err = w83795_handle_files(dev, device_create_file); if (err) -- cgit v1.2.3 From c1a792a6eea42d88a99e6ace215b22fbdb76c7b6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Avoid reading the same register twice Shorten driver load time by avoiding duplicate register access during initialization. This saves 112 ms on modprobe on my test system. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index fd70a7b46295..aea3275f5dae 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1986,6 +1986,9 @@ static int w83795_probe(struct i2c_client *client, data->in[i][IN_READ] = tmp; } for (i = 0; i < IN_LSB_REG_NUM; i++) { + if ((i == 2 && data->chip_type == w83795adg) || + (i >= 4 && !(data->has_in & (1 << (i + 11))))) + continue; data->in_lsb[i][IN_MAX] = w83795_read(client, IN_LSB_REG(i, IN_MAX)); data->in_lsb[i][IN_LOW] = @@ -1995,13 +1998,17 @@ static int w83795_probe(struct i2c_client *client, /* First update fan and limits */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { + /* Each register contains LSB for 2 fans, but we want to + * read it only once to save time */ + if ((i & 1) == 0 && (data->has_fan & (3 << i))) + tmp = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); + if (!(data->has_fan & (1 << i))) continue; data->fan_min[i] = w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; data->fan_min[i] |= - (w83795_read(client, W83795_REG_FAN_MIN_LSB(i)) >> - W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; + (tmp >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; data->fan[i] |= (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; -- cgit v1.2.3 From a654b9d4e7152b06557e2f22bcf0a245bc88bc98 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Get rid of VRLSB_SHIFT VRLSB_SHIFT is a non-sense, the actual shift depends on the sensor type (fans need 4, other sensors need 6). Get rid of it to prevent any confusion. Also get rid of the useless masking, the meaningful bits are always the MSb so there's nothing to mask out after shifting. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index aea3275f5dae..71b7a254beeb 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -127,7 +127,6 @@ static const u16 W83795_REG_IN[][3] = { {0x24, 0xa2, 0xa3}, /* VSEN17 */ }; #define W83795_REG_VRLSB 0x3C -#define VRLSB_SHIFT 6 static const u8 W83795_REG_IN_HL_LSB[] = { 0x8e, /* VSEN1-4 */ @@ -485,8 +484,7 @@ static struct w83795_data *w83795_update_device(struct device *dev) if (!(data->has_in & (1 << i))) continue; tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; - tmp |= (w83795_read(client, W83795_REG_VRLSB) - >> VRLSB_SHIFT) & 0x03; + tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; data->in[i][IN_READ] = tmp; } @@ -1140,8 +1138,7 @@ show_temp(struct device *dev, struct device_attribute *attr, char *buf) long temp = temp_from_reg(data->temp[index][nr]); if (TEMP_READ == nr) - temp += ((data->temp_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) - * 250; + temp += (data->temp_read_vrlsb[index] >> 6) * 250; return sprintf(buf, "%ld\n", temp); } @@ -1202,7 +1199,7 @@ show_dts(struct device *dev, struct device_attribute *attr, char *buf) struct w83795_data *data = w83795_update_device(dev); long temp = temp_from_reg(data->dts[index]); - temp += ((data->dts_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250; + temp += (data->dts_read_vrlsb[index] >> 6) * 250; return sprintf(buf, "%ld\n", temp); } @@ -1981,8 +1978,7 @@ static int w83795_probe(struct i2c_client *client, data->in[i][IN_LOW] = w83795_read(client, W83795_REG_IN[i][IN_LOW]); tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; - tmp |= (w83795_read(client, W83795_REG_VRLSB) - >> VRLSB_SHIFT) & 0x03; + tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; data->in[i][IN_READ] = tmp; } for (i = 0; i < IN_LSB_REG_NUM; i++) { @@ -2010,8 +2006,7 @@ static int w83795_probe(struct i2c_client *client, data->fan_min[i] |= (tmp >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; - data->fan[i] |= - (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; + data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; } /* temperature and limits */ -- cgit v1.2.3 From 7eb8d508b5cfabbb147670ee063438469d94c465 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:47 +0200 Subject: hwmon: (w83795) Fix parity checks x % 1 is obviously wrong, as it always evaluates to 0. You want x % 2, or x & 1, for parity checking. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 71b7a254beeb..ec8a1d1f7d79 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -183,7 +183,7 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) #define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ - (((index) % 1) ? 4 : 0) + (((index) & 1) ? 4 : 0) #define W83795_REG_VID_CTRL 0x6A @@ -670,7 +670,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, data->fan_min[index] = val; w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); val &= 0x0f; - if (index % 1) { + if (index & 1) { val <<= 4; val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) & 0x0f; @@ -823,7 +823,7 @@ show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) u8 val = index / 2; u8 tmp = data->temp_src[val]; - if (index % 1) + if (index & 1) val = 4; else val = 0; @@ -850,7 +850,7 @@ store_temp_src(struct device *dev, struct device_attribute *attr, tmp = SENSORS_LIMIT(tmp, 0, 15); mutex_lock(&data->update_lock); - if (index % 1) { + if (index & 1) { tmp <<= 4; data->temp_src[val] &= 0x0f; } else { -- cgit v1.2.3 From 49c7347a44224b5b87c7e6a3c6c92619d77c06d5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Drop REST_VLT_BEGIN/END Get rid of REST_VLT_BEGIN and REST_VLT_END, they don't make the code more readable. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index ec8a1d1f7d79..4e54edc415d7 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -175,10 +175,6 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { }; -/* 3VDD, 3VSB, VBAT * 0.006 */ -#define REST_VLT_BEGIN 12 /* the 13th volt to 15th */ -#define REST_VLT_END 14 /* the 13th volt to 15th */ - #define W83795_REG_FAN(index) (0x2E + (index)) #define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) #define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) @@ -250,7 +246,8 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { static inline u16 in_from_reg(u8 index, u16 val) { - if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) + /* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */ + if (index >= 12 && index <= 14) return val * 6; else return val * 2; @@ -258,7 +255,7 @@ static inline u16 in_from_reg(u8 index, u16 val) static inline u16 in_to_reg(u8 index, u16 val) { - if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END)) + if (index >= 12 && index <= 14) return val / 6; else return val / 2; -- cgit v1.2.3 From cd316df582925f3dab1ce5863651b3e260687035 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Drop _NUM constants Consistently use ARRAY_SIZE() to control for loops. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 4e54edc415d7..c8f62044ac19 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -145,8 +145,6 @@ static const u8 W83795_REG_IN_HL_LSB[] = { (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ : (W83795_REG_IN_HL_LSB[(index)] + 1)) -#define IN_LSB_REG_NUM 10 - #define IN_LSB_SHIFT 0 #define IN_LSB_IDX 1 static const u8 IN_LSB_SHIFT_IDX[][2] = { @@ -183,14 +181,12 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define W83795_REG_VID_CTRL 0x6A -#define ALARM_BEEP_REG_NUM 6 #define W83795_REG_ALARM(index) (0x41 + (index)) #define W83795_REG_BEEP(index) (0x50 + (index)) #define W83795_REG_CLR_CHASSIS 0x4D -#define W83795_REG_TEMP_NUM 6 #define W83795_REG_FCMS1 0x201 #define W83795_REG_FCMS2 0x208 #define W83795_REG_TFMR(index) (0x202 + (index)) @@ -545,7 +541,7 @@ static struct w83795_data *w83795_update_device(struct device *dev) } /* update alarm */ - for (i = 0; i < ALARM_BEEP_REG_NUM; i++) + for (i = 0; i < ARRAY_SIZE(data->alarms); i++) data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); data->last_updated = jiffies; @@ -1978,7 +1974,7 @@ static int w83795_probe(struct i2c_client *client, tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; data->in[i][IN_READ] = tmp; } - for (i = 0; i < IN_LSB_REG_NUM; i++) { + for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { if ((i == 2 && data->chip_type == w83795adg) || (i >= 4 && !(data->has_in & (1 << (i + 11))))) continue; @@ -2054,7 +2050,7 @@ static int w83795_probe(struct i2c_client *client, data->has_pwm = 2; data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); - for (i = 0; i < W83795_REG_TEMP_NUM; i++) + for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); for (i = 0; i < data->has_pwm; i++) { @@ -2071,7 +2067,7 @@ static int w83795_probe(struct i2c_client *client, } data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; - for (i = 0; i < W83795_REG_TEMP_NUM; i++) { + for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { data->pwm_temp[i][TEMP_PWM_TTTI] = w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; data->pwm_temp[i][TEMP_PWM_CTFS] = @@ -2080,7 +2076,7 @@ static int w83795_probe(struct i2c_client *client, data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; } - for (i = 0; i < W83795_REG_TEMP_NUM; i++) { + for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { for (tmp = 0; tmp < 7; tmp++) { data->sf4_reg[i][SF4_TEMP][tmp] = w83795_read(client, @@ -2097,7 +2093,7 @@ static int w83795_probe(struct i2c_client *client, } /* alarm and beep */ - for (i = 0; i < ALARM_BEEP_REG_NUM; i++) { + for (i = 0; i < ARRAY_SIZE(data->alarms); i++) { data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); } -- cgit v1.2.3 From 39deb6993e7c22274c272c95013eef886f7004e8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Simplify temperature sensor type handling All 3 temperature sensor type sysfs functions (show_temp_mode, store_temp_mode and show_dts_mode) can be simplified. We don't create these files when the correponding input isn't in temperature monitoring mode, so there is no point in handling that case. Likewise, we don't allow changing inputs from temperature to voltage, so the code handling this case is dead and can be removed. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 107 +++++++++++-------------------------------------- 1 file changed, 24 insertions(+), 83 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index c8f62044ac19..07e8de58dcd4 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -66,23 +66,6 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); #define W83795_REG_FANIN_CTRL2 0x07 #define W83795_REG_VMIGB_CTRL 0x08 -#define TEMP_CTRL_DISABLE 0 -#define TEMP_CTRL_TD 1 -#define TEMP_CTRL_VSEN 2 -#define TEMP_CTRL_TR 3 -#define TEMP_CTRL_SHIFT 4 -#define TEMP_CTRL_HASIN_SHIFT 5 -/* temp mode may effect VSEN17-12 (in20-15) */ -static const u16 W83795_REG_TEMP_CTRL[][6] = { - /* Disable, TD, VSEN, TR, register shift value, has_in shift num */ - {0x00, 0x01, 0x02, 0x03, 0, 17}, /* TR1 */ - {0x00, 0x04, 0x08, 0x0C, 2, 18}, /* TR2 */ - {0x00, 0x10, 0x20, 0x30, 4, 19}, /* TR3 */ - {0x00, 0x40, 0x80, 0xC0, 6, 20}, /* TR4 */ - {0x00, 0x00, 0x02, 0x03, 0, 15}, /* TR5 */ - {0x00, 0x00, 0x08, 0x0C, 2, 16}, /* TR6 */ -}; - #define TEMP_READ 0 #define TEMP_CRIT 1 #define TEMP_CRIT_HYST 2 @@ -359,7 +342,7 @@ struct w83795_data { u8 has_temp; /* Enable monitor temp6-1 or not */ s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ u8 temp_read_vrlsb[6]; - u8 temp_mode; /* bit 0: TR mode, bit 1: TD mode */ + u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */ u8 temp_src[3]; /* Register value */ u8 enable_dts; /* Enable PECI and SB-TSI, @@ -509,13 +492,6 @@ static struct w83795_data *w83795_update_device(struct device *dev) /* Update temperature */ for (i = 0; i < ARRAY_SIZE(data->temp); i++) { - /* even stop monitor, register still keep value, just read out - * it */ - if (!(data->has_temp & (1 << i))) { - data->temp[i][TEMP_READ] = 0; - data->temp_read_vrlsb[i] = 0; - continue; - } data->temp[i][TEMP_READ] = w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); data->temp_read_vrlsb[i] = @@ -1163,22 +1139,12 @@ show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct w83795_data *data = i2c_get_clientdata(client); - struct sensor_device_attribute_2 *sensor_attr = - to_sensor_dev_attr_2(attr); - int index = sensor_attr->index; - u8 tmp; + int tmp; - if (data->enable_dts == 0) - return sprintf(buf, "%d\n", 0); - - if ((data->has_dts >> index) & 0x01) { - if (data->enable_dts & 2) - tmp = 5; - else - tmp = 6; - } else { - tmp = 0; - } + if (data->enable_dts & 2) + tmp = 5; + else + tmp = 6; return sprintf(buf, "%d\n", tmp); } @@ -1231,14 +1197,6 @@ store_dts_ext(struct device *dev, struct device_attribute *attr, } -/* - Type 3: Thermal diode - Type 4: Thermistor - - Temp5-6, default TR - Temp1-4, default TD -*/ - static ssize_t show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1247,20 +1205,17 @@ show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; - u8 tmp; + int tmp; - if (data->has_temp >> index & 0x01) { - if (data->temp_mode >> index & 0x01) - tmp = 3; - else - tmp = 4; - } else { - tmp = 0; - } + if (data->temp_mode & (1 << index)) + tmp = 3; /* Thermal diode */ + else + tmp = 4; /* Thermistor */ return sprintf(buf, "%d\n", tmp); } +/* Only for temp1-4 (temp5-6 can only be thermistor) */ static ssize_t store_temp_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1270,45 +1225,31 @@ store_temp_mode(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; + int reg_shift; unsigned long val; u8 tmp; - u32 mask; if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; if ((val != 4) && (val != 3)) return -EINVAL; - if ((index > 3) && (val == 3)) - return -EINVAL; mutex_lock(&data->update_lock); if (val == 3) { - val = TEMP_CTRL_TD; - data->has_temp |= 1 << index; + /* Thermal diode */ + val = 0x01; data->temp_mode |= 1 << index; } else if (val == 4) { - val = TEMP_CTRL_TR; - data->has_temp |= 1 << index; - tmp = 1 << index; - data->temp_mode &= ~tmp; + /* Thermistor */ + val = 0x03; + data->temp_mode &= ~(1 << index); } - if (index > 3) - tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); - else - tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); - - mask = 0x03 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_SHIFT]; - tmp &= ~mask; - tmp |= W83795_REG_TEMP_CTRL[index][val]; - - mask = 1 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_HASIN_SHIFT]; - data->has_in &= ~mask; - - if (index > 3) - w83795_write(client, W83795_REG_TEMP_CTRL1, tmp); - else - w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); + reg_shift = 2 * index; + tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); + tmp &= ~(0x03 << reg_shift); + tmp |= val << reg_shift; + w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); mutex_unlock(&data->update_lock); return count; @@ -1506,7 +1447,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } #define SENSOR_ATTR_TEMP(index) { \ - SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \ + SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \ show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ NULL, TEMP_READ, index - 1), \ -- cgit v1.2.3 From 5f7b77cbd4599b6a90d18981d9883a3e20e689fb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Don't pre-read values we'll update later There is no point in reading registers during initialization if we will refresh the values in the update function later. This is only slowing down the driver loading with no benefit, stop doing it. This change saves 480 ms on driver load on my test system. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 07e8de58dcd4..a1d884bb58ad 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1903,7 +1903,7 @@ static int w83795_probe(struct i2c_client *client, } } - /* First update the voltages measured value and limits */ + /* Read the voltage limits */ for (i = 0; i < ARRAY_SIZE(data->in); i++) { if (!(data->has_in & (1 << i))) continue; @@ -1911,9 +1911,6 @@ static int w83795_probe(struct i2c_client *client, w83795_read(client, W83795_REG_IN[i][IN_MAX]); data->in[i][IN_LOW] = w83795_read(client, W83795_REG_IN[i][IN_LOW]); - tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; - tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; - data->in[i][IN_READ] = tmp; } for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { if ((i == 2 && data->chip_type == w83795adg) || @@ -1926,7 +1923,7 @@ static int w83795_probe(struct i2c_client *client, } data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; - /* First update fan and limits */ + /* Read the fan limits */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { /* Each register contains LSB for 2 fans, but we want to * read it only once to save time */ @@ -1939,11 +1936,9 @@ static int w83795_probe(struct i2c_client *client, w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; data->fan_min[i] |= (tmp >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; - data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; - data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; } - /* temperature and limits */ + /* Read the temperature limits */ for (i = 0; i < ARRAY_SIZE(data->temp); i++) { if (!(data->has_temp & (1 << i))) continue; @@ -1955,13 +1950,9 @@ static int w83795_probe(struct i2c_client *client, w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN]); data->temp[i][TEMP_WARN_HYST] = w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]); - data->temp[i][TEMP_READ] = - w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); - data->temp_read_vrlsb[i] = - w83795_read(client, W83795_REG_VRLSB); } - /* dts temperature and limits */ + /* Read the DTS limits */ if (data->enable_dts != 0) { data->dts_ext[DTS_CRIT] = w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT)); @@ -1971,13 +1962,6 @@ static int w83795_probe(struct i2c_client *client, w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN)); data->dts_ext[DTS_WARN_HYST] = w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN_HYST)); - for (i = 0; i < ARRAY_SIZE(data->dts); i++) { - if (!(data->has_dts & (1 << i))) - continue; - data->dts[i] = w83795_read(client, W83795_REG_DTS(i)); - data->dts_read_vrlsb[i] = - w83795_read(client, W83795_REG_VRLSB); - } } /* First update temp source selction */ @@ -1995,10 +1979,9 @@ static int w83795_probe(struct i2c_client *client, data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); for (i = 0; i < data->has_pwm; i++) { - for (tmp = 0; tmp < 5; tmp++) { + for (tmp = PWM_START; tmp <= PWM_FREQ; tmp++) data->pwm[i][tmp] = w83795_read(client, W83795_REG_PWM(i, tmp)); - } } for (i = 0; i < 8; i++) { data->target_speed[i] = @@ -2033,11 +2016,9 @@ static int w83795_probe(struct i2c_client *client, w83795_read(client, W83795_REG_SETUP_PWM(i)); } - /* alarm and beep */ - for (i = 0; i < ARRAY_SIZE(data->alarms); i++) { - data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); + /* Read beep settings */ + for (i = 0; i < ARRAY_SIZE(data->beeps); i++) data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); - } err = w83795_handle_files(dev, device_create_file); if (err) -- cgit v1.2.3 From fd7f82b8a37ff4d400c2db9c9fa8f9467dc54a08 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Make W83795_REG_PWM more efficient Cascaded conditionals are inefficient. Reorder the fields so that PWM register addresses can be computed more efficiently. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index a1d884bb58ad..35f87ca88cf3 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -178,15 +178,11 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { #define W83795_REG_TSS(index) (0x209 + (index)) #define PWM_OUTPUT 0 -#define PWM_START 1 -#define PWM_NONSTOP 2 -#define PWM_STOP_TIME 3 -#define PWM_FREQ 4 -#define W83795_REG_PWM(index, nr) \ - (((nr) == 0 ? 0x210 : \ - (nr) == 1 ? 0x220 : \ - (nr) == 2 ? 0x228 : \ - (nr) == 3 ? 0x230 : 0x218) + (index)) +#define PWM_FREQ 1 +#define PWM_START 2 +#define PWM_NONSTOP 3 +#define PWM_STOP_TIME 4 +#define W83795_REG_PWM(index, nr) (0x210 + (nr) * 8 + (index)) #define W83795_REG_FTSH(index) (0x240 + (index) * 2) #define W83795_REG_FTSL(index) (0x241 + (index) * 2) @@ -356,8 +352,8 @@ struct w83795_data { u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, * no config register, only affected by chip * type */ - u8 pwm[8][5]; /* Register value, output, start, non stop, stop - * time, freq */ + u8 pwm[8][5]; /* Register value, output, freq, start, + * non stop, stop time */ u16 clkin; /* CLKIN frequency in kHz */ u8 pwm_fcms[2]; /* Register value */ u8 pwm_tfmr[6]; /* Register value */ @@ -1979,7 +1975,7 @@ static int w83795_probe(struct i2c_client *client, data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); for (i = 0; i < data->has_pwm; i++) { - for (tmp = PWM_START; tmp <= PWM_FREQ; tmp++) + for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) data->pwm[i][tmp] = w83795_read(client, W83795_REG_PWM(i, tmp)); } -- cgit v1.2.3 From 476a4e5d3768ac72bb342166db294c0a9d2c010f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Pack similar register reads Pack similar register reads using for loops. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 35f87ca88cf3..e25a2e31df3f 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1938,26 +1938,16 @@ static int w83795_probe(struct i2c_client *client, for (i = 0; i < ARRAY_SIZE(data->temp); i++) { if (!(data->has_temp & (1 << i))) continue; - data->temp[i][TEMP_CRIT] = - w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT]); - data->temp[i][TEMP_CRIT_HYST] = - w83795_read(client, W83795_REG_TEMP[i][TEMP_CRIT_HYST]); - data->temp[i][TEMP_WARN] = - w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN]); - data->temp[i][TEMP_WARN_HYST] = - w83795_read(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]); + for (tmp = TEMP_CRIT; tmp <= TEMP_WARN_HYST; tmp++) + data->temp[i][tmp] = + w83795_read(client, W83795_REG_TEMP[i][tmp]); } /* Read the DTS limits */ if (data->enable_dts != 0) { - data->dts_ext[DTS_CRIT] = - w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT)); - data->dts_ext[DTS_CRIT_HYST] = - w83795_read(client, W83795_REG_DTS_EXT(DTS_CRIT_HYST)); - data->dts_ext[DTS_WARN] = - w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN)); - data->dts_ext[DTS_WARN_HYST] = - w83795_read(client, W83795_REG_DTS_EXT(DTS_WARN_HYST)); + for (i = DTS_CRIT; i <= DTS_WARN_HYST; i++) + data->dts_ext[i] = + w83795_read(client, W83795_REG_DTS_EXT(i)); } /* First update temp source selction */ -- cgit v1.2.3 From 0d7237bfd13a0a8df270654223c15a16b368a3bd Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Move register reads to dedicated functions Move initial register reads out of probe, to dedicated functions. This makes the code clearer, and will be needed if we want to delay calling these functions until they are needed, or want to call them periodically. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 218 +++++++++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 99 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index e25a2e31df3f..511bced1ee97 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -438,6 +438,123 @@ static int w83795_write(struct i2c_client *client, u16 reg, u8 value) return err; } +static void w83795_update_limits(struct i2c_client *client) +{ + struct w83795_data *data = i2c_get_clientdata(client); + int i, limit; + + /* Read the voltage limits */ + for (i = 0; i < ARRAY_SIZE(data->in); i++) { + if (!(data->has_in & (1 << i))) + continue; + data->in[i][IN_MAX] = + w83795_read(client, W83795_REG_IN[i][IN_MAX]); + data->in[i][IN_LOW] = + w83795_read(client, W83795_REG_IN[i][IN_LOW]); + } + for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { + if ((i == 2 && data->chip_type == w83795adg) || + (i >= 4 && !(data->has_in & (1 << (i + 11))))) + continue; + data->in_lsb[i][IN_MAX] = + w83795_read(client, IN_LSB_REG(i, IN_MAX)); + data->in_lsb[i][IN_LOW] = + w83795_read(client, IN_LSB_REG(i, IN_LOW)); + } + + /* Read the fan limits */ + for (i = 0; i < ARRAY_SIZE(data->fan); i++) { + u8 lsb; + + /* Each register contains LSB for 2 fans, but we want to + * read it only once to save time */ + if ((i & 1) == 0 && (data->has_fan & (3 << i))) + lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); + + if (!(data->has_fan & (1 << i))) + continue; + data->fan_min[i] = + w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; + data->fan_min[i] |= + (lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; + } + + /* Read the temperature limits */ + for (i = 0; i < ARRAY_SIZE(data->temp); i++) { + if (!(data->has_temp & (1 << i))) + continue; + for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++) + data->temp[i][limit] = + w83795_read(client, W83795_REG_TEMP[i][limit]); + } + + /* Read the DTS limits */ + if (data->enable_dts != 0) { + for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++) + data->dts_ext[limit] = + w83795_read(client, W83795_REG_DTS_EXT(limit)); + } + + /* Read beep settings */ + for (i = 0; i < ARRAY_SIZE(data->beeps); i++) + data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); +} + +static void w83795_update_pwm_config(struct i2c_client *client) +{ + struct w83795_data *data = i2c_get_clientdata(client); + int i, tmp; + + /* Read temperature source selection */ + for (i = 0; i < ARRAY_SIZE(data->temp_src); i++) + data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); + + /* Read automatic fan speed control settings */ + data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); + data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); + for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) + data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); + data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); + for (i = 0; i < data->has_pwm; i++) { + for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) + data->pwm[i][tmp] = + w83795_read(client, W83795_REG_PWM(i, tmp)); + } + for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) { + data->target_speed[i] = + w83795_read(client, W83795_REG_FTSH(i)) << 4; + data->target_speed[i] |= + w83795_read(client, W83795_REG_FTSL(i)) >> 4; + } + data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; + + for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { + data->pwm_temp[i][TEMP_PWM_TTTI] = + w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; + data->pwm_temp[i][TEMP_PWM_CTFS] = + w83795_read(client, W83795_REG_CTFS(i)); + tmp = w83795_read(client, W83795_REG_HT(i)); + data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; + data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; + } + + /* Read SmartFanIV trip points */ + for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { + for (tmp = 0; tmp < 7; tmp++) { + data->sf4_reg[i][SF4_TEMP][tmp] = + w83795_read(client, + W83795_REG_SF4_TEMP(i, tmp)); + data->sf4_reg[i][SF4_PWM][tmp] = + w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); + } + } + + /* Read setup PWM */ + for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++) + data->setup_pwm[i] = + w83795_read(client, W83795_REG_SETUP_PWM(i)); +} + static struct w83795_data *w83795_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -1899,112 +2016,15 @@ static int w83795_probe(struct i2c_client *client, } } - /* Read the voltage limits */ - for (i = 0; i < ARRAY_SIZE(data->in); i++) { - if (!(data->has_in & (1 << i))) - continue; - data->in[i][IN_MAX] = - w83795_read(client, W83795_REG_IN[i][IN_MAX]); - data->in[i][IN_LOW] = - w83795_read(client, W83795_REG_IN[i][IN_LOW]); - } - for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { - if ((i == 2 && data->chip_type == w83795adg) || - (i >= 4 && !(data->has_in & (1 << (i + 11))))) - continue; - data->in_lsb[i][IN_MAX] = - w83795_read(client, IN_LSB_REG(i, IN_MAX)); - data->in_lsb[i][IN_LOW] = - w83795_read(client, IN_LSB_REG(i, IN_LOW)); - } data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; - - /* Read the fan limits */ - for (i = 0; i < ARRAY_SIZE(data->fan); i++) { - /* Each register contains LSB for 2 fans, but we want to - * read it only once to save time */ - if ((i & 1) == 0 && (data->has_fan & (3 << i))) - tmp = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); - - if (!(data->has_fan & (1 << i))) - continue; - data->fan_min[i] = - w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; - data->fan_min[i] |= - (tmp >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; - } - - /* Read the temperature limits */ - for (i = 0; i < ARRAY_SIZE(data->temp); i++) { - if (!(data->has_temp & (1 << i))) - continue; - for (tmp = TEMP_CRIT; tmp <= TEMP_WARN_HYST; tmp++) - data->temp[i][tmp] = - w83795_read(client, W83795_REG_TEMP[i][tmp]); - } - - /* Read the DTS limits */ - if (data->enable_dts != 0) { - for (i = DTS_CRIT; i <= DTS_WARN_HYST; i++) - data->dts_ext[i] = - w83795_read(client, W83795_REG_DTS_EXT(i)); - } - - /* First update temp source selction */ - for (i = 0; i < 3; i++) - data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); + w83795_update_limits(client); /* pwm and smart fan */ if (data->chip_type == w83795g) data->has_pwm = 8; else data->has_pwm = 2; - data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); - data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); - for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) - data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); - data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); - for (i = 0; i < data->has_pwm; i++) { - for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) - data->pwm[i][tmp] = - w83795_read(client, W83795_REG_PWM(i, tmp)); - } - for (i = 0; i < 8; i++) { - data->target_speed[i] = - w83795_read(client, W83795_REG_FTSH(i)) << 4; - data->target_speed[i] |= - w83795_read(client, W83795_REG_FTSL(i)) >> 4; - } - data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; - - for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { - data->pwm_temp[i][TEMP_PWM_TTTI] = - w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; - data->pwm_temp[i][TEMP_PWM_CTFS] = - w83795_read(client, W83795_REG_CTFS(i)); - tmp = w83795_read(client, W83795_REG_HT(i)); - data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; - data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; - } - for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { - for (tmp = 0; tmp < 7; tmp++) { - data->sf4_reg[i][SF4_TEMP][tmp] = - w83795_read(client, - W83795_REG_SF4_TEMP(i, tmp)); - data->sf4_reg[i][SF4_PWM][tmp] = - w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); - } - } - - /* Setup PWM Register */ - for (i = 0; i < 3; i++) { - data->setup_pwm[i] = - w83795_read(client, W83795_REG_SETUP_PWM(i)); - } - - /* Read beep settings */ - for (i = 0; i < ARRAY_SIZE(data->beeps); i++) - data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); + w83795_update_pwm_config(client); err = w83795_handle_files(dev, device_create_file); if (err) -- cgit v1.2.3 From 2ae61de90545fe3dadae8119181c430d89a8627b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Delay reading limit registers Wait until we need the limit register values, instead of pre-reading them. This saves 544 ms on modprobe on my test system. Obviously this time is added when first running "sensors" or any other monitoring application, but I think it is better than slowing down the boot. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 511bced1ee97..6464a52b134b 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -371,6 +371,7 @@ struct w83795_data { u8 beeps[6]; /* Register value */ char valid; + char valid_limits; }; /* @@ -498,6 +499,8 @@ static void w83795_update_limits(struct i2c_client *client) /* Read beep settings */ for (i = 0; i < ARRAY_SIZE(data->beeps); i++) data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i)); + + data->valid_limits = 1; } static void w83795_update_pwm_config(struct i2c_client *client) @@ -564,6 +567,9 @@ static struct w83795_data *w83795_update_device(struct device *dev) mutex_lock(&data->update_lock); + if (!data->valid_limits) + w83795_update_limits(client); + if (!(time_after(jiffies, data->last_updated + HZ * 2) || !data->valid)) goto END; @@ -2017,7 +2023,6 @@ static int w83795_probe(struct i2c_client *client, } data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; - w83795_update_limits(client); /* pwm and smart fan */ if (data->chip_type == w83795g) -- cgit v1.2.3 From 1bb3450ce5050bc677c1995a60a0ddfe9e33e7b6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:48 +0200 Subject: hwmon: (w83795) Delay reading pwm config registers Wait until we need the pwm config register values, instead of pre-reading them. This saves over 1 second on modprobe on my test system. Obviously this time is added when first accessing pwm config attributes, however not everybody will use them, so it seems unfair to slow down driver loading (and thus boot) for an optional feature. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 51 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 6464a52b134b..78a876f35fa3 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -372,6 +372,7 @@ struct w83795_data { char valid; char valid_limits; + char valid_pwm_config; }; /* @@ -503,11 +504,17 @@ static void w83795_update_limits(struct i2c_client *client) data->valid_limits = 1; } -static void w83795_update_pwm_config(struct i2c_client *client) +static struct w83795_data *w83795_update_pwm_config(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct w83795_data *data = i2c_get_clientdata(client); int i, tmp; + mutex_lock(&data->update_lock); + + if (data->valid_pwm_config) + goto END; + /* Read temperature source selection */ for (i = 0; i < ARRAY_SIZE(data->temp_src); i++) data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); @@ -556,6 +563,12 @@ static void w83795_update_pwm_config(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++) data->setup_pwm[i] = w83795_read(client, W83795_REG_SETUP_PWM(i)); + + data->valid_pwm_config = 1; + +END: + mutex_unlock(&data->update_lock); + return data; } static struct w83795_data *w83795_update_device(struct device *dev) @@ -775,13 +788,16 @@ store_fan_min(struct device *dev, struct device_attribute *attr, static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83795_data *data = w83795_update_device(dev); + struct w83795_data *data; struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; unsigned int val; + data = nr == PWM_OUTPUT ? w83795_update_device(dev) + : w83795_update_pwm_config(dev); + switch (nr) { case PWM_STOP_TIME: val = time_from_reg(data->pwm[index][nr]); @@ -835,8 +851,7 @@ show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); int index = sensor_attr->index; u8 tmp; @@ -864,7 +879,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; @@ -905,8 +920,7 @@ show_temp_src(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); int index = sensor_attr->index; u8 val = index / 2; u8 tmp = data->temp_src[val]; @@ -926,7 +940,7 @@ store_temp_src(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; @@ -957,8 +971,7 @@ static ssize_t show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; @@ -986,7 +999,7 @@ store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; @@ -1023,8 +1036,7 @@ store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, static ssize_t show_fanin(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; @@ -1081,8 +1093,7 @@ store_fanin(struct device *dev, struct device_attribute *attr, static ssize_t show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; @@ -1143,8 +1154,7 @@ store_temp_pwm(struct device *dev, struct device_attribute *attr, static ssize_t show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; @@ -1179,8 +1189,7 @@ store_sf4_pwm(struct device *dev, struct device_attribute *attr, static ssize_t show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; @@ -1456,8 +1465,7 @@ show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = w83795_update_pwm_config(dev); u16 val = data->setup_pwm[nr]; switch (nr) { @@ -2029,7 +2037,6 @@ static int w83795_probe(struct i2c_client *client, data->has_pwm = 8; else data->has_pwm = 2; - w83795_update_pwm_config(client); err = w83795_handle_files(dev, device_create_file); if (err) -- cgit v1.2.3 From 21fc977551da43ec21ae0ebb859411afd4243d2b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:49 +0200 Subject: hwmon: (w83795) Use dev_get_drvdata() where possible When we don't need the client pointer, calling dev_get_drvdata() is more efficient that calling to_i2c_client() and then i2c_get_clientdata(). Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 78a876f35fa3..e916c04e8681 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1265,8 +1265,7 @@ store_temp(struct device *dev, struct device_attribute *attr, static ssize_t show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = dev_get_drvdata(dev); int tmp; if (data->enable_dts & 2) @@ -1296,8 +1295,7 @@ show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = dev_get_drvdata(dev); long temp = temp_from_reg(data->dts_ext[nr]); return sprintf(buf, "%ld\n", temp); @@ -1328,8 +1326,7 @@ store_dts_ext(struct device *dev, struct device_attribute *attr, static ssize_t show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83795_data *data = i2c_get_clientdata(client); + struct w83795_data *data = dev_get_drvdata(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; -- cgit v1.2.3 From 5d2cd958f777e533fa2809527836996f59b2d823 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:49 +0200 Subject: hwmon: (w83795) Fix LSB reading of voltage limits Wrong index caused the wrong register value to be read, resulting in random LSB for voltage limits. Signed-off-by: Jean Delvare --- drivers/hwmon/w83795.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index e916c04e8681..9d73768060d4 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1405,7 +1405,7 @@ show_in(struct device *dev, struct device_attribute *attr, char *buf) lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; val <<= 2; val |= (data->in_lsb[lsb_idx][nr] >> - IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03; + IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03; if ((index >= 17) && !((data->has_gain >> (index - 17)) & 1)) val *= 8; -- cgit v1.2.3 From eb02755a50f8f3508030b311e3788426fbdc23b7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:49 +0200 Subject: hwmon: (w83795) More style cleanups Cleanups suggested by Guenter Roeck, falling into 4 categories: * Swapping test orders, because if (var == CONSTANT) is much easier to read than if (CONSTANT == var). * Simplifying comparisons with 0. * Dropping unneeded masks. * Dropping unneeded parentheses and curly braces. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 9d73768060d4..ce1e71ba6c73 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -491,7 +491,7 @@ static void w83795_update_limits(struct i2c_client *client) } /* Read the DTS limits */ - if (data->enable_dts != 0) { + if (data->enable_dts) { for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++) data->dts_ext[limit] = w83795_read(client, W83795_REG_DTS_EXT(limit)); @@ -544,7 +544,7 @@ static struct w83795_data *w83795_update_pwm_config(struct device *dev) data->pwm_temp[i][TEMP_PWM_CTFS] = w83795_read(client, W83795_REG_CTFS(i)); tmp = w83795_read(client, W83795_REG_HT(i)); - data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f; + data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4; data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; } @@ -618,8 +618,7 @@ static struct w83795_data *w83795_update_device(struct device *dev) if (!(data->has_fan & (1 << i))) continue; data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; - data->fan[i] |= - (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F; + data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; } /* Update temperature */ @@ -631,7 +630,7 @@ static struct w83795_data *w83795_update_device(struct device *dev) } /* Update dts temperature */ - if (data->enable_dts != 0) { + if (data->enable_dts) { for (i = 0; i < ARRAY_SIZE(data->dts); i++) { if (!(data->has_dts & (1 << i))) continue; @@ -677,11 +676,10 @@ show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) int bit = sensor_attr->index & 0x07; u8 val; - if (ALARM_STATUS == nr) { - val = (data->alarms[index] >> (bit)) & 1; - } else { /* BEEP_ENABLE */ - val = (data->beeps[index] >> (bit)) & 1; - } + if (nr == ALARM_STATUS) + val = (data->alarms[index] >> bit) & 1; + else /* BEEP_ENABLE */ + val = (data->beeps[index] >> bit) & 1; return sprintf(buf, "%u\n", val); } @@ -744,7 +742,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf) struct w83795_data *data = w83795_update_device(dev); u16 val; - if (FAN_INPUT == nr) + if (nr == FAN_INPUT) val = data->fan[index] & 0x0fff; else val = data->fan_min[index] & 0x0fff; @@ -1011,7 +1009,7 @@ store_temp_pwm_enable(struct device *dev, struct device_attribute *attr, switch (nr) { case TEMP_PWM_ENABLE: - if ((tmp != 3) && (tmp != 4)) + if (tmp != 3 && tmp != 4) return -EINVAL; tmp -= 3; mutex_lock(&data->update_lock); @@ -1074,7 +1072,7 @@ store_fanin(struct device *dev, struct device_attribute *attr, switch (nr) { case FANIN_TARGET: val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff)); - w83795_write(client, W83795_REG_FTSH(index), (val >> 4) & 0xff); + w83795_write(client, W83795_REG_FTSH(index), val >> 4); w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); data->target_speed[index] = val; break; @@ -1234,7 +1232,7 @@ show_temp(struct device *dev, struct device_attribute *attr, char *buf) struct w83795_data *data = w83795_update_device(dev); long temp = temp_from_reg(data->temp[index][nr]); - if (TEMP_READ == nr) + if (nr == TEMP_READ) temp += (data->temp_read_vrlsb[index] >> 6) * 250; return sprintf(buf, "%ld\n", temp); } @@ -1891,7 +1889,7 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, } } - if (data->enable_dts != 0) { + if (data->enable_dts) { for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { if (!(data->has_dts & (1 << i))) continue; -- cgit v1.2.3 From e3760b432d589ddd9bdb8c337539b815125bc7aa Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:49 +0200 Subject: hwmon: (w83795) Add myself as co-author and maintainer I've made so many changes to the w83795 driver that it's only fair to list myself as a co-author. I'll also maintain the driver for some time. There's more work needed on the driver for sure. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index ce1e71ba6c73..a9116ad747f2 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -2,6 +2,7 @@ * w83795.c - Linux kernel driver for hardware monitoring * Copyright (C) 2008 Nuvoton Technology Corp. * Wei Song + * Copyright (C) 2010 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2097,7 +2098,7 @@ static void __exit sensors_w83795_exit(void) i2c_del_driver(&w83795_driver); } -MODULE_AUTHOR("Wei Song"); +MODULE_AUTHOR("Wei Song, Jean Delvare "); MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 00030af23153f1958f015df8b9fec8c29fcca8b8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:49 +0200 Subject: hwmon: (w83795) Exclude fan control feature by default The fan control feature of the w83795 driver is insufficiently reviewed and tested for public consumption at this time, so make it optional and disabled by default. We will change the default when review and testing is deemed sufficient. Ultimately the option will go away. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index a9116ad747f2..c461e753f9bf 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1455,6 +1455,7 @@ store_in(struct device *dev, struct device_attribute *attr, } +#ifdef CONFIG_SENSORS_W83795_FANCTRL static ssize_t show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1506,6 +1507,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, mutex_unlock(&data->update_lock); return count; } +#endif #define NOT_USED -1 @@ -1711,6 +1713,7 @@ static const struct sensor_device_attribute_2 sda_single_files[] = { store_chassis_clear, ALARM_STATUS, 46), SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, store_beep, BEEP_ENABLE, 47), +#ifdef CONFIG_SENSORS_W83795_FANCTRL SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, store_fanin, FANIN_TOL, NOT_USED), SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, @@ -1719,6 +1722,7 @@ static const struct sensor_device_attribute_2 sda_single_files[] = { store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), +#endif }; /* @@ -1872,6 +1876,7 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, return err; } +#ifdef CONFIG_SENSORS_W83795_FANCTRL for (i = 0; i < data->has_pwm; i++) { for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) { err = fn(dev, &w83795_pwm[i][j].dev_attr); @@ -1879,11 +1884,16 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *, return err; } } +#endif for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { if (!(data->has_temp & (1 << i))) continue; +#ifdef CONFIG_SENSORS_W83795_FANCTRL for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) { +#else + for (j = 0; j < 8; j++) { +#endif err = fn(dev, &w83795_temp[i][j].dev_attr); if (err) return err; -- cgit v1.2.3 From 24377101023d3c66136123bd8b20441814da6a90 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 28 Oct 2010 20:31:49 +0200 Subject: hwmon: (w83795) Use standard attributes for chassis intrusion Follow the standard attribute naming for the chassis intrusion feature. I couldn't test the beeping (my board apparently doesn't do that) but the alarm works fine. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon/w83795.c') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index c461e753f9bf..1d840aa83782 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -713,7 +713,7 @@ store_beep(struct device *dev, struct device_attribute *attr, return count; } -/* Write any value to clear chassis alarm */ +/* Write 0 to clear chassis alarm */ static ssize_t store_chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, @@ -721,7 +721,10 @@ store_chassis_clear(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct w83795_data *data = i2c_get_clientdata(client); - u8 val; + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0 || val != 0) + return -EINVAL; mutex_lock(&data->update_lock); val = w83795_read(client, W83795_REG_CLR_CHASSIS); @@ -1709,8 +1712,10 @@ static const struct sensor_device_attribute_2 w83795_pwm[][7] = { }; static const struct sensor_device_attribute_2 sda_single_files[] = { - SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, + SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, store_chassis_clear, ALARM_STATUS, 46), + SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep, + store_beep, BEEP_ENABLE, 46), SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, store_beep, BEEP_ENABLE, 47), #ifdef CONFIG_SENSORS_W83795_FANCTRL -- cgit v1.2.3