18d5d45fbSJean Delvare /* 28d5d45fbSJean Delvare adm1031.c - Part of lm_sensors, Linux kernel modules for hardware 38d5d45fbSJean Delvare monitoring 48d5d45fbSJean Delvare Based on lm75.c and lm85.c 58d5d45fbSJean Delvare Supports adm1030 / adm1031 68d5d45fbSJean Delvare Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org> 78d5d45fbSJean Delvare Reworked by Jean Delvare <khali@linux-fr.org> 88d5d45fbSJean Delvare 98d5d45fbSJean Delvare This program is free software; you can redistribute it and/or modify 108d5d45fbSJean Delvare it under the terms of the GNU General Public License as published by 118d5d45fbSJean Delvare the Free Software Foundation; either version 2 of the License, or 128d5d45fbSJean Delvare (at your option) any later version. 138d5d45fbSJean Delvare 148d5d45fbSJean Delvare This program is distributed in the hope that it will be useful, 158d5d45fbSJean Delvare but WITHOUT ANY WARRANTY; without even the implied warranty of 168d5d45fbSJean Delvare MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178d5d45fbSJean Delvare GNU General Public License for more details. 188d5d45fbSJean Delvare 198d5d45fbSJean Delvare You should have received a copy of the GNU General Public License 208d5d45fbSJean Delvare along with this program; if not, write to the Free Software 218d5d45fbSJean Delvare Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 228d5d45fbSJean Delvare */ 238d5d45fbSJean Delvare 248d5d45fbSJean Delvare #include <linux/module.h> 258d5d45fbSJean Delvare #include <linux/init.h> 268d5d45fbSJean Delvare #include <linux/slab.h> 278d5d45fbSJean Delvare #include <linux/jiffies.h> 288d5d45fbSJean Delvare #include <linux/i2c.h> 29943b0830SMark M. Hoffman #include <linux/hwmon.h> 30943b0830SMark M. Hoffman #include <linux/err.h> 319a61bf63SIngo Molnar #include <linux/mutex.h> 328d5d45fbSJean Delvare 338d5d45fbSJean Delvare /* Following macros takes channel parameter starting from 0 to 2 */ 348d5d45fbSJean Delvare #define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) 358d5d45fbSJean Delvare #define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) 368d5d45fbSJean Delvare #define ADM1031_REG_PWM (0x22) 378d5d45fbSJean Delvare #define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) 388d5d45fbSJean Delvare 398d5d45fbSJean Delvare #define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr)) 408d5d45fbSJean Delvare #define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr)) 418d5d45fbSJean Delvare #define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr)) 428d5d45fbSJean Delvare 438d5d45fbSJean Delvare #define ADM1031_REG_TEMP(nr) (0xa + (nr)) 448d5d45fbSJean Delvare #define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) 458d5d45fbSJean Delvare 468d5d45fbSJean Delvare #define ADM1031_REG_STATUS(nr) (0x2 + (nr)) 478d5d45fbSJean Delvare 488d5d45fbSJean Delvare #define ADM1031_REG_CONF1 0x0 498d5d45fbSJean Delvare #define ADM1031_REG_CONF2 0x1 508d5d45fbSJean Delvare #define ADM1031_REG_EXT_TEMP 0x6 518d5d45fbSJean Delvare 528d5d45fbSJean Delvare #define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ 538d5d45fbSJean Delvare #define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ 548d5d45fbSJean Delvare #define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */ 558d5d45fbSJean Delvare 568d5d45fbSJean Delvare #define ADM1031_CONF2_PWM1_ENABLE 0x01 578d5d45fbSJean Delvare #define ADM1031_CONF2_PWM2_ENABLE 0x02 588d5d45fbSJean Delvare #define ADM1031_CONF2_TACH1_ENABLE 0x04 598d5d45fbSJean Delvare #define ADM1031_CONF2_TACH2_ENABLE 0x08 608d5d45fbSJean Delvare #define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) 618d5d45fbSJean Delvare 628d5d45fbSJean Delvare /* Addresses to scan */ 638d5d45fbSJean Delvare static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 648d5d45fbSJean Delvare 658d5d45fbSJean Delvare /* Insmod parameters */ 66f4b50261SJean Delvare I2C_CLIENT_INSMOD_2(adm1030, adm1031); 678d5d45fbSJean Delvare 688d5d45fbSJean Delvare typedef u8 auto_chan_table_t[8][2]; 698d5d45fbSJean Delvare 708d5d45fbSJean Delvare /* Each client has this additional data */ 718d5d45fbSJean Delvare struct adm1031_data { 728d5d45fbSJean Delvare struct i2c_client client; 73943b0830SMark M. Hoffman struct class_device *class_dev; 749a61bf63SIngo Molnar struct mutex update_lock; 758d5d45fbSJean Delvare int chip_type; 768d5d45fbSJean Delvare char valid; /* !=0 if following fields are valid */ 778d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */ 788d5d45fbSJean Delvare /* The chan_select_table contains the possible configurations for 798d5d45fbSJean Delvare * auto fan control. 808d5d45fbSJean Delvare */ 818d5d45fbSJean Delvare auto_chan_table_t *chan_select_table; 828d5d45fbSJean Delvare u16 alarm; 838d5d45fbSJean Delvare u8 conf1; 848d5d45fbSJean Delvare u8 conf2; 858d5d45fbSJean Delvare u8 fan[2]; 868d5d45fbSJean Delvare u8 fan_div[2]; 878d5d45fbSJean Delvare u8 fan_min[2]; 888d5d45fbSJean Delvare u8 pwm[2]; 898d5d45fbSJean Delvare u8 old_pwm[2]; 908d5d45fbSJean Delvare s8 temp[3]; 918d5d45fbSJean Delvare u8 ext_temp[3]; 928d5d45fbSJean Delvare u8 auto_temp[3]; 938d5d45fbSJean Delvare u8 auto_temp_min[3]; 948d5d45fbSJean Delvare u8 auto_temp_off[3]; 958d5d45fbSJean Delvare u8 auto_temp_max[3]; 968d5d45fbSJean Delvare s8 temp_min[3]; 978d5d45fbSJean Delvare s8 temp_max[3]; 988d5d45fbSJean Delvare s8 temp_crit[3]; 998d5d45fbSJean Delvare }; 1008d5d45fbSJean Delvare 1018d5d45fbSJean Delvare static int adm1031_attach_adapter(struct i2c_adapter *adapter); 1028d5d45fbSJean Delvare static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind); 1038d5d45fbSJean Delvare static void adm1031_init_client(struct i2c_client *client); 1048d5d45fbSJean Delvare static int adm1031_detach_client(struct i2c_client *client); 1058d5d45fbSJean Delvare static struct adm1031_data *adm1031_update_device(struct device *dev); 1068d5d45fbSJean Delvare 1078d5d45fbSJean Delvare /* This is the driver that will be inserted */ 1088d5d45fbSJean Delvare static struct i2c_driver adm1031_driver = { 109cdaf7934SLaurent Riffard .driver = { 1108d5d45fbSJean Delvare .name = "adm1031", 111cdaf7934SLaurent Riffard }, 1128d5d45fbSJean Delvare .attach_adapter = adm1031_attach_adapter, 1138d5d45fbSJean Delvare .detach_client = adm1031_detach_client, 1148d5d45fbSJean Delvare }; 1158d5d45fbSJean Delvare 1168d5d45fbSJean Delvare static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) 1178d5d45fbSJean Delvare { 1188d5d45fbSJean Delvare return i2c_smbus_read_byte_data(client, reg); 1198d5d45fbSJean Delvare } 1208d5d45fbSJean Delvare 1218d5d45fbSJean Delvare static inline int 1228d5d45fbSJean Delvare adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) 1238d5d45fbSJean Delvare { 1248d5d45fbSJean Delvare return i2c_smbus_write_byte_data(client, reg, value); 1258d5d45fbSJean Delvare } 1268d5d45fbSJean Delvare 1278d5d45fbSJean Delvare 1288d5d45fbSJean Delvare #define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \ 1298d5d45fbSJean Delvare ((val + 500) / 1000))) 1308d5d45fbSJean Delvare 1318d5d45fbSJean Delvare #define TEMP_FROM_REG(val) ((val) * 1000) 1328d5d45fbSJean Delvare 1338d5d45fbSJean Delvare #define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125) 1348d5d45fbSJean Delvare 1358d5d45fbSJean Delvare #define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) 1368d5d45fbSJean Delvare 1378d5d45fbSJean Delvare static int FAN_TO_REG(int reg, int div) 1388d5d45fbSJean Delvare { 1398d5d45fbSJean Delvare int tmp; 1408d5d45fbSJean Delvare tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div); 1418d5d45fbSJean Delvare return tmp > 255 ? 255 : tmp; 1428d5d45fbSJean Delvare } 1438d5d45fbSJean Delvare 1448d5d45fbSJean Delvare #define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) 1458d5d45fbSJean Delvare 1468d5d45fbSJean Delvare #define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4) 1478d5d45fbSJean Delvare #define PWM_FROM_REG(val) ((val) << 4) 1488d5d45fbSJean Delvare 1498d5d45fbSJean Delvare #define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) 1508d5d45fbSJean Delvare #define FAN_CHAN_TO_REG(val, reg) \ 1518d5d45fbSJean Delvare (((reg) & 0x1F) | (((val) << 5) & 0xe0)) 1528d5d45fbSJean Delvare 1538d5d45fbSJean Delvare #define AUTO_TEMP_MIN_TO_REG(val, reg) \ 1548d5d45fbSJean Delvare ((((val)/500) & 0xf8)|((reg) & 0x7)) 1558d5d45fbSJean Delvare #define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) 1568d5d45fbSJean Delvare #define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) 1578d5d45fbSJean Delvare 1588d5d45fbSJean Delvare #define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) 1598d5d45fbSJean Delvare 1608d5d45fbSJean Delvare #define AUTO_TEMP_OFF_FROM_REG(reg) \ 1618d5d45fbSJean Delvare (AUTO_TEMP_MIN_FROM_REG(reg) - 5000) 1628d5d45fbSJean Delvare 1638d5d45fbSJean Delvare #define AUTO_TEMP_MAX_FROM_REG(reg) \ 1648d5d45fbSJean Delvare (AUTO_TEMP_RANGE_FROM_REG(reg) + \ 1658d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG(reg)) 1668d5d45fbSJean Delvare 1678d5d45fbSJean Delvare static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) 1688d5d45fbSJean Delvare { 1698d5d45fbSJean Delvare int ret; 1708d5d45fbSJean Delvare int range = val - AUTO_TEMP_MIN_FROM_REG(reg); 1718d5d45fbSJean Delvare 1728d5d45fbSJean Delvare range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm); 1738d5d45fbSJean Delvare ret = ((reg & 0xf8) | 1748d5d45fbSJean Delvare (range < 10000 ? 0 : 1758d5d45fbSJean Delvare range < 20000 ? 1 : 1768d5d45fbSJean Delvare range < 40000 ? 2 : range < 80000 ? 3 : 4)); 1778d5d45fbSJean Delvare return ret; 1788d5d45fbSJean Delvare } 1798d5d45fbSJean Delvare 1808d5d45fbSJean Delvare /* FAN auto control */ 1818d5d45fbSJean Delvare #define GET_FAN_AUTO_BITFIELD(data, idx) \ 1828d5d45fbSJean Delvare (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] 1838d5d45fbSJean Delvare 1848d5d45fbSJean Delvare /* The tables below contains the possible values for the auto fan 1858d5d45fbSJean Delvare * control bitfields. the index in the table is the register value. 1868d5d45fbSJean Delvare * MSb is the auto fan control enable bit, so the four first entries 1878d5d45fbSJean Delvare * in the table disables auto fan control when both bitfields are zero. 1888d5d45fbSJean Delvare */ 1898d5d45fbSJean Delvare static auto_chan_table_t auto_channel_select_table_adm1031 = { 1908d5d45fbSJean Delvare {0, 0}, {0, 0}, {0, 0}, {0, 0}, 1918d5d45fbSJean Delvare {2 /*0b010 */ , 4 /*0b100 */ }, 1928d5d45fbSJean Delvare {2 /*0b010 */ , 2 /*0b010 */ }, 1938d5d45fbSJean Delvare {4 /*0b100 */ , 4 /*0b100 */ }, 1948d5d45fbSJean Delvare {7 /*0b111 */ , 7 /*0b111 */ }, 1958d5d45fbSJean Delvare }; 1968d5d45fbSJean Delvare 1978d5d45fbSJean Delvare static auto_chan_table_t auto_channel_select_table_adm1030 = { 1988d5d45fbSJean Delvare {0, 0}, {0, 0}, {0, 0}, {0, 0}, 1998d5d45fbSJean Delvare {2 /*0b10 */ , 0}, 2008d5d45fbSJean Delvare {0xff /*invalid */ , 0}, 2018d5d45fbSJean Delvare {0xff /*invalid */ , 0}, 2028d5d45fbSJean Delvare {3 /*0b11 */ , 0}, 2038d5d45fbSJean Delvare }; 2048d5d45fbSJean Delvare 2058d5d45fbSJean Delvare /* That function checks if a bitfield is valid and returns the other bitfield 2068d5d45fbSJean Delvare * nearest match if no exact match where found. 2078d5d45fbSJean Delvare */ 2088d5d45fbSJean Delvare static int 2098d5d45fbSJean Delvare get_fan_auto_nearest(struct adm1031_data *data, 2108d5d45fbSJean Delvare int chan, u8 val, u8 reg, u8 * new_reg) 2118d5d45fbSJean Delvare { 2128d5d45fbSJean Delvare int i; 2138d5d45fbSJean Delvare int first_match = -1, exact_match = -1; 2148d5d45fbSJean Delvare u8 other_reg_val = 2158d5d45fbSJean Delvare (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; 2168d5d45fbSJean Delvare 2178d5d45fbSJean Delvare if (val == 0) { 2188d5d45fbSJean Delvare *new_reg = 0; 2198d5d45fbSJean Delvare return 0; 2208d5d45fbSJean Delvare } 2218d5d45fbSJean Delvare 2228d5d45fbSJean Delvare for (i = 0; i < 8; i++) { 2238d5d45fbSJean Delvare if ((val == (*data->chan_select_table)[i][chan]) && 2248d5d45fbSJean Delvare ((*data->chan_select_table)[i][chan ? 0 : 1] == 2258d5d45fbSJean Delvare other_reg_val)) { 2268d5d45fbSJean Delvare /* We found an exact match */ 2278d5d45fbSJean Delvare exact_match = i; 2288d5d45fbSJean Delvare break; 2298d5d45fbSJean Delvare } else if (val == (*data->chan_select_table)[i][chan] && 2308d5d45fbSJean Delvare first_match == -1) { 2318d5d45fbSJean Delvare /* Save the first match in case of an exact match has not been 2328d5d45fbSJean Delvare * found 2338d5d45fbSJean Delvare */ 2348d5d45fbSJean Delvare first_match = i; 2358d5d45fbSJean Delvare } 2368d5d45fbSJean Delvare } 2378d5d45fbSJean Delvare 2388d5d45fbSJean Delvare if (exact_match >= 0) { 2398d5d45fbSJean Delvare *new_reg = exact_match; 2408d5d45fbSJean Delvare } else if (first_match >= 0) { 2418d5d45fbSJean Delvare *new_reg = first_match; 2428d5d45fbSJean Delvare } else { 2438d5d45fbSJean Delvare return -EINVAL; 2448d5d45fbSJean Delvare } 2458d5d45fbSJean Delvare return 0; 2468d5d45fbSJean Delvare } 2478d5d45fbSJean Delvare 2488d5d45fbSJean Delvare static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr) 2498d5d45fbSJean Delvare { 2508d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 2518d5d45fbSJean Delvare return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); 2528d5d45fbSJean Delvare } 2538d5d45fbSJean Delvare 2548d5d45fbSJean Delvare static ssize_t 2558d5d45fbSJean Delvare set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) 2568d5d45fbSJean Delvare { 2578d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 2588d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 2598d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 2608d5d45fbSJean Delvare u8 reg; 2618d5d45fbSJean Delvare int ret; 2628d5d45fbSJean Delvare u8 old_fan_mode; 2638d5d45fbSJean Delvare 2648d5d45fbSJean Delvare old_fan_mode = data->conf1; 2658d5d45fbSJean Delvare 2669a61bf63SIngo Molnar mutex_lock(&data->update_lock); 2678d5d45fbSJean Delvare 2688d5d45fbSJean Delvare if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { 2699a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 2708d5d45fbSJean Delvare return ret; 2718d5d45fbSJean Delvare } 2728d5d45fbSJean Delvare if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ 2738d5d45fbSJean Delvare (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { 2748d5d45fbSJean Delvare if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ 2758d5d45fbSJean Delvare /* Switch to Auto Fan Mode 2768d5d45fbSJean Delvare * Save PWM registers 2778d5d45fbSJean Delvare * Set PWM registers to 33% Both */ 2788d5d45fbSJean Delvare data->old_pwm[0] = data->pwm[0]; 2798d5d45fbSJean Delvare data->old_pwm[1] = data->pwm[1]; 2808d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_PWM, 0x55); 2818d5d45fbSJean Delvare } else { 2828d5d45fbSJean Delvare /* Switch to Manual Mode */ 2838d5d45fbSJean Delvare data->pwm[0] = data->old_pwm[0]; 2848d5d45fbSJean Delvare data->pwm[1] = data->old_pwm[1]; 2858d5d45fbSJean Delvare /* Restore PWM registers */ 2868d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_PWM, 2878d5d45fbSJean Delvare data->pwm[0] | (data->pwm[1] << 4)); 2888d5d45fbSJean Delvare } 2898d5d45fbSJean Delvare } 2908d5d45fbSJean Delvare data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); 2918d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); 2929a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 2938d5d45fbSJean Delvare return count; 2948d5d45fbSJean Delvare } 2958d5d45fbSJean Delvare 2968d5d45fbSJean Delvare #define fan_auto_channel_offset(offset) \ 2978d5d45fbSJean Delvare static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 2988d5d45fbSJean Delvare { \ 2998d5d45fbSJean Delvare return show_fan_auto_channel(dev, buf, offset - 1); \ 3008d5d45fbSJean Delvare } \ 3018d5d45fbSJean Delvare static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ 3028d5d45fbSJean Delvare const char *buf, size_t count) \ 3038d5d45fbSJean Delvare { \ 3048d5d45fbSJean Delvare return set_fan_auto_channel(dev, buf, count, offset - 1); \ 3058d5d45fbSJean Delvare } \ 3068d5d45fbSJean Delvare static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \ 3078d5d45fbSJean Delvare show_fan_auto_channel_##offset, \ 3088d5d45fbSJean Delvare set_fan_auto_channel_##offset) 3098d5d45fbSJean Delvare 3108d5d45fbSJean Delvare fan_auto_channel_offset(1); 3118d5d45fbSJean Delvare fan_auto_channel_offset(2); 3128d5d45fbSJean Delvare 3138d5d45fbSJean Delvare /* Auto Temps */ 3148d5d45fbSJean Delvare static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr) 3158d5d45fbSJean Delvare { 3168d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 3178d5d45fbSJean Delvare return sprintf(buf, "%d\n", 3188d5d45fbSJean Delvare AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); 3198d5d45fbSJean Delvare } 3208d5d45fbSJean Delvare static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr) 3218d5d45fbSJean Delvare { 3228d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 3238d5d45fbSJean Delvare return sprintf(buf, "%d\n", 3248d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); 3258d5d45fbSJean Delvare } 3268d5d45fbSJean Delvare static ssize_t 3278d5d45fbSJean Delvare set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) 3288d5d45fbSJean Delvare { 3298d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 3308d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 3318d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 3328d5d45fbSJean Delvare 3339a61bf63SIngo Molnar mutex_lock(&data->update_lock); 3348d5d45fbSJean Delvare data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); 3358d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), 3368d5d45fbSJean Delvare data->auto_temp[nr]); 3379a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 3388d5d45fbSJean Delvare return count; 3398d5d45fbSJean Delvare } 3408d5d45fbSJean Delvare static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) 3418d5d45fbSJean Delvare { 3428d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 3438d5d45fbSJean Delvare return sprintf(buf, "%d\n", 3448d5d45fbSJean Delvare AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); 3458d5d45fbSJean Delvare } 3468d5d45fbSJean Delvare static ssize_t 3478d5d45fbSJean Delvare set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) 3488d5d45fbSJean Delvare { 3498d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 3508d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 3518d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 3528d5d45fbSJean Delvare 3539a61bf63SIngo Molnar mutex_lock(&data->update_lock); 3548d5d45fbSJean Delvare data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); 3558d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), 3568d5d45fbSJean Delvare data->temp_max[nr]); 3579a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 3588d5d45fbSJean Delvare return count; 3598d5d45fbSJean Delvare } 3608d5d45fbSJean Delvare 3618d5d45fbSJean Delvare #define auto_temp_reg(offset) \ 3628d5d45fbSJean Delvare static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ 3638d5d45fbSJean Delvare { \ 3648d5d45fbSJean Delvare return show_auto_temp_off(dev, buf, offset - 1); \ 3658d5d45fbSJean Delvare } \ 3668d5d45fbSJean Delvare static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ 3678d5d45fbSJean Delvare { \ 3688d5d45fbSJean Delvare return show_auto_temp_min(dev, buf, offset - 1); \ 3698d5d45fbSJean Delvare } \ 3708d5d45fbSJean Delvare static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ 3718d5d45fbSJean Delvare { \ 3728d5d45fbSJean Delvare return show_auto_temp_max(dev, buf, offset - 1); \ 3738d5d45fbSJean Delvare } \ 3748d5d45fbSJean Delvare static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ 3758d5d45fbSJean Delvare const char *buf, size_t count) \ 3768d5d45fbSJean Delvare { \ 3778d5d45fbSJean Delvare return set_auto_temp_min(dev, buf, count, offset - 1); \ 3788d5d45fbSJean Delvare } \ 3798d5d45fbSJean Delvare static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ 3808d5d45fbSJean Delvare const char *buf, size_t count) \ 3818d5d45fbSJean Delvare { \ 3828d5d45fbSJean Delvare return set_auto_temp_max(dev, buf, count, offset - 1); \ 3838d5d45fbSJean Delvare } \ 3848d5d45fbSJean Delvare static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ 3858d5d45fbSJean Delvare show_auto_temp_##offset##_off, NULL); \ 3868d5d45fbSJean Delvare static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ 3878d5d45fbSJean Delvare show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\ 3888d5d45fbSJean Delvare static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ 3898d5d45fbSJean Delvare show_auto_temp_##offset##_max, set_auto_temp_##offset##_max) 3908d5d45fbSJean Delvare 3918d5d45fbSJean Delvare auto_temp_reg(1); 3928d5d45fbSJean Delvare auto_temp_reg(2); 3938d5d45fbSJean Delvare auto_temp_reg(3); 3948d5d45fbSJean Delvare 3958d5d45fbSJean Delvare /* pwm */ 3968d5d45fbSJean Delvare static ssize_t show_pwm(struct device *dev, char *buf, int nr) 3978d5d45fbSJean Delvare { 3988d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 3998d5d45fbSJean Delvare return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); 4008d5d45fbSJean Delvare } 4018d5d45fbSJean Delvare static ssize_t 4028d5d45fbSJean Delvare set_pwm(struct device *dev, const char *buf, size_t count, int nr) 4038d5d45fbSJean Delvare { 4048d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 4058d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 4068d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 4078d5d45fbSJean Delvare int reg; 4088d5d45fbSJean Delvare 4099a61bf63SIngo Molnar mutex_lock(&data->update_lock); 4108d5d45fbSJean Delvare if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && 4118d5d45fbSJean Delvare (((val>>4) & 0xf) != 5)) { 4128d5d45fbSJean Delvare /* In automatic mode, the only PWM accepted is 33% */ 4139a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4148d5d45fbSJean Delvare return -EINVAL; 4158d5d45fbSJean Delvare } 4168d5d45fbSJean Delvare data->pwm[nr] = PWM_TO_REG(val); 4178d5d45fbSJean Delvare reg = adm1031_read_value(client, ADM1031_REG_PWM); 4188d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_PWM, 4198d5d45fbSJean Delvare nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf) 4208d5d45fbSJean Delvare : (data->pwm[nr] & 0xf) | (reg & 0xf0)); 4219a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 4228d5d45fbSJean Delvare return count; 4238d5d45fbSJean Delvare } 4248d5d45fbSJean Delvare 4258d5d45fbSJean Delvare #define pwm_reg(offset) \ 4268d5d45fbSJean Delvare static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 4278d5d45fbSJean Delvare { \ 4288d5d45fbSJean Delvare return show_pwm(dev, buf, offset - 1); \ 4298d5d45fbSJean Delvare } \ 4308d5d45fbSJean Delvare static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ 4318d5d45fbSJean Delvare const char *buf, size_t count) \ 4328d5d45fbSJean Delvare { \ 4338d5d45fbSJean Delvare return set_pwm(dev, buf, count, offset - 1); \ 4348d5d45fbSJean Delvare } \ 4358d5d45fbSJean Delvare static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ 4368d5d45fbSJean Delvare show_pwm_##offset, set_pwm_##offset) 4378d5d45fbSJean Delvare 4388d5d45fbSJean Delvare pwm_reg(1); 4398d5d45fbSJean Delvare pwm_reg(2); 4408d5d45fbSJean Delvare 4418d5d45fbSJean Delvare /* Fans */ 4428d5d45fbSJean Delvare 4438d5d45fbSJean Delvare /* 4448d5d45fbSJean Delvare * That function checks the cases where the fan reading is not 4458d5d45fbSJean Delvare * relevant. It is used to provide 0 as fan reading when the fan is 4468d5d45fbSJean Delvare * not supposed to run 4478d5d45fbSJean Delvare */ 4488d5d45fbSJean Delvare static int trust_fan_readings(struct adm1031_data *data, int chan) 4498d5d45fbSJean Delvare { 4508d5d45fbSJean Delvare int res = 0; 4518d5d45fbSJean Delvare 4528d5d45fbSJean Delvare if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { 4538d5d45fbSJean Delvare switch (data->conf1 & 0x60) { 4548d5d45fbSJean Delvare case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ 4558d5d45fbSJean Delvare res = data->temp[chan+1] >= 4568d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); 4578d5d45fbSJean Delvare break; 4588d5d45fbSJean Delvare case 0x20: /* remote temp1 controls both fans */ 4598d5d45fbSJean Delvare res = 4608d5d45fbSJean Delvare data->temp[1] >= 4618d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]); 4628d5d45fbSJean Delvare break; 4638d5d45fbSJean Delvare case 0x40: /* remote temp2 controls both fans */ 4648d5d45fbSJean Delvare res = 4658d5d45fbSJean Delvare data->temp[2] >= 4668d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]); 4678d5d45fbSJean Delvare break; 4688d5d45fbSJean Delvare case 0x60: /* max controls both fans */ 4698d5d45fbSJean Delvare res = 4708d5d45fbSJean Delvare data->temp[0] >= 4718d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) 4728d5d45fbSJean Delvare || data->temp[1] >= 4738d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) 4748d5d45fbSJean Delvare || (data->chip_type == adm1031 4758d5d45fbSJean Delvare && data->temp[2] >= 4768d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); 4778d5d45fbSJean Delvare break; 4788d5d45fbSJean Delvare } 4798d5d45fbSJean Delvare } else { 4808d5d45fbSJean Delvare res = data->pwm[chan] > 0; 4818d5d45fbSJean Delvare } 4828d5d45fbSJean Delvare return res; 4838d5d45fbSJean Delvare } 4848d5d45fbSJean Delvare 4858d5d45fbSJean Delvare 4868d5d45fbSJean Delvare static ssize_t show_fan(struct device *dev, char *buf, int nr) 4878d5d45fbSJean Delvare { 4888d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 4898d5d45fbSJean Delvare int value; 4908d5d45fbSJean Delvare 4918d5d45fbSJean Delvare value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr], 4928d5d45fbSJean Delvare FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; 4938d5d45fbSJean Delvare return sprintf(buf, "%d\n", value); 4948d5d45fbSJean Delvare } 4958d5d45fbSJean Delvare 4968d5d45fbSJean Delvare static ssize_t show_fan_div(struct device *dev, char *buf, int nr) 4978d5d45fbSJean Delvare { 4988d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 4998d5d45fbSJean Delvare return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); 5008d5d45fbSJean Delvare } 5018d5d45fbSJean Delvare static ssize_t show_fan_min(struct device *dev, char *buf, int nr) 5028d5d45fbSJean Delvare { 5038d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 5048d5d45fbSJean Delvare return sprintf(buf, "%d\n", 5058d5d45fbSJean Delvare FAN_FROM_REG(data->fan_min[nr], 5068d5d45fbSJean Delvare FAN_DIV_FROM_REG(data->fan_div[nr]))); 5078d5d45fbSJean Delvare } 5088d5d45fbSJean Delvare static ssize_t 5098d5d45fbSJean Delvare set_fan_min(struct device *dev, const char *buf, size_t count, int nr) 5108d5d45fbSJean Delvare { 5118d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 5128d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 5138d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 5148d5d45fbSJean Delvare 5159a61bf63SIngo Molnar mutex_lock(&data->update_lock); 5168d5d45fbSJean Delvare if (val) { 5178d5d45fbSJean Delvare data->fan_min[nr] = 5188d5d45fbSJean Delvare FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); 5198d5d45fbSJean Delvare } else { 5208d5d45fbSJean Delvare data->fan_min[nr] = 0xff; 5218d5d45fbSJean Delvare } 5228d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); 5239a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 5248d5d45fbSJean Delvare return count; 5258d5d45fbSJean Delvare } 5268d5d45fbSJean Delvare static ssize_t 5278d5d45fbSJean Delvare set_fan_div(struct device *dev, const char *buf, size_t count, int nr) 5288d5d45fbSJean Delvare { 5298d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 5308d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 5318d5d45fbSJean Delvare int val = simple_strtol(buf, NULL, 10); 5328d5d45fbSJean Delvare u8 tmp; 5338d5d45fbSJean Delvare int old_div; 5348d5d45fbSJean Delvare int new_min; 5358d5d45fbSJean Delvare 5368d5d45fbSJean Delvare tmp = val == 8 ? 0xc0 : 5378d5d45fbSJean Delvare val == 4 ? 0x80 : 5388d5d45fbSJean Delvare val == 2 ? 0x40 : 5398d5d45fbSJean Delvare val == 1 ? 0x00 : 5408d5d45fbSJean Delvare 0xff; 5418d5d45fbSJean Delvare if (tmp == 0xff) 5428d5d45fbSJean Delvare return -EINVAL; 5438d5d45fbSJean Delvare 5449a61bf63SIngo Molnar mutex_lock(&data->update_lock); 5458d5d45fbSJean Delvare old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); 5468d5d45fbSJean Delvare data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]); 5478d5d45fbSJean Delvare new_min = data->fan_min[nr] * old_div / 5488d5d45fbSJean Delvare FAN_DIV_FROM_REG(data->fan_div[nr]); 5498d5d45fbSJean Delvare data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; 5508d5d45fbSJean Delvare data->fan[nr] = data->fan[nr] * old_div / 5518d5d45fbSJean Delvare FAN_DIV_FROM_REG(data->fan_div[nr]); 5528d5d45fbSJean Delvare 5538d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), 5548d5d45fbSJean Delvare data->fan_div[nr]); 5558d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), 5568d5d45fbSJean Delvare data->fan_min[nr]); 5579a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 5588d5d45fbSJean Delvare return count; 5598d5d45fbSJean Delvare } 5608d5d45fbSJean Delvare 5618d5d45fbSJean Delvare #define fan_offset(offset) \ 5628d5d45fbSJean Delvare static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 5638d5d45fbSJean Delvare { \ 5648d5d45fbSJean Delvare return show_fan(dev, buf, offset - 1); \ 5658d5d45fbSJean Delvare } \ 5668d5d45fbSJean Delvare static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ 5678d5d45fbSJean Delvare { \ 5688d5d45fbSJean Delvare return show_fan_min(dev, buf, offset - 1); \ 5698d5d45fbSJean Delvare } \ 5708d5d45fbSJean Delvare static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ 5718d5d45fbSJean Delvare { \ 5728d5d45fbSJean Delvare return show_fan_div(dev, buf, offset - 1); \ 5738d5d45fbSJean Delvare } \ 5748d5d45fbSJean Delvare static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ 5758d5d45fbSJean Delvare const char *buf, size_t count) \ 5768d5d45fbSJean Delvare { \ 5778d5d45fbSJean Delvare return set_fan_min(dev, buf, count, offset - 1); \ 5788d5d45fbSJean Delvare } \ 5798d5d45fbSJean Delvare static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ 5808d5d45fbSJean Delvare const char *buf, size_t count) \ 5818d5d45fbSJean Delvare { \ 5828d5d45fbSJean Delvare return set_fan_div(dev, buf, count, offset - 1); \ 5838d5d45fbSJean Delvare } \ 5848d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ 5858d5d45fbSJean Delvare NULL); \ 5868d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ 5878d5d45fbSJean Delvare show_fan_##offset##_min, set_fan_##offset##_min); \ 5888d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ 5898d5d45fbSJean Delvare show_fan_##offset##_div, set_fan_##offset##_div); \ 5908d5d45fbSJean Delvare static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \ 5918d5d45fbSJean Delvare show_pwm_##offset, set_pwm_##offset) 5928d5d45fbSJean Delvare 5938d5d45fbSJean Delvare fan_offset(1); 5948d5d45fbSJean Delvare fan_offset(2); 5958d5d45fbSJean Delvare 5968d5d45fbSJean Delvare 5978d5d45fbSJean Delvare /* Temps */ 5988d5d45fbSJean Delvare static ssize_t show_temp(struct device *dev, char *buf, int nr) 5998d5d45fbSJean Delvare { 6008d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 6018d5d45fbSJean Delvare int ext; 6028d5d45fbSJean Delvare ext = nr == 0 ? 6038d5d45fbSJean Delvare ((data->ext_temp[nr] >> 6) & 0x3) * 2 : 6048d5d45fbSJean Delvare (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); 6058d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); 6068d5d45fbSJean Delvare } 6078d5d45fbSJean Delvare static ssize_t show_temp_min(struct device *dev, char *buf, int nr) 6088d5d45fbSJean Delvare { 6098d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 6108d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); 6118d5d45fbSJean Delvare } 6128d5d45fbSJean Delvare static ssize_t show_temp_max(struct device *dev, char *buf, int nr) 6138d5d45fbSJean Delvare { 6148d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 6158d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); 6168d5d45fbSJean Delvare } 6178d5d45fbSJean Delvare static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) 6188d5d45fbSJean Delvare { 6198d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 6208d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); 6218d5d45fbSJean Delvare } 6228d5d45fbSJean Delvare static ssize_t 6238d5d45fbSJean Delvare set_temp_min(struct device *dev, const char *buf, size_t count, int nr) 6248d5d45fbSJean Delvare { 6258d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 6268d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 6278d5d45fbSJean Delvare int val; 6288d5d45fbSJean Delvare 6298d5d45fbSJean Delvare val = simple_strtol(buf, NULL, 10); 6308d5d45fbSJean Delvare val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); 6319a61bf63SIngo Molnar mutex_lock(&data->update_lock); 6328d5d45fbSJean Delvare data->temp_min[nr] = TEMP_TO_REG(val); 6338d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), 6348d5d45fbSJean Delvare data->temp_min[nr]); 6359a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 6368d5d45fbSJean Delvare return count; 6378d5d45fbSJean Delvare } 6388d5d45fbSJean Delvare static ssize_t 6398d5d45fbSJean Delvare set_temp_max(struct device *dev, const char *buf, size_t count, int nr) 6408d5d45fbSJean Delvare { 6418d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 6428d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 6438d5d45fbSJean Delvare int val; 6448d5d45fbSJean Delvare 6458d5d45fbSJean Delvare val = simple_strtol(buf, NULL, 10); 6468d5d45fbSJean Delvare val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); 6479a61bf63SIngo Molnar mutex_lock(&data->update_lock); 6488d5d45fbSJean Delvare data->temp_max[nr] = TEMP_TO_REG(val); 6498d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), 6508d5d45fbSJean Delvare data->temp_max[nr]); 6519a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 6528d5d45fbSJean Delvare return count; 6538d5d45fbSJean Delvare } 6548d5d45fbSJean Delvare static ssize_t 6558d5d45fbSJean Delvare set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) 6568d5d45fbSJean Delvare { 6578d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 6588d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 6598d5d45fbSJean Delvare int val; 6608d5d45fbSJean Delvare 6618d5d45fbSJean Delvare val = simple_strtol(buf, NULL, 10); 6628d5d45fbSJean Delvare val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); 6639a61bf63SIngo Molnar mutex_lock(&data->update_lock); 6648d5d45fbSJean Delvare data->temp_crit[nr] = TEMP_TO_REG(val); 6658d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), 6668d5d45fbSJean Delvare data->temp_crit[nr]); 6679a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 6688d5d45fbSJean Delvare return count; 6698d5d45fbSJean Delvare } 6708d5d45fbSJean Delvare 6718d5d45fbSJean Delvare #define temp_reg(offset) \ 6728d5d45fbSJean Delvare static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 6738d5d45fbSJean Delvare { \ 6748d5d45fbSJean Delvare return show_temp(dev, buf, offset - 1); \ 6758d5d45fbSJean Delvare } \ 6768d5d45fbSJean Delvare static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ 6778d5d45fbSJean Delvare { \ 6788d5d45fbSJean Delvare return show_temp_min(dev, buf, offset - 1); \ 6798d5d45fbSJean Delvare } \ 6808d5d45fbSJean Delvare static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ 6818d5d45fbSJean Delvare { \ 6828d5d45fbSJean Delvare return show_temp_max(dev, buf, offset - 1); \ 6838d5d45fbSJean Delvare } \ 6848d5d45fbSJean Delvare static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ 6858d5d45fbSJean Delvare { \ 6868d5d45fbSJean Delvare return show_temp_crit(dev, buf, offset - 1); \ 6878d5d45fbSJean Delvare } \ 6888d5d45fbSJean Delvare static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ 6898d5d45fbSJean Delvare const char *buf, size_t count) \ 6908d5d45fbSJean Delvare { \ 6918d5d45fbSJean Delvare return set_temp_min(dev, buf, count, offset - 1); \ 6928d5d45fbSJean Delvare } \ 6938d5d45fbSJean Delvare static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ 6948d5d45fbSJean Delvare const char *buf, size_t count) \ 6958d5d45fbSJean Delvare { \ 6968d5d45fbSJean Delvare return set_temp_max(dev, buf, count, offset - 1); \ 6978d5d45fbSJean Delvare } \ 6988d5d45fbSJean Delvare static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ 6998d5d45fbSJean Delvare const char *buf, size_t count) \ 7008d5d45fbSJean Delvare { \ 7018d5d45fbSJean Delvare return set_temp_crit(dev, buf, count, offset - 1); \ 7028d5d45fbSJean Delvare } \ 7038d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ 7048d5d45fbSJean Delvare NULL); \ 7058d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ 7068d5d45fbSJean Delvare show_temp_##offset##_min, set_temp_##offset##_min); \ 7078d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 7088d5d45fbSJean Delvare show_temp_##offset##_max, set_temp_##offset##_max); \ 7098d5d45fbSJean Delvare static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ 7108d5d45fbSJean Delvare show_temp_##offset##_crit, set_temp_##offset##_crit) 7118d5d45fbSJean Delvare 7128d5d45fbSJean Delvare temp_reg(1); 7138d5d45fbSJean Delvare temp_reg(2); 7148d5d45fbSJean Delvare temp_reg(3); 7158d5d45fbSJean Delvare 7168d5d45fbSJean Delvare /* Alarms */ 7178d5d45fbSJean Delvare static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) 7188d5d45fbSJean Delvare { 7198d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev); 7208d5d45fbSJean Delvare return sprintf(buf, "%d\n", data->alarm); 7218d5d45fbSJean Delvare } 7228d5d45fbSJean Delvare 7238d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 7248d5d45fbSJean Delvare 7258d5d45fbSJean Delvare 7268d5d45fbSJean Delvare static int adm1031_attach_adapter(struct i2c_adapter *adapter) 7278d5d45fbSJean Delvare { 7288d5d45fbSJean Delvare if (!(adapter->class & I2C_CLASS_HWMON)) 7298d5d45fbSJean Delvare return 0; 7302ed2dc3cSJean Delvare return i2c_probe(adapter, &addr_data, adm1031_detect); 7318d5d45fbSJean Delvare } 7328d5d45fbSJean Delvare 733*681c6f7aSMark M. Hoffman static struct attribute *adm1031_attributes[] = { 734*681c6f7aSMark M. Hoffman &dev_attr_fan1_input.attr, 735*681c6f7aSMark M. Hoffman &dev_attr_fan1_div.attr, 736*681c6f7aSMark M. Hoffman &dev_attr_fan1_min.attr, 737*681c6f7aSMark M. Hoffman &dev_attr_pwm1.attr, 738*681c6f7aSMark M. Hoffman &dev_attr_auto_fan1_channel.attr, 739*681c6f7aSMark M. Hoffman &dev_attr_temp1_input.attr, 740*681c6f7aSMark M. Hoffman &dev_attr_temp1_min.attr, 741*681c6f7aSMark M. Hoffman &dev_attr_temp1_max.attr, 742*681c6f7aSMark M. Hoffman &dev_attr_temp1_crit.attr, 743*681c6f7aSMark M. Hoffman &dev_attr_temp2_input.attr, 744*681c6f7aSMark M. Hoffman &dev_attr_temp2_min.attr, 745*681c6f7aSMark M. Hoffman &dev_attr_temp2_max.attr, 746*681c6f7aSMark M. Hoffman &dev_attr_temp2_crit.attr, 747*681c6f7aSMark M. Hoffman 748*681c6f7aSMark M. Hoffman &dev_attr_auto_temp1_off.attr, 749*681c6f7aSMark M. Hoffman &dev_attr_auto_temp1_min.attr, 750*681c6f7aSMark M. Hoffman &dev_attr_auto_temp1_max.attr, 751*681c6f7aSMark M. Hoffman 752*681c6f7aSMark M. Hoffman &dev_attr_auto_temp2_off.attr, 753*681c6f7aSMark M. Hoffman &dev_attr_auto_temp2_min.attr, 754*681c6f7aSMark M. Hoffman &dev_attr_auto_temp2_max.attr, 755*681c6f7aSMark M. Hoffman 756*681c6f7aSMark M. Hoffman &dev_attr_auto_fan1_min_pwm.attr, 757*681c6f7aSMark M. Hoffman 758*681c6f7aSMark M. Hoffman &dev_attr_alarms.attr, 759*681c6f7aSMark M. Hoffman 760*681c6f7aSMark M. Hoffman NULL 761*681c6f7aSMark M. Hoffman }; 762*681c6f7aSMark M. Hoffman 763*681c6f7aSMark M. Hoffman static const struct attribute_group adm1031_group = { 764*681c6f7aSMark M. Hoffman .attrs = adm1031_attributes, 765*681c6f7aSMark M. Hoffman }; 766*681c6f7aSMark M. Hoffman 767*681c6f7aSMark M. Hoffman static struct attribute *adm1031_attributes_opt[] = { 768*681c6f7aSMark M. Hoffman &dev_attr_fan2_input.attr, 769*681c6f7aSMark M. Hoffman &dev_attr_fan2_div.attr, 770*681c6f7aSMark M. Hoffman &dev_attr_fan2_min.attr, 771*681c6f7aSMark M. Hoffman &dev_attr_pwm2.attr, 772*681c6f7aSMark M. Hoffman &dev_attr_auto_fan2_channel.attr, 773*681c6f7aSMark M. Hoffman &dev_attr_temp3_input.attr, 774*681c6f7aSMark M. Hoffman &dev_attr_temp3_min.attr, 775*681c6f7aSMark M. Hoffman &dev_attr_temp3_max.attr, 776*681c6f7aSMark M. Hoffman &dev_attr_temp3_crit.attr, 777*681c6f7aSMark M. Hoffman &dev_attr_auto_temp3_off.attr, 778*681c6f7aSMark M. Hoffman &dev_attr_auto_temp3_min.attr, 779*681c6f7aSMark M. Hoffman &dev_attr_auto_temp3_max.attr, 780*681c6f7aSMark M. Hoffman &dev_attr_auto_fan2_min_pwm.attr, 781*681c6f7aSMark M. Hoffman NULL 782*681c6f7aSMark M. Hoffman }; 783*681c6f7aSMark M. Hoffman 784*681c6f7aSMark M. Hoffman static const struct attribute_group adm1031_group_opt = { 785*681c6f7aSMark M. Hoffman .attrs = adm1031_attributes_opt, 786*681c6f7aSMark M. Hoffman }; 787*681c6f7aSMark M. Hoffman 7882ed2dc3cSJean Delvare /* This function is called by i2c_probe */ 7898d5d45fbSJean Delvare static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) 7908d5d45fbSJean Delvare { 7918d5d45fbSJean Delvare struct i2c_client *new_client; 7928d5d45fbSJean Delvare struct adm1031_data *data; 7938d5d45fbSJean Delvare int err = 0; 7948d5d45fbSJean Delvare const char *name = ""; 7958d5d45fbSJean Delvare 7968d5d45fbSJean Delvare if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 7978d5d45fbSJean Delvare goto exit; 7988d5d45fbSJean Delvare 799ba9c2e8dSDeepak Saxena if (!(data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { 8008d5d45fbSJean Delvare err = -ENOMEM; 8018d5d45fbSJean Delvare goto exit; 8028d5d45fbSJean Delvare } 8038d5d45fbSJean Delvare 8048d5d45fbSJean Delvare new_client = &data->client; 8058d5d45fbSJean Delvare i2c_set_clientdata(new_client, data); 8068d5d45fbSJean Delvare new_client->addr = address; 8078d5d45fbSJean Delvare new_client->adapter = adapter; 8088d5d45fbSJean Delvare new_client->driver = &adm1031_driver; 8098d5d45fbSJean Delvare new_client->flags = 0; 8108d5d45fbSJean Delvare 8118d5d45fbSJean Delvare if (kind < 0) { 8128d5d45fbSJean Delvare int id, co; 8138d5d45fbSJean Delvare id = i2c_smbus_read_byte_data(new_client, 0x3d); 8148d5d45fbSJean Delvare co = i2c_smbus_read_byte_data(new_client, 0x3e); 8158d5d45fbSJean Delvare 8168d5d45fbSJean Delvare if (!((id == 0x31 || id == 0x30) && co == 0x41)) 8178d5d45fbSJean Delvare goto exit_free; 8188d5d45fbSJean Delvare kind = (id == 0x30) ? adm1030 : adm1031; 8198d5d45fbSJean Delvare } 8208d5d45fbSJean Delvare 8218d5d45fbSJean Delvare if (kind <= 0) 8228d5d45fbSJean Delvare kind = adm1031; 8238d5d45fbSJean Delvare 8248d5d45fbSJean Delvare /* Given the detected chip type, set the chip name and the 8258d5d45fbSJean Delvare * auto fan control helper table. */ 8268d5d45fbSJean Delvare if (kind == adm1030) { 8278d5d45fbSJean Delvare name = "adm1030"; 8288d5d45fbSJean Delvare data->chan_select_table = &auto_channel_select_table_adm1030; 8298d5d45fbSJean Delvare } else if (kind == adm1031) { 8308d5d45fbSJean Delvare name = "adm1031"; 8318d5d45fbSJean Delvare data->chan_select_table = &auto_channel_select_table_adm1031; 8328d5d45fbSJean Delvare } 8338d5d45fbSJean Delvare data->chip_type = kind; 8348d5d45fbSJean Delvare 8358d5d45fbSJean Delvare strlcpy(new_client->name, name, I2C_NAME_SIZE); 8368d5d45fbSJean Delvare data->valid = 0; 8379a61bf63SIngo Molnar mutex_init(&data->update_lock); 8388d5d45fbSJean Delvare 8398d5d45fbSJean Delvare /* Tell the I2C layer a new client has arrived */ 8408d5d45fbSJean Delvare if ((err = i2c_attach_client(new_client))) 8418d5d45fbSJean Delvare goto exit_free; 8428d5d45fbSJean Delvare 8438d5d45fbSJean Delvare /* Initialize the ADM1031 chip */ 8448d5d45fbSJean Delvare adm1031_init_client(new_client); 8458d5d45fbSJean Delvare 8468d5d45fbSJean Delvare /* Register sysfs hooks */ 847*681c6f7aSMark M. Hoffman if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group))) 848*681c6f7aSMark M. Hoffman goto exit_detach; 849*681c6f7aSMark M. Hoffman 850*681c6f7aSMark M. Hoffman if (kind == adm1031) { 851*681c6f7aSMark M. Hoffman if ((err = sysfs_create_group(&new_client->dev.kobj, 852*681c6f7aSMark M. Hoffman &adm1031_group_opt))) 853*681c6f7aSMark M. Hoffman goto exit_remove; 854*681c6f7aSMark M. Hoffman } 855*681c6f7aSMark M. Hoffman 856943b0830SMark M. Hoffman data->class_dev = hwmon_device_register(&new_client->dev); 857943b0830SMark M. Hoffman if (IS_ERR(data->class_dev)) { 858943b0830SMark M. Hoffman err = PTR_ERR(data->class_dev); 859*681c6f7aSMark M. Hoffman goto exit_remove; 8608d5d45fbSJean Delvare } 8618d5d45fbSJean Delvare 8628d5d45fbSJean Delvare return 0; 8638d5d45fbSJean Delvare 864*681c6f7aSMark M. Hoffman exit_remove: 865*681c6f7aSMark M. Hoffman sysfs_remove_group(&new_client->dev.kobj, &adm1031_group); 866*681c6f7aSMark M. Hoffman sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt); 867943b0830SMark M. Hoffman exit_detach: 868943b0830SMark M. Hoffman i2c_detach_client(new_client); 8698d5d45fbSJean Delvare exit_free: 8701f57ff89SAlexey Dobriyan kfree(data); 8718d5d45fbSJean Delvare exit: 8728d5d45fbSJean Delvare return err; 8738d5d45fbSJean Delvare } 8748d5d45fbSJean Delvare 8758d5d45fbSJean Delvare static int adm1031_detach_client(struct i2c_client *client) 8768d5d45fbSJean Delvare { 877943b0830SMark M. Hoffman struct adm1031_data *data = i2c_get_clientdata(client); 8788d5d45fbSJean Delvare int ret; 879943b0830SMark M. Hoffman 880943b0830SMark M. Hoffman hwmon_device_unregister(data->class_dev); 881*681c6f7aSMark M. Hoffman sysfs_remove_group(&client->dev.kobj, &adm1031_group); 882*681c6f7aSMark M. Hoffman sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt); 8838d5d45fbSJean Delvare if ((ret = i2c_detach_client(client)) != 0) { 8848d5d45fbSJean Delvare return ret; 8858d5d45fbSJean Delvare } 886943b0830SMark M. Hoffman kfree(data); 8878d5d45fbSJean Delvare return 0; 8888d5d45fbSJean Delvare } 8898d5d45fbSJean Delvare 8908d5d45fbSJean Delvare static void adm1031_init_client(struct i2c_client *client) 8918d5d45fbSJean Delvare { 8928d5d45fbSJean Delvare unsigned int read_val; 8938d5d45fbSJean Delvare unsigned int mask; 8948d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 8958d5d45fbSJean Delvare 8968d5d45fbSJean Delvare mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); 8978d5d45fbSJean Delvare if (data->chip_type == adm1031) { 8988d5d45fbSJean Delvare mask |= (ADM1031_CONF2_PWM2_ENABLE | 8998d5d45fbSJean Delvare ADM1031_CONF2_TACH2_ENABLE); 9008d5d45fbSJean Delvare } 9018d5d45fbSJean Delvare /* Initialize the ADM1031 chip (enables fan speed reading ) */ 9028d5d45fbSJean Delvare read_val = adm1031_read_value(client, ADM1031_REG_CONF2); 9038d5d45fbSJean Delvare if ((read_val | mask) != read_val) { 9048d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); 9058d5d45fbSJean Delvare } 9068d5d45fbSJean Delvare 9078d5d45fbSJean Delvare read_val = adm1031_read_value(client, ADM1031_REG_CONF1); 9088d5d45fbSJean Delvare if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { 9098d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_CONF1, read_val | 9108d5d45fbSJean Delvare ADM1031_CONF1_MONITOR_ENABLE); 9118d5d45fbSJean Delvare } 9128d5d45fbSJean Delvare 9138d5d45fbSJean Delvare } 9148d5d45fbSJean Delvare 9158d5d45fbSJean Delvare static struct adm1031_data *adm1031_update_device(struct device *dev) 9168d5d45fbSJean Delvare { 9178d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 9188d5d45fbSJean Delvare struct adm1031_data *data = i2c_get_clientdata(client); 9198d5d45fbSJean Delvare int chan; 9208d5d45fbSJean Delvare 9219a61bf63SIngo Molnar mutex_lock(&data->update_lock); 9228d5d45fbSJean Delvare 9238d5d45fbSJean Delvare if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 9248d5d45fbSJean Delvare || !data->valid) { 9258d5d45fbSJean Delvare 9268d5d45fbSJean Delvare dev_dbg(&client->dev, "Starting adm1031 update\n"); 9278d5d45fbSJean Delvare for (chan = 0; 9288d5d45fbSJean Delvare chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) { 9298d5d45fbSJean Delvare u8 oldh, newh; 9308d5d45fbSJean Delvare 9318d5d45fbSJean Delvare oldh = 9328d5d45fbSJean Delvare adm1031_read_value(client, ADM1031_REG_TEMP(chan)); 9338d5d45fbSJean Delvare data->ext_temp[chan] = 9348d5d45fbSJean Delvare adm1031_read_value(client, ADM1031_REG_EXT_TEMP); 9358d5d45fbSJean Delvare newh = 9368d5d45fbSJean Delvare adm1031_read_value(client, ADM1031_REG_TEMP(chan)); 9378d5d45fbSJean Delvare if (newh != oldh) { 9388d5d45fbSJean Delvare data->ext_temp[chan] = 9398d5d45fbSJean Delvare adm1031_read_value(client, 9408d5d45fbSJean Delvare ADM1031_REG_EXT_TEMP); 9418d5d45fbSJean Delvare #ifdef DEBUG 9428d5d45fbSJean Delvare oldh = 9438d5d45fbSJean Delvare adm1031_read_value(client, 9448d5d45fbSJean Delvare ADM1031_REG_TEMP(chan)); 9458d5d45fbSJean Delvare 9468d5d45fbSJean Delvare /* oldh is actually newer */ 9478d5d45fbSJean Delvare if (newh != oldh) 9488d5d45fbSJean Delvare dev_warn(&client->dev, 9498d5d45fbSJean Delvare "Remote temperature may be " 9508d5d45fbSJean Delvare "wrong.\n"); 9518d5d45fbSJean Delvare #endif 9528d5d45fbSJean Delvare } 9538d5d45fbSJean Delvare data->temp[chan] = newh; 9548d5d45fbSJean Delvare 9558d5d45fbSJean Delvare data->temp_min[chan] = 9568d5d45fbSJean Delvare adm1031_read_value(client, 9578d5d45fbSJean Delvare ADM1031_REG_TEMP_MIN(chan)); 9588d5d45fbSJean Delvare data->temp_max[chan] = 9598d5d45fbSJean Delvare adm1031_read_value(client, 9608d5d45fbSJean Delvare ADM1031_REG_TEMP_MAX(chan)); 9618d5d45fbSJean Delvare data->temp_crit[chan] = 9628d5d45fbSJean Delvare adm1031_read_value(client, 9638d5d45fbSJean Delvare ADM1031_REG_TEMP_CRIT(chan)); 9648d5d45fbSJean Delvare data->auto_temp[chan] = 9658d5d45fbSJean Delvare adm1031_read_value(client, 9668d5d45fbSJean Delvare ADM1031_REG_AUTO_TEMP(chan)); 9678d5d45fbSJean Delvare 9688d5d45fbSJean Delvare } 9698d5d45fbSJean Delvare 9708d5d45fbSJean Delvare data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); 9718d5d45fbSJean Delvare data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); 9728d5d45fbSJean Delvare 9738d5d45fbSJean Delvare data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) 9748d5d45fbSJean Delvare | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) 9758d5d45fbSJean Delvare << 8); 9768d5d45fbSJean Delvare if (data->chip_type == adm1030) { 9778d5d45fbSJean Delvare data->alarm &= 0xc0ff; 9788d5d45fbSJean Delvare } 9798d5d45fbSJean Delvare 9808d5d45fbSJean Delvare for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { 9818d5d45fbSJean Delvare data->fan_div[chan] = 9828d5d45fbSJean Delvare adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); 9838d5d45fbSJean Delvare data->fan_min[chan] = 9848d5d45fbSJean Delvare adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); 9858d5d45fbSJean Delvare data->fan[chan] = 9868d5d45fbSJean Delvare adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); 9878d5d45fbSJean Delvare data->pwm[chan] = 9888d5d45fbSJean Delvare 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> 9898d5d45fbSJean Delvare (4*chan)); 9908d5d45fbSJean Delvare } 9918d5d45fbSJean Delvare data->last_updated = jiffies; 9928d5d45fbSJean Delvare data->valid = 1; 9938d5d45fbSJean Delvare } 9948d5d45fbSJean Delvare 9959a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 9968d5d45fbSJean Delvare 9978d5d45fbSJean Delvare return data; 9988d5d45fbSJean Delvare } 9998d5d45fbSJean Delvare 10008d5d45fbSJean Delvare static int __init sensors_adm1031_init(void) 10018d5d45fbSJean Delvare { 10028d5d45fbSJean Delvare return i2c_add_driver(&adm1031_driver); 10038d5d45fbSJean Delvare } 10048d5d45fbSJean Delvare 10058d5d45fbSJean Delvare static void __exit sensors_adm1031_exit(void) 10068d5d45fbSJean Delvare { 10078d5d45fbSJean Delvare i2c_del_driver(&adm1031_driver); 10088d5d45fbSJean Delvare } 10098d5d45fbSJean Delvare 10108d5d45fbSJean Delvare MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>"); 10118d5d45fbSJean Delvare MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); 10128d5d45fbSJean Delvare MODULE_LICENSE("GPL"); 10138d5d45fbSJean Delvare 10148d5d45fbSJean Delvare module_init(sensors_adm1031_init); 10158d5d45fbSJean Delvare module_exit(sensors_adm1031_exit); 1016