174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
3fbb6670dSGuenter Roeck * adm1031.c - Part of lm_sensors, Linux kernel modules for hardware
4fbb6670dSGuenter Roeck * monitoring
5fbb6670dSGuenter Roeck * Based on lm75.c and lm85.c
6fbb6670dSGuenter Roeck * Supports adm1030 / adm1031
7fbb6670dSGuenter Roeck * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
87c81c60fSJean Delvare * Reworked by Jean Delvare <jdelvare@suse.de>
98d5d45fbSJean Delvare */
108d5d45fbSJean Delvare
118d5d45fbSJean Delvare #include <linux/module.h>
128d5d45fbSJean Delvare #include <linux/init.h>
138d5d45fbSJean Delvare #include <linux/slab.h>
148d5d45fbSJean Delvare #include <linux/jiffies.h>
158d5d45fbSJean Delvare #include <linux/i2c.h>
16943b0830SMark M. Hoffman #include <linux/hwmon.h>
17c801082dSJean Delvare #include <linux/hwmon-sysfs.h>
18943b0830SMark M. Hoffman #include <linux/err.h>
199a61bf63SIngo Molnar #include <linux/mutex.h>
208d5d45fbSJean Delvare
218d5d45fbSJean Delvare /* Following macros takes channel parameter starting from 0 to 2 */
228d5d45fbSJean Delvare #define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr))
238d5d45fbSJean Delvare #define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr))
248d5d45fbSJean Delvare #define ADM1031_REG_PWM (0x22)
258d5d45fbSJean Delvare #define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr))
2687c33daaSJean Delvare #define ADM1031_REG_FAN_FILTER (0x23)
278d5d45fbSJean Delvare
2849dc9efeSIra Snyder #define ADM1031_REG_TEMP_OFFSET(nr) (0x0d + (nr))
298d5d45fbSJean Delvare #define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr))
308d5d45fbSJean Delvare #define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr))
318d5d45fbSJean Delvare #define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr))
328d5d45fbSJean Delvare
336d6006b8SJean Delvare #define ADM1031_REG_TEMP(nr) (0x0a + (nr))
348d5d45fbSJean Delvare #define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr))
358d5d45fbSJean Delvare
368d5d45fbSJean Delvare #define ADM1031_REG_STATUS(nr) (0x2 + (nr))
378d5d45fbSJean Delvare
386d6006b8SJean Delvare #define ADM1031_REG_CONF1 0x00
396d6006b8SJean Delvare #define ADM1031_REG_CONF2 0x01
406d6006b8SJean Delvare #define ADM1031_REG_EXT_TEMP 0x06
418d5d45fbSJean Delvare
428d5d45fbSJean Delvare #define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */
438d5d45fbSJean Delvare #define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */
448d5d45fbSJean Delvare #define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */
458d5d45fbSJean Delvare
468d5d45fbSJean Delvare #define ADM1031_CONF2_PWM1_ENABLE 0x01
478d5d45fbSJean Delvare #define ADM1031_CONF2_PWM2_ENABLE 0x02
488d5d45fbSJean Delvare #define ADM1031_CONF2_TACH1_ENABLE 0x04
498d5d45fbSJean Delvare #define ADM1031_CONF2_TACH2_ENABLE 0x08
508d5d45fbSJean Delvare #define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan))
518d5d45fbSJean Delvare
5287c33daaSJean Delvare #define ADM1031_UPDATE_RATE_MASK 0x1c
5387c33daaSJean Delvare #define ADM1031_UPDATE_RATE_SHIFT 2
5487c33daaSJean Delvare
558d5d45fbSJean Delvare /* Addresses to scan */
5625e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
578d5d45fbSJean Delvare
58e5e9f44cSJean Delvare enum chips { adm1030, adm1031 };
598d5d45fbSJean Delvare
608d5d45fbSJean Delvare typedef u8 auto_chan_table_t[8][2];
618d5d45fbSJean Delvare
628d5d45fbSJean Delvare /* Each client has this additional data */
638d5d45fbSJean Delvare struct adm1031_data {
64b060f3c4SAxel Lin struct i2c_client *client;
65b060f3c4SAxel Lin const struct attribute_group *groups[3];
669a61bf63SIngo Molnar struct mutex update_lock;
678d5d45fbSJean Delvare int chip_type;
68952a11caSPaul Fertser bool valid; /* true if following fields are valid */
698d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */
70a51b9944SGuenter Roeck unsigned int update_interval; /* In milliseconds */
71fbb6670dSGuenter Roeck /*
72fbb6670dSGuenter Roeck * The chan_select_table contains the possible configurations for
738d5d45fbSJean Delvare * auto fan control.
748d5d45fbSJean Delvare */
756d6006b8SJean Delvare const auto_chan_table_t *chan_select_table;
768d5d45fbSJean Delvare u16 alarm;
778d5d45fbSJean Delvare u8 conf1;
788d5d45fbSJean Delvare u8 conf2;
798d5d45fbSJean Delvare u8 fan[2];
808d5d45fbSJean Delvare u8 fan_div[2];
818d5d45fbSJean Delvare u8 fan_min[2];
828d5d45fbSJean Delvare u8 pwm[2];
838d5d45fbSJean Delvare u8 old_pwm[2];
848d5d45fbSJean Delvare s8 temp[3];
858d5d45fbSJean Delvare u8 ext_temp[3];
868d5d45fbSJean Delvare u8 auto_temp[3];
878d5d45fbSJean Delvare u8 auto_temp_min[3];
888d5d45fbSJean Delvare u8 auto_temp_off[3];
898d5d45fbSJean Delvare u8 auto_temp_max[3];
9049dc9efeSIra Snyder s8 temp_offset[3];
918d5d45fbSJean Delvare s8 temp_min[3];
928d5d45fbSJean Delvare s8 temp_max[3];
938d5d45fbSJean Delvare s8 temp_crit[3];
948d5d45fbSJean Delvare };
958d5d45fbSJean Delvare
adm1031_read_value(struct i2c_client * client,u8 reg)968d5d45fbSJean Delvare static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
978d5d45fbSJean Delvare {
988d5d45fbSJean Delvare return i2c_smbus_read_byte_data(client, reg);
998d5d45fbSJean Delvare }
1008d5d45fbSJean Delvare
1018d5d45fbSJean Delvare static inline int
adm1031_write_value(struct i2c_client * client,u8 reg,unsigned int value)1028d5d45fbSJean Delvare adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
1038d5d45fbSJean Delvare {
1048d5d45fbSJean Delvare return i2c_smbus_write_byte_data(client, reg, value);
1058d5d45fbSJean Delvare }
1068d5d45fbSJean Delvare
adm1031_update_device(struct device * dev)107278ee1c8SAxel Lin static struct adm1031_data *adm1031_update_device(struct device *dev)
108278ee1c8SAxel Lin {
109b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
110b060f3c4SAxel Lin struct i2c_client *client = data->client;
111278ee1c8SAxel Lin unsigned long next_update;
112278ee1c8SAxel Lin int chan;
113278ee1c8SAxel Lin
114278ee1c8SAxel Lin mutex_lock(&data->update_lock);
115278ee1c8SAxel Lin
116278ee1c8SAxel Lin next_update = data->last_updated
117278ee1c8SAxel Lin + msecs_to_jiffies(data->update_interval);
118278ee1c8SAxel Lin if (time_after(jiffies, next_update) || !data->valid) {
119278ee1c8SAxel Lin
120278ee1c8SAxel Lin dev_dbg(&client->dev, "Starting adm1031 update\n");
121278ee1c8SAxel Lin for (chan = 0;
122278ee1c8SAxel Lin chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {
123278ee1c8SAxel Lin u8 oldh, newh;
124278ee1c8SAxel Lin
125278ee1c8SAxel Lin oldh =
126278ee1c8SAxel Lin adm1031_read_value(client, ADM1031_REG_TEMP(chan));
127278ee1c8SAxel Lin data->ext_temp[chan] =
128278ee1c8SAxel Lin adm1031_read_value(client, ADM1031_REG_EXT_TEMP);
129278ee1c8SAxel Lin newh =
130278ee1c8SAxel Lin adm1031_read_value(client, ADM1031_REG_TEMP(chan));
131278ee1c8SAxel Lin if (newh != oldh) {
132278ee1c8SAxel Lin data->ext_temp[chan] =
133278ee1c8SAxel Lin adm1031_read_value(client,
134278ee1c8SAxel Lin ADM1031_REG_EXT_TEMP);
135278ee1c8SAxel Lin #ifdef DEBUG
136278ee1c8SAxel Lin oldh =
137278ee1c8SAxel Lin adm1031_read_value(client,
138278ee1c8SAxel Lin ADM1031_REG_TEMP(chan));
139278ee1c8SAxel Lin
140278ee1c8SAxel Lin /* oldh is actually newer */
141278ee1c8SAxel Lin if (newh != oldh)
142278ee1c8SAxel Lin dev_warn(&client->dev,
143278ee1c8SAxel Lin "Remote temperature may be wrong.\n");
144278ee1c8SAxel Lin #endif
145278ee1c8SAxel Lin }
146278ee1c8SAxel Lin data->temp[chan] = newh;
147278ee1c8SAxel Lin
148278ee1c8SAxel Lin data->temp_offset[chan] =
149278ee1c8SAxel Lin adm1031_read_value(client,
150278ee1c8SAxel Lin ADM1031_REG_TEMP_OFFSET(chan));
151278ee1c8SAxel Lin data->temp_min[chan] =
152278ee1c8SAxel Lin adm1031_read_value(client,
153278ee1c8SAxel Lin ADM1031_REG_TEMP_MIN(chan));
154278ee1c8SAxel Lin data->temp_max[chan] =
155278ee1c8SAxel Lin adm1031_read_value(client,
156278ee1c8SAxel Lin ADM1031_REG_TEMP_MAX(chan));
157278ee1c8SAxel Lin data->temp_crit[chan] =
158278ee1c8SAxel Lin adm1031_read_value(client,
159278ee1c8SAxel Lin ADM1031_REG_TEMP_CRIT(chan));
160278ee1c8SAxel Lin data->auto_temp[chan] =
161278ee1c8SAxel Lin adm1031_read_value(client,
162278ee1c8SAxel Lin ADM1031_REG_AUTO_TEMP(chan));
163278ee1c8SAxel Lin
164278ee1c8SAxel Lin }
165278ee1c8SAxel Lin
166278ee1c8SAxel Lin data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);
167278ee1c8SAxel Lin data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
168278ee1c8SAxel Lin
169278ee1c8SAxel Lin data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
170278ee1c8SAxel Lin | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
171278ee1c8SAxel Lin if (data->chip_type == adm1030)
172278ee1c8SAxel Lin data->alarm &= 0xc0ff;
173278ee1c8SAxel Lin
174278ee1c8SAxel Lin for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
175278ee1c8SAxel Lin chan++) {
176278ee1c8SAxel Lin data->fan_div[chan] =
177278ee1c8SAxel Lin adm1031_read_value(client,
178278ee1c8SAxel Lin ADM1031_REG_FAN_DIV(chan));
179278ee1c8SAxel Lin data->fan_min[chan] =
180278ee1c8SAxel Lin adm1031_read_value(client,
181278ee1c8SAxel Lin ADM1031_REG_FAN_MIN(chan));
182278ee1c8SAxel Lin data->fan[chan] =
183278ee1c8SAxel Lin adm1031_read_value(client,
184278ee1c8SAxel Lin ADM1031_REG_FAN_SPEED(chan));
185278ee1c8SAxel Lin data->pwm[chan] =
186278ee1c8SAxel Lin (adm1031_read_value(client,
187278ee1c8SAxel Lin ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
188278ee1c8SAxel Lin }
189278ee1c8SAxel Lin data->last_updated = jiffies;
190952a11caSPaul Fertser data->valid = true;
191278ee1c8SAxel Lin }
192278ee1c8SAxel Lin
193278ee1c8SAxel Lin mutex_unlock(&data->update_lock);
194278ee1c8SAxel Lin
195278ee1c8SAxel Lin return data;
196278ee1c8SAxel Lin }
1978d5d45fbSJean Delvare
1988d5d45fbSJean Delvare #define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \
1998d5d45fbSJean Delvare ((val + 500) / 1000)))
2008d5d45fbSJean Delvare
2018d5d45fbSJean Delvare #define TEMP_FROM_REG(val) ((val) * 1000)
2028d5d45fbSJean Delvare
2038d5d45fbSJean Delvare #define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125)
2048d5d45fbSJean Delvare
20549dc9efeSIra Snyder #define TEMP_OFFSET_TO_REG(val) (TEMP_TO_REG(val) & 0x8f)
20649dc9efeSIra Snyder #define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \
20749dc9efeSIra Snyder (val) | 0x70 : (val))
20849dc9efeSIra Snyder
2091c720093SGuenter Roeck #define FAN_FROM_REG(reg, div) ((reg) ? \
2101c720093SGuenter Roeck (11250 * 60) / ((reg) * (div)) : 0)
2118d5d45fbSJean Delvare
FAN_TO_REG(int reg,int div)2128d5d45fbSJean Delvare static int FAN_TO_REG(int reg, int div)
2138d5d45fbSJean Delvare {
2148d5d45fbSJean Delvare int tmp;
2152a844c14SGuenter Roeck tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
2168d5d45fbSJean Delvare return tmp > 255 ? 255 : tmp;
2178d5d45fbSJean Delvare }
2188d5d45fbSJean Delvare
2198d5d45fbSJean Delvare #define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6))
2208d5d45fbSJean Delvare
2212a844c14SGuenter Roeck #define PWM_TO_REG(val) (clamp_val((val), 0, 255) >> 4)
2228d5d45fbSJean Delvare #define PWM_FROM_REG(val) ((val) << 4)
2238d5d45fbSJean Delvare
2248d5d45fbSJean Delvare #define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7)
2258d5d45fbSJean Delvare #define FAN_CHAN_TO_REG(val, reg) \
2268d5d45fbSJean Delvare (((reg) & 0x1F) | (((val) << 5) & 0xe0))
2278d5d45fbSJean Delvare
2288d5d45fbSJean Delvare #define AUTO_TEMP_MIN_TO_REG(val, reg) \
2298d5d45fbSJean Delvare ((((val) / 500) & 0xf8) | ((reg) & 0x7))
2308d5d45fbSJean Delvare #define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7)))
2318d5d45fbSJean Delvare #define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2))
2328d5d45fbSJean Delvare
2338d5d45fbSJean Delvare #define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2)
2348d5d45fbSJean Delvare
2358d5d45fbSJean Delvare #define AUTO_TEMP_OFF_FROM_REG(reg) \
2368d5d45fbSJean Delvare (AUTO_TEMP_MIN_FROM_REG(reg) - 5000)
2378d5d45fbSJean Delvare
2388d5d45fbSJean Delvare #define AUTO_TEMP_MAX_FROM_REG(reg) \
2398d5d45fbSJean Delvare (AUTO_TEMP_RANGE_FROM_REG(reg) + \
2408d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG(reg))
2418d5d45fbSJean Delvare
AUTO_TEMP_MAX_TO_REG(int val,int reg,int pwm)2428d5d45fbSJean Delvare static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
2438d5d45fbSJean Delvare {
2448d5d45fbSJean Delvare int ret;
245d7555379SColin Ian King int range = ((val - AUTO_TEMP_MIN_FROM_REG(reg)) * 10) / (16 - pwm);
2468d5d45fbSJean Delvare
2478d5d45fbSJean Delvare ret = ((reg & 0xf8) |
2488d5d45fbSJean Delvare (range < 10000 ? 0 :
2498d5d45fbSJean Delvare range < 20000 ? 1 :
2508d5d45fbSJean Delvare range < 40000 ? 2 : range < 80000 ? 3 : 4));
2518d5d45fbSJean Delvare return ret;
2528d5d45fbSJean Delvare }
2538d5d45fbSJean Delvare
2548d5d45fbSJean Delvare /* FAN auto control */
2558d5d45fbSJean Delvare #define GET_FAN_AUTO_BITFIELD(data, idx) \
2568d5d45fbSJean Delvare (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
2578d5d45fbSJean Delvare
258fbb6670dSGuenter Roeck /*
259fbb6670dSGuenter Roeck * The tables below contains the possible values for the auto fan
2608d5d45fbSJean Delvare * control bitfields. the index in the table is the register value.
2618d5d45fbSJean Delvare * MSb is the auto fan control enable bit, so the four first entries
2628d5d45fbSJean Delvare * in the table disables auto fan control when both bitfields are zero.
2638d5d45fbSJean Delvare */
2646d6006b8SJean Delvare static const auto_chan_table_t auto_channel_select_table_adm1031 = {
2658d5d45fbSJean Delvare { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2668d5d45fbSJean Delvare { 2 /* 0b010 */ , 4 /* 0b100 */ },
2678d5d45fbSJean Delvare { 2 /* 0b010 */ , 2 /* 0b010 */ },
2688d5d45fbSJean Delvare { 4 /* 0b100 */ , 4 /* 0b100 */ },
2698d5d45fbSJean Delvare { 7 /* 0b111 */ , 7 /* 0b111 */ },
2708d5d45fbSJean Delvare };
2718d5d45fbSJean Delvare
2726d6006b8SJean Delvare static const auto_chan_table_t auto_channel_select_table_adm1030 = {
2738d5d45fbSJean Delvare { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2748d5d45fbSJean Delvare { 2 /* 0b10 */ , 0 },
2758d5d45fbSJean Delvare { 0xff /* invalid */ , 0 },
2768d5d45fbSJean Delvare { 0xff /* invalid */ , 0 },
2778d5d45fbSJean Delvare { 3 /* 0b11 */ , 0 },
2788d5d45fbSJean Delvare };
2798d5d45fbSJean Delvare
280fbb6670dSGuenter Roeck /*
281fbb6670dSGuenter Roeck * That function checks if a bitfield is valid and returns the other bitfield
2828d5d45fbSJean Delvare * nearest match if no exact match where found.
2838d5d45fbSJean Delvare */
2848d5d45fbSJean Delvare static int
get_fan_auto_nearest(struct adm1031_data * data,int chan,u8 val,u8 reg)285ce15a81dSGuenter Roeck get_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg)
2868d5d45fbSJean Delvare {
2878d5d45fbSJean Delvare int i;
2888d5d45fbSJean Delvare int first_match = -1, exact_match = -1;
2898d5d45fbSJean Delvare u8 other_reg_val =
2908d5d45fbSJean Delvare (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1];
2918d5d45fbSJean Delvare
292ce15a81dSGuenter Roeck if (val == 0)
2938d5d45fbSJean Delvare return 0;
2948d5d45fbSJean Delvare
2958d5d45fbSJean Delvare for (i = 0; i < 8; i++) {
2968d5d45fbSJean Delvare if ((val == (*data->chan_select_table)[i][chan]) &&
2978d5d45fbSJean Delvare ((*data->chan_select_table)[i][chan ? 0 : 1] ==
2988d5d45fbSJean Delvare other_reg_val)) {
2998d5d45fbSJean Delvare /* We found an exact match */
3008d5d45fbSJean Delvare exact_match = i;
3018d5d45fbSJean Delvare break;
3028d5d45fbSJean Delvare } else if (val == (*data->chan_select_table)[i][chan] &&
3038d5d45fbSJean Delvare first_match == -1) {
304fbb6670dSGuenter Roeck /*
305fbb6670dSGuenter Roeck * Save the first match in case of an exact match has
3066d6006b8SJean Delvare * not been found
3078d5d45fbSJean Delvare */
3088d5d45fbSJean Delvare first_match = i;
3098d5d45fbSJean Delvare }
3108d5d45fbSJean Delvare }
3118d5d45fbSJean Delvare
3121c720093SGuenter Roeck if (exact_match >= 0)
313ce15a81dSGuenter Roeck return exact_match;
3141c720093SGuenter Roeck else if (first_match >= 0)
315ce15a81dSGuenter Roeck return first_match;
3161c720093SGuenter Roeck
317ce15a81dSGuenter Roeck return -EINVAL;
3188d5d45fbSJean Delvare }
3198d5d45fbSJean Delvare
fan_auto_channel_show(struct device * dev,struct device_attribute * attr,char * buf)3208e757e15SGuenter Roeck static ssize_t fan_auto_channel_show(struct device *dev,
321c801082dSJean Delvare struct device_attribute *attr, char *buf)
3228d5d45fbSJean Delvare {
323c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
3248d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
3258d5d45fbSJean Delvare return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr));
3268d5d45fbSJean Delvare }
3278d5d45fbSJean Delvare
3288d5d45fbSJean Delvare static ssize_t
fan_auto_channel_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3298e757e15SGuenter Roeck fan_auto_channel_store(struct device *dev, struct device_attribute *attr,
330c801082dSJean Delvare const char *buf, size_t count)
3318d5d45fbSJean Delvare {
332b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
333b060f3c4SAxel Lin struct i2c_client *client = data->client;
334c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
3351c720093SGuenter Roeck long val;
3368d5d45fbSJean Delvare u8 reg;
3378d5d45fbSJean Delvare int ret;
3388d5d45fbSJean Delvare u8 old_fan_mode;
3398d5d45fbSJean Delvare
3401c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
3411c720093SGuenter Roeck if (ret)
3421c720093SGuenter Roeck return ret;
3431c720093SGuenter Roeck
3448d5d45fbSJean Delvare old_fan_mode = data->conf1;
3458d5d45fbSJean Delvare
3469a61bf63SIngo Molnar mutex_lock(&data->update_lock);
3478d5d45fbSJean Delvare
348ce15a81dSGuenter Roeck ret = get_fan_auto_nearest(data, nr, val, data->conf1);
349ce15a81dSGuenter Roeck if (ret < 0) {
3509a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
3518d5d45fbSJean Delvare return ret;
3528d5d45fbSJean Delvare }
353ce15a81dSGuenter Roeck reg = ret;
3546d6006b8SJean Delvare data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
3556d6006b8SJean Delvare if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
3568d5d45fbSJean Delvare (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
3578d5d45fbSJean Delvare if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
358fbb6670dSGuenter Roeck /*
359fbb6670dSGuenter Roeck * Switch to Auto Fan Mode
3608d5d45fbSJean Delvare * Save PWM registers
361fbb6670dSGuenter Roeck * Set PWM registers to 33% Both
362fbb6670dSGuenter Roeck */
3638d5d45fbSJean Delvare data->old_pwm[0] = data->pwm[0];
3648d5d45fbSJean Delvare data->old_pwm[1] = data->pwm[1];
3658d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_PWM, 0x55);
3668d5d45fbSJean Delvare } else {
3678d5d45fbSJean Delvare /* Switch to Manual Mode */
3688d5d45fbSJean Delvare data->pwm[0] = data->old_pwm[0];
3698d5d45fbSJean Delvare data->pwm[1] = data->old_pwm[1];
3708d5d45fbSJean Delvare /* Restore PWM registers */
3718d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_PWM,
3728d5d45fbSJean Delvare data->pwm[0] | (data->pwm[1] << 4));
3738d5d45fbSJean Delvare }
3748d5d45fbSJean Delvare }
3758d5d45fbSJean Delvare data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
3768d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1);
3779a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
3788d5d45fbSJean Delvare return count;
3798d5d45fbSJean Delvare }
3808d5d45fbSJean Delvare
3818e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_fan1_channel, fan_auto_channel, 0);
3828e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_fan2_channel, fan_auto_channel, 1);
3838d5d45fbSJean Delvare
3848d5d45fbSJean Delvare /* Auto Temps */
auto_temp_off_show(struct device * dev,struct device_attribute * attr,char * buf)3858e757e15SGuenter Roeck static ssize_t auto_temp_off_show(struct device *dev,
386c801082dSJean Delvare struct device_attribute *attr, char *buf)
3878d5d45fbSJean Delvare {
388c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
3898d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
3908d5d45fbSJean Delvare return sprintf(buf, "%d\n",
3918d5d45fbSJean Delvare AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr]));
3928d5d45fbSJean Delvare }
auto_temp_min_show(struct device * dev,struct device_attribute * attr,char * buf)3938e757e15SGuenter Roeck static ssize_t auto_temp_min_show(struct device *dev,
394c801082dSJean Delvare struct device_attribute *attr, char *buf)
3958d5d45fbSJean Delvare {
396c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
3978d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
3988d5d45fbSJean Delvare return sprintf(buf, "%d\n",
3998d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr]));
4008d5d45fbSJean Delvare }
4018d5d45fbSJean Delvare static ssize_t
auto_temp_min_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4028e757e15SGuenter Roeck auto_temp_min_store(struct device *dev, struct device_attribute *attr,
403c801082dSJean Delvare const char *buf, size_t count)
4048d5d45fbSJean Delvare {
405b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
406b060f3c4SAxel Lin struct i2c_client *client = data->client;
407c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
4081c720093SGuenter Roeck long val;
4091c720093SGuenter Roeck int ret;
4101c720093SGuenter Roeck
4111c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
4121c720093SGuenter Roeck if (ret)
4131c720093SGuenter Roeck return ret;
4148d5d45fbSJean Delvare
415145e74a4SGuenter Roeck val = clamp_val(val, 0, 127000);
4169a61bf63SIngo Molnar mutex_lock(&data->update_lock);
4178d5d45fbSJean Delvare data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
4188d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
4198d5d45fbSJean Delvare data->auto_temp[nr]);
4209a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
4218d5d45fbSJean Delvare return count;
4228d5d45fbSJean Delvare }
auto_temp_max_show(struct device * dev,struct device_attribute * attr,char * buf)4238e757e15SGuenter Roeck static ssize_t auto_temp_max_show(struct device *dev,
424c801082dSJean Delvare struct device_attribute *attr, char *buf)
4258d5d45fbSJean Delvare {
426c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
4278d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
4288d5d45fbSJean Delvare return sprintf(buf, "%d\n",
4298d5d45fbSJean Delvare AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr]));
4308d5d45fbSJean Delvare }
4318d5d45fbSJean Delvare static ssize_t
auto_temp_max_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4328e757e15SGuenter Roeck auto_temp_max_store(struct device *dev, struct device_attribute *attr,
433c801082dSJean Delvare const char *buf, size_t count)
4348d5d45fbSJean Delvare {
435b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
436b060f3c4SAxel Lin struct i2c_client *client = data->client;
437c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
4381c720093SGuenter Roeck long val;
4391c720093SGuenter Roeck int ret;
4401c720093SGuenter Roeck
4411c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
4421c720093SGuenter Roeck if (ret)
4431c720093SGuenter Roeck return ret;
4448d5d45fbSJean Delvare
445145e74a4SGuenter Roeck val = clamp_val(val, 0, 127000);
4469a61bf63SIngo Molnar mutex_lock(&data->update_lock);
4471c720093SGuenter Roeck data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr],
4481c720093SGuenter Roeck data->pwm[nr]);
4498d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
4508d5d45fbSJean Delvare data->temp_max[nr]);
4519a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
4528d5d45fbSJean Delvare return count;
4538d5d45fbSJean Delvare }
4548d5d45fbSJean Delvare
4558e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(auto_temp1_off, auto_temp_off, 0);
4568e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_temp1_min, auto_temp_min, 0);
4578e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_temp1_max, auto_temp_max, 0);
4588e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(auto_temp2_off, auto_temp_off, 1);
4598e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_temp2_min, auto_temp_min, 1);
4608e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_temp2_max, auto_temp_max, 1);
4618e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(auto_temp3_off, auto_temp_off, 2);
4628e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_temp3_min, auto_temp_min, 2);
4638e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_temp3_max, auto_temp_max, 2);
4648d5d45fbSJean Delvare
4658d5d45fbSJean Delvare /* pwm */
pwm_show(struct device * dev,struct device_attribute * attr,char * buf)4668e757e15SGuenter Roeck static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
4678e757e15SGuenter Roeck char *buf)
4688d5d45fbSJean Delvare {
469c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
4708d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
4718d5d45fbSJean Delvare return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
4728d5d45fbSJean Delvare }
pwm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4738e757e15SGuenter Roeck static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
474c801082dSJean Delvare const char *buf, size_t count)
4758d5d45fbSJean Delvare {
476b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
477b060f3c4SAxel Lin struct i2c_client *client = data->client;
478c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
4791c720093SGuenter Roeck long val;
4801c720093SGuenter Roeck int ret, reg;
4811c720093SGuenter Roeck
4821c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
4831c720093SGuenter Roeck if (ret)
4841c720093SGuenter Roeck return ret;
4858d5d45fbSJean Delvare
4869a61bf63SIngo Molnar mutex_lock(&data->update_lock);
4878d5d45fbSJean Delvare if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
4888d5d45fbSJean Delvare (((val>>4) & 0xf) != 5)) {
4898d5d45fbSJean Delvare /* In automatic mode, the only PWM accepted is 33% */
4909a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
4918d5d45fbSJean Delvare return -EINVAL;
4928d5d45fbSJean Delvare }
4938d5d45fbSJean Delvare data->pwm[nr] = PWM_TO_REG(val);
4948d5d45fbSJean Delvare reg = adm1031_read_value(client, ADM1031_REG_PWM);
4958d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_PWM,
4968d5d45fbSJean Delvare nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf)
4978d5d45fbSJean Delvare : (data->pwm[nr] & 0xf) | (reg & 0xf0));
4989a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
4998d5d45fbSJean Delvare return count;
5008d5d45fbSJean Delvare }
5018d5d45fbSJean Delvare
5028e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
5038e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1);
5048e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_fan1_min_pwm, pwm, 0);
5058e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(auto_fan2_min_pwm, pwm, 1);
5068d5d45fbSJean Delvare
5078d5d45fbSJean Delvare /* Fans */
5088d5d45fbSJean Delvare
5098d5d45fbSJean Delvare /*
5108d5d45fbSJean Delvare * That function checks the cases where the fan reading is not
5118d5d45fbSJean Delvare * relevant. It is used to provide 0 as fan reading when the fan is
5128d5d45fbSJean Delvare * not supposed to run
5138d5d45fbSJean Delvare */
trust_fan_readings(struct adm1031_data * data,int chan)5148d5d45fbSJean Delvare static int trust_fan_readings(struct adm1031_data *data, int chan)
5158d5d45fbSJean Delvare {
5168d5d45fbSJean Delvare int res = 0;
5178d5d45fbSJean Delvare
5188d5d45fbSJean Delvare if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
5198d5d45fbSJean Delvare switch (data->conf1 & 0x60) {
5201c720093SGuenter Roeck case 0x00:
5211c720093SGuenter Roeck /*
5221c720093SGuenter Roeck * remote temp1 controls fan1,
5231c720093SGuenter Roeck * remote temp2 controls fan2
5241c720093SGuenter Roeck */
5258d5d45fbSJean Delvare res = data->temp[chan+1] >=
5268d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
5278d5d45fbSJean Delvare break;
5288d5d45fbSJean Delvare case 0x20: /* remote temp1 controls both fans */
5298d5d45fbSJean Delvare res =
5308d5d45fbSJean Delvare data->temp[1] >=
5318d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]);
5328d5d45fbSJean Delvare break;
5338d5d45fbSJean Delvare case 0x40: /* remote temp2 controls both fans */
5348d5d45fbSJean Delvare res =
5358d5d45fbSJean Delvare data->temp[2] >=
5368d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]);
5378d5d45fbSJean Delvare break;
5388d5d45fbSJean Delvare case 0x60: /* max controls both fans */
5398d5d45fbSJean Delvare res =
5408d5d45fbSJean Delvare data->temp[0] >=
5418d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0])
5428d5d45fbSJean Delvare || data->temp[1] >=
5438d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1])
5448d5d45fbSJean Delvare || (data->chip_type == adm1031
5458d5d45fbSJean Delvare && data->temp[2] >=
5468d5d45fbSJean Delvare AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]));
5478d5d45fbSJean Delvare break;
5488d5d45fbSJean Delvare }
5498d5d45fbSJean Delvare } else {
5508d5d45fbSJean Delvare res = data->pwm[chan] > 0;
5518d5d45fbSJean Delvare }
5528d5d45fbSJean Delvare return res;
5538d5d45fbSJean Delvare }
5548d5d45fbSJean Delvare
fan_show(struct device * dev,struct device_attribute * attr,char * buf)5558e757e15SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
5568e757e15SGuenter Roeck char *buf)
5578d5d45fbSJean Delvare {
558c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
5598d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
5608d5d45fbSJean Delvare int value;
5618d5d45fbSJean Delvare
5628d5d45fbSJean Delvare value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr],
5638d5d45fbSJean Delvare FAN_DIV_FROM_REG(data->fan_div[nr])) : 0;
5648d5d45fbSJean Delvare return sprintf(buf, "%d\n", value);
5658d5d45fbSJean Delvare }
5668d5d45fbSJean Delvare
fan_div_show(struct device * dev,struct device_attribute * attr,char * buf)5678e757e15SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *attr,
5688e757e15SGuenter Roeck char *buf)
5698d5d45fbSJean Delvare {
570c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
5718d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
5728d5d45fbSJean Delvare return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr]));
5738d5d45fbSJean Delvare }
fan_min_show(struct device * dev,struct device_attribute * attr,char * buf)5748e757e15SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
5758e757e15SGuenter Roeck char *buf)
5768d5d45fbSJean Delvare {
577c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
5788d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
5798d5d45fbSJean Delvare return sprintf(buf, "%d\n",
5808d5d45fbSJean Delvare FAN_FROM_REG(data->fan_min[nr],
5818d5d45fbSJean Delvare FAN_DIV_FROM_REG(data->fan_div[nr])));
5828d5d45fbSJean Delvare }
fan_min_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)5838e757e15SGuenter Roeck static ssize_t fan_min_store(struct device *dev,
5848e757e15SGuenter Roeck struct device_attribute *attr, const char *buf,
5858e757e15SGuenter Roeck size_t count)
5868d5d45fbSJean Delvare {
587b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
588b060f3c4SAxel Lin struct i2c_client *client = data->client;
589c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
5901c720093SGuenter Roeck long val;
5911c720093SGuenter Roeck int ret;
5921c720093SGuenter Roeck
5931c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
5941c720093SGuenter Roeck if (ret)
5951c720093SGuenter Roeck return ret;
5968d5d45fbSJean Delvare
5979a61bf63SIngo Molnar mutex_lock(&data->update_lock);
5988d5d45fbSJean Delvare if (val) {
5998d5d45fbSJean Delvare data->fan_min[nr] =
6008d5d45fbSJean Delvare FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
6018d5d45fbSJean Delvare } else {
6028d5d45fbSJean Delvare data->fan_min[nr] = 0xff;
6038d5d45fbSJean Delvare }
6048d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]);
6059a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
6068d5d45fbSJean Delvare return count;
6078d5d45fbSJean Delvare }
fan_div_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)6088e757e15SGuenter Roeck static ssize_t fan_div_store(struct device *dev,
6098e757e15SGuenter Roeck struct device_attribute *attr, const char *buf,
6108e757e15SGuenter Roeck size_t count)
6118d5d45fbSJean Delvare {
612b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
613b060f3c4SAxel Lin struct i2c_client *client = data->client;
614c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
6151c720093SGuenter Roeck long val;
6168d5d45fbSJean Delvare u8 tmp;
6178d5d45fbSJean Delvare int old_div;
6188d5d45fbSJean Delvare int new_min;
6191c720093SGuenter Roeck int ret;
6201c720093SGuenter Roeck
6211c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
6221c720093SGuenter Roeck if (ret)
6231c720093SGuenter Roeck return ret;
6248d5d45fbSJean Delvare
6258d5d45fbSJean Delvare tmp = val == 8 ? 0xc0 :
6268d5d45fbSJean Delvare val == 4 ? 0x80 :
6278d5d45fbSJean Delvare val == 2 ? 0x40 :
6288d5d45fbSJean Delvare val == 1 ? 0x00 :
6298d5d45fbSJean Delvare 0xff;
6308d5d45fbSJean Delvare if (tmp == 0xff)
6318d5d45fbSJean Delvare return -EINVAL;
6328d5d45fbSJean Delvare
6339a61bf63SIngo Molnar mutex_lock(&data->update_lock);
63438a1f0e9SJean Delvare /* Get fresh readings */
63538a1f0e9SJean Delvare data->fan_div[nr] = adm1031_read_value(client,
63638a1f0e9SJean Delvare ADM1031_REG_FAN_DIV(nr));
63738a1f0e9SJean Delvare data->fan_min[nr] = adm1031_read_value(client,
63838a1f0e9SJean Delvare ADM1031_REG_FAN_MIN(nr));
63938a1f0e9SJean Delvare
64038a1f0e9SJean Delvare /* Write the new clock divider and fan min */
6418d5d45fbSJean Delvare old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
6426d6006b8SJean Delvare data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]);
6436d6006b8SJean Delvare new_min = data->fan_min[nr] * old_div / val;
6448d5d45fbSJean Delvare data->fan_min[nr] = new_min > 0xff ? 0xff : new_min;
6458d5d45fbSJean Delvare
6468d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr),
6478d5d45fbSJean Delvare data->fan_div[nr]);
6488d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr),
6498d5d45fbSJean Delvare data->fan_min[nr]);
65038a1f0e9SJean Delvare
65138a1f0e9SJean Delvare /* Invalidate the cache: fan speed is no longer valid */
652952a11caSPaul Fertser data->valid = false;
6539a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
6548d5d45fbSJean Delvare return count;
6558d5d45fbSJean Delvare }
6568d5d45fbSJean Delvare
6578e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
6588e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
6598e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
6608e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
6618e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
6628e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
6638d5d45fbSJean Delvare
6648d5d45fbSJean Delvare /* Temps */
temp_show(struct device * dev,struct device_attribute * attr,char * buf)6658e757e15SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
6668e757e15SGuenter Roeck char *buf)
6678d5d45fbSJean Delvare {
668c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
6698d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
6708d5d45fbSJean Delvare int ext;
6718d5d45fbSJean Delvare ext = nr == 0 ?
6728d5d45fbSJean Delvare ((data->ext_temp[nr] >> 6) & 0x3) * 2 :
6738d5d45fbSJean Delvare (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7));
6748d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext));
6758d5d45fbSJean Delvare }
temp_offset_show(struct device * dev,struct device_attribute * attr,char * buf)6768e757e15SGuenter Roeck static ssize_t temp_offset_show(struct device *dev,
67749dc9efeSIra Snyder struct device_attribute *attr, char *buf)
67849dc9efeSIra Snyder {
67949dc9efeSIra Snyder int nr = to_sensor_dev_attr(attr)->index;
68049dc9efeSIra Snyder struct adm1031_data *data = adm1031_update_device(dev);
68149dc9efeSIra Snyder return sprintf(buf, "%d\n",
68249dc9efeSIra Snyder TEMP_OFFSET_FROM_REG(data->temp_offset[nr]));
68349dc9efeSIra Snyder }
temp_min_show(struct device * dev,struct device_attribute * attr,char * buf)6848e757e15SGuenter Roeck static ssize_t temp_min_show(struct device *dev,
685c801082dSJean Delvare struct device_attribute *attr, char *buf)
6868d5d45fbSJean Delvare {
687c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
6888d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
6898d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
6908d5d45fbSJean Delvare }
temp_max_show(struct device * dev,struct device_attribute * attr,char * buf)6918e757e15SGuenter Roeck static ssize_t temp_max_show(struct device *dev,
692c801082dSJean Delvare struct device_attribute *attr, char *buf)
6938d5d45fbSJean Delvare {
694c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
6958d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
6968d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
6978d5d45fbSJean Delvare }
temp_crit_show(struct device * dev,struct device_attribute * attr,char * buf)6988e757e15SGuenter Roeck static ssize_t temp_crit_show(struct device *dev,
699c801082dSJean Delvare struct device_attribute *attr, char *buf)
7008d5d45fbSJean Delvare {
701c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
7028d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
7038d5d45fbSJean Delvare return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
7048d5d45fbSJean Delvare }
temp_offset_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7058e757e15SGuenter Roeck static ssize_t temp_offset_store(struct device *dev,
7068e757e15SGuenter Roeck struct device_attribute *attr,
7078e757e15SGuenter Roeck const char *buf, size_t count)
70849dc9efeSIra Snyder {
709b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
710b060f3c4SAxel Lin struct i2c_client *client = data->client;
71149dc9efeSIra Snyder int nr = to_sensor_dev_attr(attr)->index;
7121c720093SGuenter Roeck long val;
7131c720093SGuenter Roeck int ret;
71449dc9efeSIra Snyder
7151c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
7161c720093SGuenter Roeck if (ret)
7171c720093SGuenter Roeck return ret;
7181c720093SGuenter Roeck
7192a844c14SGuenter Roeck val = clamp_val(val, -15000, 15000);
72049dc9efeSIra Snyder mutex_lock(&data->update_lock);
72149dc9efeSIra Snyder data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
72249dc9efeSIra Snyder adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
72349dc9efeSIra Snyder data->temp_offset[nr]);
72449dc9efeSIra Snyder mutex_unlock(&data->update_lock);
72549dc9efeSIra Snyder return count;
72649dc9efeSIra Snyder }
temp_min_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7278e757e15SGuenter Roeck static ssize_t temp_min_store(struct device *dev,
7288e757e15SGuenter Roeck struct device_attribute *attr, const char *buf,
7298e757e15SGuenter Roeck size_t count)
7308d5d45fbSJean Delvare {
731b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
732b060f3c4SAxel Lin struct i2c_client *client = data->client;
733c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
7341c720093SGuenter Roeck long val;
7351c720093SGuenter Roeck int ret;
7368d5d45fbSJean Delvare
7371c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
7381c720093SGuenter Roeck if (ret)
7391c720093SGuenter Roeck return ret;
7401c720093SGuenter Roeck
741145e74a4SGuenter Roeck val = clamp_val(val, -55000, 127000);
7429a61bf63SIngo Molnar mutex_lock(&data->update_lock);
7438d5d45fbSJean Delvare data->temp_min[nr] = TEMP_TO_REG(val);
7448d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
7458d5d45fbSJean Delvare data->temp_min[nr]);
7469a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
7478d5d45fbSJean Delvare return count;
7488d5d45fbSJean Delvare }
temp_max_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7498e757e15SGuenter Roeck static ssize_t temp_max_store(struct device *dev,
7508e757e15SGuenter Roeck struct device_attribute *attr, const char *buf,
7518e757e15SGuenter Roeck size_t count)
7528d5d45fbSJean Delvare {
753b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
754b060f3c4SAxel Lin struct i2c_client *client = data->client;
755c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
7561c720093SGuenter Roeck long val;
7571c720093SGuenter Roeck int ret;
7588d5d45fbSJean Delvare
7591c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
7601c720093SGuenter Roeck if (ret)
7611c720093SGuenter Roeck return ret;
7621c720093SGuenter Roeck
763145e74a4SGuenter Roeck val = clamp_val(val, -55000, 127000);
7649a61bf63SIngo Molnar mutex_lock(&data->update_lock);
7658d5d45fbSJean Delvare data->temp_max[nr] = TEMP_TO_REG(val);
7668d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
7678d5d45fbSJean Delvare data->temp_max[nr]);
7689a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
7698d5d45fbSJean Delvare return count;
7708d5d45fbSJean Delvare }
temp_crit_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7718e757e15SGuenter Roeck static ssize_t temp_crit_store(struct device *dev,
7728e757e15SGuenter Roeck struct device_attribute *attr, const char *buf,
7738e757e15SGuenter Roeck size_t count)
7748d5d45fbSJean Delvare {
775b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
776b060f3c4SAxel Lin struct i2c_client *client = data->client;
777c801082dSJean Delvare int nr = to_sensor_dev_attr(attr)->index;
7781c720093SGuenter Roeck long val;
7791c720093SGuenter Roeck int ret;
7808d5d45fbSJean Delvare
7811c720093SGuenter Roeck ret = kstrtol(buf, 10, &val);
7821c720093SGuenter Roeck if (ret)
7831c720093SGuenter Roeck return ret;
7841c720093SGuenter Roeck
785145e74a4SGuenter Roeck val = clamp_val(val, -55000, 127000);
7869a61bf63SIngo Molnar mutex_lock(&data->update_lock);
7878d5d45fbSJean Delvare data->temp_crit[nr] = TEMP_TO_REG(val);
7888d5d45fbSJean Delvare adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
7898d5d45fbSJean Delvare data->temp_crit[nr]);
7909a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
7918d5d45fbSJean Delvare return count;
7928d5d45fbSJean Delvare }
7938d5d45fbSJean Delvare
7948e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
7958e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_offset, temp_offset, 0);
7968e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
7978e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
7988e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp_crit, 0);
7998e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
8008e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_offset, temp_offset, 1);
8018e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
8028e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
8038e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_crit, temp_crit, 1);
8048e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
8058e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_offset, temp_offset, 2);
8068e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2);
8078e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2);
8088e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_crit, temp_crit, 2);
8098d5d45fbSJean Delvare
8108d5d45fbSJean Delvare /* Alarms */
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)811bfb6b173SJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
8121c720093SGuenter Roeck char *buf)
8138d5d45fbSJean Delvare {
8148d5d45fbSJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
8158d5d45fbSJean Delvare return sprintf(buf, "%d\n", data->alarm);
8168d5d45fbSJean Delvare }
8178d5d45fbSJean Delvare
818bfb6b173SJulia Lawall static DEVICE_ATTR_RO(alarms);
8198d5d45fbSJean Delvare
alarm_show(struct device * dev,struct device_attribute * attr,char * buf)8208e757e15SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
8218e757e15SGuenter Roeck char *buf)
822050ab878SJean Delvare {
823050ab878SJean Delvare int bitnr = to_sensor_dev_attr(attr)->index;
824050ab878SJean Delvare struct adm1031_data *data = adm1031_update_device(dev);
825050ab878SJean Delvare return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1);
826050ab878SJean Delvare }
827050ab878SJean Delvare
8288e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 0);
8298e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, 1);
8308e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, alarm, 2);
8318e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, alarm, 3);
8328e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_crit_alarm, alarm, 4);
8338e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 5);
8348e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 6);
8358e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 7);
8368e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 8);
8378e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_fault, alarm, 9);
8388e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, alarm, 10);
8398e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_min_alarm, alarm, 11);
8408e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_crit_alarm, alarm, 12);
8418e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 13);
8428e757e15SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 14);
8438d5d45fbSJean Delvare
844a51b9944SGuenter Roeck /* Update Interval */
845a51b9944SGuenter Roeck static const unsigned int update_intervals[] = {
84687c33daaSJean Delvare 16000, 8000, 4000, 2000, 1000, 500, 250, 125,
84787c33daaSJean Delvare };
84887c33daaSJean Delvare
update_interval_show(struct device * dev,struct device_attribute * attr,char * buf)849bfb6b173SJulia Lawall static ssize_t update_interval_show(struct device *dev,
85087c33daaSJean Delvare struct device_attribute *attr, char *buf)
85187c33daaSJean Delvare {
852b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
85387c33daaSJean Delvare
854a51b9944SGuenter Roeck return sprintf(buf, "%u\n", data->update_interval);
85587c33daaSJean Delvare }
85687c33daaSJean Delvare
update_interval_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)857bfb6b173SJulia Lawall static ssize_t update_interval_store(struct device *dev,
85887c33daaSJean Delvare struct device_attribute *attr,
85987c33daaSJean Delvare const char *buf, size_t count)
86087c33daaSJean Delvare {
861b060f3c4SAxel Lin struct adm1031_data *data = dev_get_drvdata(dev);
862b060f3c4SAxel Lin struct i2c_client *client = data->client;
86387c33daaSJean Delvare unsigned long val;
86487c33daaSJean Delvare int i, err;
86587c33daaSJean Delvare u8 reg;
86687c33daaSJean Delvare
867179c4fdbSFrans Meulenbroeks err = kstrtoul(buf, 10, &val);
86887c33daaSJean Delvare if (err)
86987c33daaSJean Delvare return err;
87087c33daaSJean Delvare
871a51b9944SGuenter Roeck /*
872a51b9944SGuenter Roeck * Find the nearest update interval from the table.
873a51b9944SGuenter Roeck * Use it to determine the matching update rate.
874a51b9944SGuenter Roeck */
875a51b9944SGuenter Roeck for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) {
876a51b9944SGuenter Roeck if (val >= update_intervals[i])
87787c33daaSJean Delvare break;
87887c33daaSJean Delvare }
879a51b9944SGuenter Roeck /* if not found, we point to the last entry (lowest update interval) */
88087c33daaSJean Delvare
88187c33daaSJean Delvare /* set the new update rate while preserving other settings */
88287c33daaSJean Delvare reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
88387c33daaSJean Delvare reg &= ~ADM1031_UPDATE_RATE_MASK;
88487c33daaSJean Delvare reg |= i << ADM1031_UPDATE_RATE_SHIFT;
88587c33daaSJean Delvare adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
88687c33daaSJean Delvare
88787c33daaSJean Delvare mutex_lock(&data->update_lock);
888a51b9944SGuenter Roeck data->update_interval = update_intervals[i];
88987c33daaSJean Delvare mutex_unlock(&data->update_lock);
89087c33daaSJean Delvare
89187c33daaSJean Delvare return count;
89287c33daaSJean Delvare }
89387c33daaSJean Delvare
894bfb6b173SJulia Lawall static DEVICE_ATTR_RW(update_interval);
89587c33daaSJean Delvare
896681c6f7aSMark M. Hoffman static struct attribute *adm1031_attributes[] = {
897c801082dSJean Delvare &sensor_dev_attr_fan1_input.dev_attr.attr,
898c801082dSJean Delvare &sensor_dev_attr_fan1_div.dev_attr.attr,
899c801082dSJean Delvare &sensor_dev_attr_fan1_min.dev_attr.attr,
900050ab878SJean Delvare &sensor_dev_attr_fan1_alarm.dev_attr.attr,
901050ab878SJean Delvare &sensor_dev_attr_fan1_fault.dev_attr.attr,
902c801082dSJean Delvare &sensor_dev_attr_pwm1.dev_attr.attr,
903c801082dSJean Delvare &sensor_dev_attr_auto_fan1_channel.dev_attr.attr,
904c801082dSJean Delvare &sensor_dev_attr_temp1_input.dev_attr.attr,
90549dc9efeSIra Snyder &sensor_dev_attr_temp1_offset.dev_attr.attr,
906c801082dSJean Delvare &sensor_dev_attr_temp1_min.dev_attr.attr,
907050ab878SJean Delvare &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
908c801082dSJean Delvare &sensor_dev_attr_temp1_max.dev_attr.attr,
909050ab878SJean Delvare &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
910c801082dSJean Delvare &sensor_dev_attr_temp1_crit.dev_attr.attr,
911050ab878SJean Delvare &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
912c801082dSJean Delvare &sensor_dev_attr_temp2_input.dev_attr.attr,
91349dc9efeSIra Snyder &sensor_dev_attr_temp2_offset.dev_attr.attr,
914c801082dSJean Delvare &sensor_dev_attr_temp2_min.dev_attr.attr,
915050ab878SJean Delvare &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
916c801082dSJean Delvare &sensor_dev_attr_temp2_max.dev_attr.attr,
917050ab878SJean Delvare &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
918c801082dSJean Delvare &sensor_dev_attr_temp2_crit.dev_attr.attr,
919050ab878SJean Delvare &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
920050ab878SJean Delvare &sensor_dev_attr_temp2_fault.dev_attr.attr,
921681c6f7aSMark M. Hoffman
922c801082dSJean Delvare &sensor_dev_attr_auto_temp1_off.dev_attr.attr,
923c801082dSJean Delvare &sensor_dev_attr_auto_temp1_min.dev_attr.attr,
924c801082dSJean Delvare &sensor_dev_attr_auto_temp1_max.dev_attr.attr,
925681c6f7aSMark M. Hoffman
926c801082dSJean Delvare &sensor_dev_attr_auto_temp2_off.dev_attr.attr,
927c801082dSJean Delvare &sensor_dev_attr_auto_temp2_min.dev_attr.attr,
928c801082dSJean Delvare &sensor_dev_attr_auto_temp2_max.dev_attr.attr,
929681c6f7aSMark M. Hoffman
930c801082dSJean Delvare &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
931681c6f7aSMark M. Hoffman
932a51b9944SGuenter Roeck &dev_attr_update_interval.attr,
933681c6f7aSMark M. Hoffman &dev_attr_alarms.attr,
934681c6f7aSMark M. Hoffman
935681c6f7aSMark M. Hoffman NULL
936681c6f7aSMark M. Hoffman };
937681c6f7aSMark M. Hoffman
938681c6f7aSMark M. Hoffman static const struct attribute_group adm1031_group = {
939681c6f7aSMark M. Hoffman .attrs = adm1031_attributes,
940681c6f7aSMark M. Hoffman };
941681c6f7aSMark M. Hoffman
942681c6f7aSMark M. Hoffman static struct attribute *adm1031_attributes_opt[] = {
943c801082dSJean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr,
944c801082dSJean Delvare &sensor_dev_attr_fan2_div.dev_attr.attr,
945c801082dSJean Delvare &sensor_dev_attr_fan2_min.dev_attr.attr,
946050ab878SJean Delvare &sensor_dev_attr_fan2_alarm.dev_attr.attr,
947050ab878SJean Delvare &sensor_dev_attr_fan2_fault.dev_attr.attr,
948c801082dSJean Delvare &sensor_dev_attr_pwm2.dev_attr.attr,
949c801082dSJean Delvare &sensor_dev_attr_auto_fan2_channel.dev_attr.attr,
950c801082dSJean Delvare &sensor_dev_attr_temp3_input.dev_attr.attr,
95149dc9efeSIra Snyder &sensor_dev_attr_temp3_offset.dev_attr.attr,
952c801082dSJean Delvare &sensor_dev_attr_temp3_min.dev_attr.attr,
953050ab878SJean Delvare &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
954c801082dSJean Delvare &sensor_dev_attr_temp3_max.dev_attr.attr,
955050ab878SJean Delvare &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
956c801082dSJean Delvare &sensor_dev_attr_temp3_crit.dev_attr.attr,
957050ab878SJean Delvare &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
958050ab878SJean Delvare &sensor_dev_attr_temp3_fault.dev_attr.attr,
959c801082dSJean Delvare &sensor_dev_attr_auto_temp3_off.dev_attr.attr,
960c801082dSJean Delvare &sensor_dev_attr_auto_temp3_min.dev_attr.attr,
961c801082dSJean Delvare &sensor_dev_attr_auto_temp3_max.dev_attr.attr,
962c801082dSJean Delvare &sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr,
963681c6f7aSMark M. Hoffman NULL
964681c6f7aSMark M. Hoffman };
965681c6f7aSMark M. Hoffman
966681c6f7aSMark M. Hoffman static const struct attribute_group adm1031_group_opt = {
967681c6f7aSMark M. Hoffman .attrs = adm1031_attributes_opt,
968681c6f7aSMark M. Hoffman };
969681c6f7aSMark M. Hoffman
970af200f88SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */
adm1031_detect(struct i2c_client * client,struct i2c_board_info * info)971310ec792SJean Delvare static int adm1031_detect(struct i2c_client *client,
972af200f88SJean Delvare struct i2c_board_info *info)
9738d5d45fbSJean Delvare {
974af200f88SJean Delvare struct i2c_adapter *adapter = client->adapter;
97552df6440SJean Delvare const char *name;
97652df6440SJean Delvare int id, co;
9778d5d45fbSJean Delvare
9788d5d45fbSJean Delvare if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
979af200f88SJean Delvare return -ENODEV;
9808d5d45fbSJean Delvare
9816d6006b8SJean Delvare id = i2c_smbus_read_byte_data(client, 0x3d);
9826d6006b8SJean Delvare co = i2c_smbus_read_byte_data(client, 0x3e);
9838d5d45fbSJean Delvare
9848d5d45fbSJean Delvare if (!((id == 0x31 || id == 0x30) && co == 0x41))
985af200f88SJean Delvare return -ENODEV;
98652df6440SJean Delvare name = (id == 0x30) ? "adm1030" : "adm1031";
9878d5d45fbSJean Delvare
988f2f394dbSWolfram Sang strscpy(info->type, name, I2C_NAME_SIZE);
9898d5d45fbSJean Delvare
990af200f88SJean Delvare return 0;
991af200f88SJean Delvare }
992af200f88SJean Delvare
adm1031_init_client(struct i2c_client * client)993278ee1c8SAxel Lin static void adm1031_init_client(struct i2c_client *client)
994278ee1c8SAxel Lin {
995278ee1c8SAxel Lin unsigned int read_val;
996278ee1c8SAxel Lin unsigned int mask;
997278ee1c8SAxel Lin int i;
998278ee1c8SAxel Lin struct adm1031_data *data = i2c_get_clientdata(client);
999278ee1c8SAxel Lin
1000278ee1c8SAxel Lin mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
1001278ee1c8SAxel Lin if (data->chip_type == adm1031) {
1002278ee1c8SAxel Lin mask |= (ADM1031_CONF2_PWM2_ENABLE |
1003278ee1c8SAxel Lin ADM1031_CONF2_TACH2_ENABLE);
1004278ee1c8SAxel Lin }
1005278ee1c8SAxel Lin /* Initialize the ADM1031 chip (enables fan speed reading ) */
1006278ee1c8SAxel Lin read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
1007278ee1c8SAxel Lin if ((read_val | mask) != read_val)
1008278ee1c8SAxel Lin adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
1009278ee1c8SAxel Lin
1010278ee1c8SAxel Lin read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
1011278ee1c8SAxel Lin if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
1012278ee1c8SAxel Lin adm1031_write_value(client, ADM1031_REG_CONF1,
1013278ee1c8SAxel Lin read_val | ADM1031_CONF1_MONITOR_ENABLE);
1014278ee1c8SAxel Lin }
1015278ee1c8SAxel Lin
1016278ee1c8SAxel Lin /* Read the chip's update rate */
1017278ee1c8SAxel Lin mask = ADM1031_UPDATE_RATE_MASK;
1018278ee1c8SAxel Lin read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
1019278ee1c8SAxel Lin i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
1020278ee1c8SAxel Lin /* Save it as update interval */
1021278ee1c8SAxel Lin data->update_interval = update_intervals[i];
1022278ee1c8SAxel Lin }
1023278ee1c8SAxel Lin
102467487038SStephen Kitt static const struct i2c_device_id adm1031_id[];
102567487038SStephen Kitt
adm1031_probe(struct i2c_client * client)102667487038SStephen Kitt static int adm1031_probe(struct i2c_client *client)
1027af200f88SJean Delvare {
1028b060f3c4SAxel Lin struct device *dev = &client->dev;
1029b060f3c4SAxel Lin struct device *hwmon_dev;
1030af200f88SJean Delvare struct adm1031_data *data;
1031af200f88SJean Delvare
1032b060f3c4SAxel Lin data = devm_kzalloc(dev, sizeof(struct adm1031_data), GFP_KERNEL);
1033dc2fd663SGuenter Roeck if (!data)
1034dc2fd663SGuenter Roeck return -ENOMEM;
1035af200f88SJean Delvare
1036af200f88SJean Delvare i2c_set_clientdata(client, data);
1037b060f3c4SAxel Lin data->client = client;
103867487038SStephen Kitt data->chip_type = i2c_match_id(adm1031_id, client)->driver_data;
10399a61bf63SIngo Molnar mutex_init(&data->update_lock);
10408d5d45fbSJean Delvare
1041af200f88SJean Delvare if (data->chip_type == adm1030)
1042af200f88SJean Delvare data->chan_select_table = &auto_channel_select_table_adm1030;
1043af200f88SJean Delvare else
1044af200f88SJean Delvare data->chan_select_table = &auto_channel_select_table_adm1031;
10458d5d45fbSJean Delvare
10468d5d45fbSJean Delvare /* Initialize the ADM1031 chip */
10476d6006b8SJean Delvare adm1031_init_client(client);
10488d5d45fbSJean Delvare
1049b060f3c4SAxel Lin /* sysfs hooks */
1050b060f3c4SAxel Lin data->groups[0] = &adm1031_group;
1051b060f3c4SAxel Lin if (data->chip_type == adm1031)
1052b060f3c4SAxel Lin data->groups[1] = &adm1031_group_opt;
1053681c6f7aSMark M. Hoffman
1054b060f3c4SAxel Lin hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
1055b060f3c4SAxel Lin data, data->groups);
1056b060f3c4SAxel Lin return PTR_ERR_OR_ZERO(hwmon_dev);
10578d5d45fbSJean Delvare }
10588d5d45fbSJean Delvare
1059278ee1c8SAxel Lin static const struct i2c_device_id adm1031_id[] = {
1060278ee1c8SAxel Lin { "adm1030", adm1030 },
1061278ee1c8SAxel Lin { "adm1031", adm1031 },
1062278ee1c8SAxel Lin { }
1063278ee1c8SAxel Lin };
1064278ee1c8SAxel Lin MODULE_DEVICE_TABLE(i2c, adm1031_id);
10658d5d45fbSJean Delvare
1066278ee1c8SAxel Lin static struct i2c_driver adm1031_driver = {
1067278ee1c8SAxel Lin .class = I2C_CLASS_HWMON,
1068278ee1c8SAxel Lin .driver = {
1069278ee1c8SAxel Lin .name = "adm1031",
1070278ee1c8SAxel Lin },
1071*1975d167SUwe Kleine-König .probe = adm1031_probe,
1072278ee1c8SAxel Lin .id_table = adm1031_id,
1073278ee1c8SAxel Lin .detect = adm1031_detect,
1074278ee1c8SAxel Lin .address_list = normal_i2c,
1075278ee1c8SAxel Lin };
10768d5d45fbSJean Delvare
1077f0967eeaSAxel Lin module_i2c_driver(adm1031_driver);
10788d5d45fbSJean Delvare
10798d5d45fbSJean Delvare MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");
10808d5d45fbSJean Delvare MODULE_DESCRIPTION("ADM1031/ADM1030 driver");
10818d5d45fbSJean Delvare MODULE_LICENSE("GPL");
1082