xref: /openbmc/linux/drivers/hwmon/adm1031.c (revision bfb6b1732a2c3212ab1088adf26444783367cb28)
18d5d45fbSJean Delvare /*
2fbb6670dSGuenter Roeck  * adm1031.c - Part of lm_sensors, Linux kernel modules for hardware
3fbb6670dSGuenter Roeck  *	       monitoring
4fbb6670dSGuenter Roeck  * Based on lm75.c and lm85.c
5fbb6670dSGuenter Roeck  * Supports adm1030 / adm1031
6fbb6670dSGuenter Roeck  * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
77c81c60fSJean Delvare  * Reworked by Jean Delvare <jdelvare@suse.de>
8fbb6670dSGuenter Roeck  *
9fbb6670dSGuenter Roeck  * This program is free software; you can redistribute it and/or modify
10fbb6670dSGuenter Roeck  * it under the terms of the GNU General Public License as published by
11fbb6670dSGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
12fbb6670dSGuenter Roeck  * (at your option) any later version.
13fbb6670dSGuenter Roeck  *
14fbb6670dSGuenter Roeck  * This program is distributed in the hope that it will be useful,
15fbb6670dSGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16fbb6670dSGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17fbb6670dSGuenter Roeck  * GNU General Public License for more details.
18fbb6670dSGuenter Roeck  *
19fbb6670dSGuenter Roeck  * You should have received a copy of the GNU General Public License
20fbb6670dSGuenter Roeck  * along with this program; if not, write to the Free Software
21fbb6670dSGuenter Roeck  * 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>
30c801082dSJean Delvare #include <linux/hwmon-sysfs.h>
31943b0830SMark M. Hoffman #include <linux/err.h>
329a61bf63SIngo Molnar #include <linux/mutex.h>
338d5d45fbSJean Delvare 
348d5d45fbSJean Delvare /* Following macros takes channel parameter starting from 0 to 2 */
358d5d45fbSJean Delvare #define ADM1031_REG_FAN_SPEED(nr)	(0x08 + (nr))
368d5d45fbSJean Delvare #define ADM1031_REG_FAN_DIV(nr)		(0x20 + (nr))
378d5d45fbSJean Delvare #define ADM1031_REG_PWM			(0x22)
388d5d45fbSJean Delvare #define ADM1031_REG_FAN_MIN(nr)		(0x10 + (nr))
3987c33daaSJean Delvare #define ADM1031_REG_FAN_FILTER		(0x23)
408d5d45fbSJean Delvare 
4149dc9efeSIra Snyder #define ADM1031_REG_TEMP_OFFSET(nr)	(0x0d + (nr))
428d5d45fbSJean Delvare #define ADM1031_REG_TEMP_MAX(nr)	(0x14 + 4 * (nr))
438d5d45fbSJean Delvare #define ADM1031_REG_TEMP_MIN(nr)	(0x15 + 4 * (nr))
448d5d45fbSJean Delvare #define ADM1031_REG_TEMP_CRIT(nr)	(0x16 + 4 * (nr))
458d5d45fbSJean Delvare 
466d6006b8SJean Delvare #define ADM1031_REG_TEMP(nr)		(0x0a + (nr))
478d5d45fbSJean Delvare #define ADM1031_REG_AUTO_TEMP(nr)	(0x24 + (nr))
488d5d45fbSJean Delvare 
498d5d45fbSJean Delvare #define ADM1031_REG_STATUS(nr)		(0x2 + (nr))
508d5d45fbSJean Delvare 
516d6006b8SJean Delvare #define ADM1031_REG_CONF1		0x00
526d6006b8SJean Delvare #define ADM1031_REG_CONF2		0x01
536d6006b8SJean Delvare #define ADM1031_REG_EXT_TEMP		0x06
548d5d45fbSJean Delvare 
558d5d45fbSJean Delvare #define ADM1031_CONF1_MONITOR_ENABLE	0x01	/* Monitoring enable */
568d5d45fbSJean Delvare #define ADM1031_CONF1_PWM_INVERT	0x08	/* PWM Invert */
578d5d45fbSJean Delvare #define ADM1031_CONF1_AUTO_MODE		0x80	/* Auto FAN */
588d5d45fbSJean Delvare 
598d5d45fbSJean Delvare #define ADM1031_CONF2_PWM1_ENABLE	0x01
608d5d45fbSJean Delvare #define ADM1031_CONF2_PWM2_ENABLE	0x02
618d5d45fbSJean Delvare #define ADM1031_CONF2_TACH1_ENABLE	0x04
628d5d45fbSJean Delvare #define ADM1031_CONF2_TACH2_ENABLE	0x08
638d5d45fbSJean Delvare #define ADM1031_CONF2_TEMP_ENABLE(chan)	(0x10 << (chan))
648d5d45fbSJean Delvare 
6587c33daaSJean Delvare #define ADM1031_UPDATE_RATE_MASK	0x1c
6687c33daaSJean Delvare #define ADM1031_UPDATE_RATE_SHIFT	2
6787c33daaSJean Delvare 
688d5d45fbSJean Delvare /* Addresses to scan */
6925e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
708d5d45fbSJean Delvare 
71e5e9f44cSJean Delvare enum chips { adm1030, adm1031 };
728d5d45fbSJean Delvare 
738d5d45fbSJean Delvare typedef u8 auto_chan_table_t[8][2];
748d5d45fbSJean Delvare 
758d5d45fbSJean Delvare /* Each client has this additional data */
768d5d45fbSJean Delvare struct adm1031_data {
77b060f3c4SAxel Lin 	struct i2c_client *client;
78b060f3c4SAxel Lin 	const struct attribute_group *groups[3];
799a61bf63SIngo Molnar 	struct mutex update_lock;
808d5d45fbSJean Delvare 	int chip_type;
818d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
828d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
83a51b9944SGuenter Roeck 	unsigned int update_interval;	/* In milliseconds */
84fbb6670dSGuenter Roeck 	/*
85fbb6670dSGuenter Roeck 	 * The chan_select_table contains the possible configurations for
868d5d45fbSJean Delvare 	 * auto fan control.
878d5d45fbSJean Delvare 	 */
886d6006b8SJean Delvare 	const auto_chan_table_t *chan_select_table;
898d5d45fbSJean Delvare 	u16 alarm;
908d5d45fbSJean Delvare 	u8 conf1;
918d5d45fbSJean Delvare 	u8 conf2;
928d5d45fbSJean Delvare 	u8 fan[2];
938d5d45fbSJean Delvare 	u8 fan_div[2];
948d5d45fbSJean Delvare 	u8 fan_min[2];
958d5d45fbSJean Delvare 	u8 pwm[2];
968d5d45fbSJean Delvare 	u8 old_pwm[2];
978d5d45fbSJean Delvare 	s8 temp[3];
988d5d45fbSJean Delvare 	u8 ext_temp[3];
998d5d45fbSJean Delvare 	u8 auto_temp[3];
1008d5d45fbSJean Delvare 	u8 auto_temp_min[3];
1018d5d45fbSJean Delvare 	u8 auto_temp_off[3];
1028d5d45fbSJean Delvare 	u8 auto_temp_max[3];
10349dc9efeSIra Snyder 	s8 temp_offset[3];
1048d5d45fbSJean Delvare 	s8 temp_min[3];
1058d5d45fbSJean Delvare 	s8 temp_max[3];
1068d5d45fbSJean Delvare 	s8 temp_crit[3];
1078d5d45fbSJean Delvare };
1088d5d45fbSJean Delvare 
1098d5d45fbSJean Delvare static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
1108d5d45fbSJean Delvare {
1118d5d45fbSJean Delvare 	return i2c_smbus_read_byte_data(client, reg);
1128d5d45fbSJean Delvare }
1138d5d45fbSJean Delvare 
1148d5d45fbSJean Delvare static inline int
1158d5d45fbSJean Delvare adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
1168d5d45fbSJean Delvare {
1178d5d45fbSJean Delvare 	return i2c_smbus_write_byte_data(client, reg, value);
1188d5d45fbSJean Delvare }
1198d5d45fbSJean Delvare 
120278ee1c8SAxel Lin static struct adm1031_data *adm1031_update_device(struct device *dev)
121278ee1c8SAxel Lin {
122b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
123b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
124278ee1c8SAxel Lin 	unsigned long next_update;
125278ee1c8SAxel Lin 	int chan;
126278ee1c8SAxel Lin 
127278ee1c8SAxel Lin 	mutex_lock(&data->update_lock);
128278ee1c8SAxel Lin 
129278ee1c8SAxel Lin 	next_update = data->last_updated
130278ee1c8SAxel Lin 	  + msecs_to_jiffies(data->update_interval);
131278ee1c8SAxel Lin 	if (time_after(jiffies, next_update) || !data->valid) {
132278ee1c8SAxel Lin 
133278ee1c8SAxel Lin 		dev_dbg(&client->dev, "Starting adm1031 update\n");
134278ee1c8SAxel Lin 		for (chan = 0;
135278ee1c8SAxel Lin 		     chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {
136278ee1c8SAxel Lin 			u8 oldh, newh;
137278ee1c8SAxel Lin 
138278ee1c8SAxel Lin 			oldh =
139278ee1c8SAxel Lin 			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));
140278ee1c8SAxel Lin 			data->ext_temp[chan] =
141278ee1c8SAxel Lin 			    adm1031_read_value(client, ADM1031_REG_EXT_TEMP);
142278ee1c8SAxel Lin 			newh =
143278ee1c8SAxel Lin 			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));
144278ee1c8SAxel Lin 			if (newh != oldh) {
145278ee1c8SAxel Lin 				data->ext_temp[chan] =
146278ee1c8SAxel Lin 				    adm1031_read_value(client,
147278ee1c8SAxel Lin 						       ADM1031_REG_EXT_TEMP);
148278ee1c8SAxel Lin #ifdef DEBUG
149278ee1c8SAxel Lin 				oldh =
150278ee1c8SAxel Lin 				    adm1031_read_value(client,
151278ee1c8SAxel Lin 						       ADM1031_REG_TEMP(chan));
152278ee1c8SAxel Lin 
153278ee1c8SAxel Lin 				/* oldh is actually newer */
154278ee1c8SAxel Lin 				if (newh != oldh)
155278ee1c8SAxel Lin 					dev_warn(&client->dev,
156278ee1c8SAxel Lin 					  "Remote temperature may be wrong.\n");
157278ee1c8SAxel Lin #endif
158278ee1c8SAxel Lin 			}
159278ee1c8SAxel Lin 			data->temp[chan] = newh;
160278ee1c8SAxel Lin 
161278ee1c8SAxel Lin 			data->temp_offset[chan] =
162278ee1c8SAxel Lin 			    adm1031_read_value(client,
163278ee1c8SAxel Lin 					       ADM1031_REG_TEMP_OFFSET(chan));
164278ee1c8SAxel Lin 			data->temp_min[chan] =
165278ee1c8SAxel Lin 			    adm1031_read_value(client,
166278ee1c8SAxel Lin 					       ADM1031_REG_TEMP_MIN(chan));
167278ee1c8SAxel Lin 			data->temp_max[chan] =
168278ee1c8SAxel Lin 			    adm1031_read_value(client,
169278ee1c8SAxel Lin 					       ADM1031_REG_TEMP_MAX(chan));
170278ee1c8SAxel Lin 			data->temp_crit[chan] =
171278ee1c8SAxel Lin 			    adm1031_read_value(client,
172278ee1c8SAxel Lin 					       ADM1031_REG_TEMP_CRIT(chan));
173278ee1c8SAxel Lin 			data->auto_temp[chan] =
174278ee1c8SAxel Lin 			    adm1031_read_value(client,
175278ee1c8SAxel Lin 					       ADM1031_REG_AUTO_TEMP(chan));
176278ee1c8SAxel Lin 
177278ee1c8SAxel Lin 		}
178278ee1c8SAxel Lin 
179278ee1c8SAxel Lin 		data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);
180278ee1c8SAxel Lin 		data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
181278ee1c8SAxel Lin 
182278ee1c8SAxel Lin 		data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
183278ee1c8SAxel Lin 		    | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
184278ee1c8SAxel Lin 		if (data->chip_type == adm1030)
185278ee1c8SAxel Lin 			data->alarm &= 0xc0ff;
186278ee1c8SAxel Lin 
187278ee1c8SAxel Lin 		for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
188278ee1c8SAxel Lin 		     chan++) {
189278ee1c8SAxel Lin 			data->fan_div[chan] =
190278ee1c8SAxel Lin 			    adm1031_read_value(client,
191278ee1c8SAxel Lin 					       ADM1031_REG_FAN_DIV(chan));
192278ee1c8SAxel Lin 			data->fan_min[chan] =
193278ee1c8SAxel Lin 			    adm1031_read_value(client,
194278ee1c8SAxel Lin 					       ADM1031_REG_FAN_MIN(chan));
195278ee1c8SAxel Lin 			data->fan[chan] =
196278ee1c8SAxel Lin 			    adm1031_read_value(client,
197278ee1c8SAxel Lin 					       ADM1031_REG_FAN_SPEED(chan));
198278ee1c8SAxel Lin 			data->pwm[chan] =
199278ee1c8SAxel Lin 			  (adm1031_read_value(client,
200278ee1c8SAxel Lin 					ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
201278ee1c8SAxel Lin 		}
202278ee1c8SAxel Lin 		data->last_updated = jiffies;
203278ee1c8SAxel Lin 		data->valid = 1;
204278ee1c8SAxel Lin 	}
205278ee1c8SAxel Lin 
206278ee1c8SAxel Lin 	mutex_unlock(&data->update_lock);
207278ee1c8SAxel Lin 
208278ee1c8SAxel Lin 	return data;
209278ee1c8SAxel Lin }
2108d5d45fbSJean Delvare 
2118d5d45fbSJean Delvare #define TEMP_TO_REG(val)		(((val) < 0 ? ((val - 500) / 1000) : \
2128d5d45fbSJean Delvare 					((val + 500) / 1000)))
2138d5d45fbSJean Delvare 
2148d5d45fbSJean Delvare #define TEMP_FROM_REG(val)		((val) * 1000)
2158d5d45fbSJean Delvare 
2168d5d45fbSJean Delvare #define TEMP_FROM_REG_EXT(val, ext)	(TEMP_FROM_REG(val) + (ext) * 125)
2178d5d45fbSJean Delvare 
21849dc9efeSIra Snyder #define TEMP_OFFSET_TO_REG(val)		(TEMP_TO_REG(val) & 0x8f)
21949dc9efeSIra Snyder #define TEMP_OFFSET_FROM_REG(val)	TEMP_FROM_REG((val) < 0 ? \
22049dc9efeSIra Snyder 						      (val) | 0x70 : (val))
22149dc9efeSIra Snyder 
2221c720093SGuenter Roeck #define FAN_FROM_REG(reg, div)		((reg) ? \
2231c720093SGuenter Roeck 					 (11250 * 60) / ((reg) * (div)) : 0)
2248d5d45fbSJean Delvare 
2258d5d45fbSJean Delvare static int FAN_TO_REG(int reg, int div)
2268d5d45fbSJean Delvare {
2278d5d45fbSJean Delvare 	int tmp;
2282a844c14SGuenter Roeck 	tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
2298d5d45fbSJean Delvare 	return tmp > 255 ? 255 : tmp;
2308d5d45fbSJean Delvare }
2318d5d45fbSJean Delvare 
2328d5d45fbSJean Delvare #define FAN_DIV_FROM_REG(reg)		(1<<(((reg)&0xc0)>>6))
2338d5d45fbSJean Delvare 
2342a844c14SGuenter Roeck #define PWM_TO_REG(val)			(clamp_val((val), 0, 255) >> 4)
2358d5d45fbSJean Delvare #define PWM_FROM_REG(val)		((val) << 4)
2368d5d45fbSJean Delvare 
2378d5d45fbSJean Delvare #define FAN_CHAN_FROM_REG(reg)		(((reg) >> 5) & 7)
2388d5d45fbSJean Delvare #define FAN_CHAN_TO_REG(val, reg)	\
2398d5d45fbSJean Delvare 	(((reg) & 0x1F) | (((val) << 5) & 0xe0))
2408d5d45fbSJean Delvare 
2418d5d45fbSJean Delvare #define AUTO_TEMP_MIN_TO_REG(val, reg)	\
2428d5d45fbSJean Delvare 	((((val) / 500) & 0xf8) | ((reg) & 0x7))
2438d5d45fbSJean Delvare #define AUTO_TEMP_RANGE_FROM_REG(reg)	(5000 * (1 << ((reg) & 0x7)))
2448d5d45fbSJean Delvare #define AUTO_TEMP_MIN_FROM_REG(reg)	(1000 * ((((reg) >> 3) & 0x1f) << 2))
2458d5d45fbSJean Delvare 
2468d5d45fbSJean Delvare #define AUTO_TEMP_MIN_FROM_REG_DEG(reg)	((((reg) >> 3) & 0x1f) << 2)
2478d5d45fbSJean Delvare 
2488d5d45fbSJean Delvare #define AUTO_TEMP_OFF_FROM_REG(reg)		\
2498d5d45fbSJean Delvare 	(AUTO_TEMP_MIN_FROM_REG(reg) - 5000)
2508d5d45fbSJean Delvare 
2518d5d45fbSJean Delvare #define AUTO_TEMP_MAX_FROM_REG(reg)		\
2528d5d45fbSJean Delvare 	(AUTO_TEMP_RANGE_FROM_REG(reg) +	\
2538d5d45fbSJean Delvare 	AUTO_TEMP_MIN_FROM_REG(reg))
2548d5d45fbSJean Delvare 
2558d5d45fbSJean Delvare static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
2568d5d45fbSJean Delvare {
2578d5d45fbSJean Delvare 	int ret;
2588d5d45fbSJean Delvare 	int range = val - AUTO_TEMP_MIN_FROM_REG(reg);
2598d5d45fbSJean Delvare 
2608d5d45fbSJean Delvare 	range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm);
2618d5d45fbSJean Delvare 	ret = ((reg & 0xf8) |
2628d5d45fbSJean Delvare 	       (range < 10000 ? 0 :
2638d5d45fbSJean Delvare 		range < 20000 ? 1 :
2648d5d45fbSJean Delvare 		range < 40000 ? 2 : range < 80000 ? 3 : 4));
2658d5d45fbSJean Delvare 	return ret;
2668d5d45fbSJean Delvare }
2678d5d45fbSJean Delvare 
2688d5d45fbSJean Delvare /* FAN auto control */
2698d5d45fbSJean Delvare #define GET_FAN_AUTO_BITFIELD(data, idx)	\
2708d5d45fbSJean Delvare 	(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
2718d5d45fbSJean Delvare 
272fbb6670dSGuenter Roeck /*
273fbb6670dSGuenter Roeck  * The tables below contains the possible values for the auto fan
2748d5d45fbSJean Delvare  * control bitfields. the index in the table is the register value.
2758d5d45fbSJean Delvare  * MSb is the auto fan control enable bit, so the four first entries
2768d5d45fbSJean Delvare  * in the table disables auto fan control when both bitfields are zero.
2778d5d45fbSJean Delvare  */
2786d6006b8SJean Delvare static const auto_chan_table_t auto_channel_select_table_adm1031 = {
2798d5d45fbSJean Delvare 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2808d5d45fbSJean Delvare 	{ 2 /* 0b010 */ , 4 /* 0b100 */ },
2818d5d45fbSJean Delvare 	{ 2 /* 0b010 */ , 2 /* 0b010 */ },
2828d5d45fbSJean Delvare 	{ 4 /* 0b100 */ , 4 /* 0b100 */ },
2838d5d45fbSJean Delvare 	{ 7 /* 0b111 */ , 7 /* 0b111 */ },
2848d5d45fbSJean Delvare };
2858d5d45fbSJean Delvare 
2866d6006b8SJean Delvare static const auto_chan_table_t auto_channel_select_table_adm1030 = {
2878d5d45fbSJean Delvare 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2888d5d45fbSJean Delvare 	{ 2 /* 0b10 */		, 0 },
2898d5d45fbSJean Delvare 	{ 0xff /* invalid */	, 0 },
2908d5d45fbSJean Delvare 	{ 0xff /* invalid */	, 0 },
2918d5d45fbSJean Delvare 	{ 3 /* 0b11 */		, 0 },
2928d5d45fbSJean Delvare };
2938d5d45fbSJean Delvare 
294fbb6670dSGuenter Roeck /*
295fbb6670dSGuenter Roeck  * That function checks if a bitfield is valid and returns the other bitfield
2968d5d45fbSJean Delvare  * nearest match if no exact match where found.
2978d5d45fbSJean Delvare  */
2988d5d45fbSJean Delvare static int
299ce15a81dSGuenter Roeck get_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg)
3008d5d45fbSJean Delvare {
3018d5d45fbSJean Delvare 	int i;
3028d5d45fbSJean Delvare 	int first_match = -1, exact_match = -1;
3038d5d45fbSJean Delvare 	u8 other_reg_val =
3048d5d45fbSJean Delvare 	    (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1];
3058d5d45fbSJean Delvare 
306ce15a81dSGuenter Roeck 	if (val == 0)
3078d5d45fbSJean Delvare 		return 0;
3088d5d45fbSJean Delvare 
3098d5d45fbSJean Delvare 	for (i = 0; i < 8; i++) {
3108d5d45fbSJean Delvare 		if ((val == (*data->chan_select_table)[i][chan]) &&
3118d5d45fbSJean Delvare 		    ((*data->chan_select_table)[i][chan ? 0 : 1] ==
3128d5d45fbSJean Delvare 		     other_reg_val)) {
3138d5d45fbSJean Delvare 			/* We found an exact match */
3148d5d45fbSJean Delvare 			exact_match = i;
3158d5d45fbSJean Delvare 			break;
3168d5d45fbSJean Delvare 		} else if (val == (*data->chan_select_table)[i][chan] &&
3178d5d45fbSJean Delvare 			   first_match == -1) {
318fbb6670dSGuenter Roeck 			/*
319fbb6670dSGuenter Roeck 			 * Save the first match in case of an exact match has
3206d6006b8SJean Delvare 			 * not been found
3218d5d45fbSJean Delvare 			 */
3228d5d45fbSJean Delvare 			first_match = i;
3238d5d45fbSJean Delvare 		}
3248d5d45fbSJean Delvare 	}
3258d5d45fbSJean Delvare 
3261c720093SGuenter Roeck 	if (exact_match >= 0)
327ce15a81dSGuenter Roeck 		return exact_match;
3281c720093SGuenter Roeck 	else if (first_match >= 0)
329ce15a81dSGuenter Roeck 		return first_match;
3301c720093SGuenter Roeck 
331ce15a81dSGuenter Roeck 	return -EINVAL;
3328d5d45fbSJean Delvare }
3338d5d45fbSJean Delvare 
334c801082dSJean Delvare static ssize_t show_fan_auto_channel(struct device *dev,
335c801082dSJean Delvare 				     struct device_attribute *attr, char *buf)
3368d5d45fbSJean Delvare {
337c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
3388d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
3398d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr));
3408d5d45fbSJean Delvare }
3418d5d45fbSJean Delvare 
3428d5d45fbSJean Delvare static ssize_t
343c801082dSJean Delvare set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
344c801082dSJean Delvare 		     const char *buf, size_t count)
3458d5d45fbSJean Delvare {
346b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
347b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
348c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
3491c720093SGuenter Roeck 	long val;
3508d5d45fbSJean Delvare 	u8 reg;
3518d5d45fbSJean Delvare 	int ret;
3528d5d45fbSJean Delvare 	u8 old_fan_mode;
3538d5d45fbSJean Delvare 
3541c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
3551c720093SGuenter Roeck 	if (ret)
3561c720093SGuenter Roeck 		return ret;
3571c720093SGuenter Roeck 
3588d5d45fbSJean Delvare 	old_fan_mode = data->conf1;
3598d5d45fbSJean Delvare 
3609a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
3618d5d45fbSJean Delvare 
362ce15a81dSGuenter Roeck 	ret = get_fan_auto_nearest(data, nr, val, data->conf1);
363ce15a81dSGuenter Roeck 	if (ret < 0) {
3649a61bf63SIngo Molnar 		mutex_unlock(&data->update_lock);
3658d5d45fbSJean Delvare 		return ret;
3668d5d45fbSJean Delvare 	}
367ce15a81dSGuenter Roeck 	reg = ret;
3686d6006b8SJean Delvare 	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
3696d6006b8SJean Delvare 	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
3708d5d45fbSJean Delvare 	    (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
3718d5d45fbSJean Delvare 		if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
372fbb6670dSGuenter Roeck 			/*
373fbb6670dSGuenter Roeck 			 * Switch to Auto Fan Mode
3748d5d45fbSJean Delvare 			 * Save PWM registers
375fbb6670dSGuenter Roeck 			 * Set PWM registers to 33% Both
376fbb6670dSGuenter Roeck 			 */
3778d5d45fbSJean Delvare 			data->old_pwm[0] = data->pwm[0];
3788d5d45fbSJean Delvare 			data->old_pwm[1] = data->pwm[1];
3798d5d45fbSJean Delvare 			adm1031_write_value(client, ADM1031_REG_PWM, 0x55);
3808d5d45fbSJean Delvare 		} else {
3818d5d45fbSJean Delvare 			/* Switch to Manual Mode */
3828d5d45fbSJean Delvare 			data->pwm[0] = data->old_pwm[0];
3838d5d45fbSJean Delvare 			data->pwm[1] = data->old_pwm[1];
3848d5d45fbSJean Delvare 			/* Restore PWM registers */
3858d5d45fbSJean Delvare 			adm1031_write_value(client, ADM1031_REG_PWM,
3868d5d45fbSJean Delvare 					    data->pwm[0] | (data->pwm[1] << 4));
3878d5d45fbSJean Delvare 		}
3888d5d45fbSJean Delvare 	}
3898d5d45fbSJean Delvare 	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
3908d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1);
3919a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3928d5d45fbSJean Delvare 	return count;
3938d5d45fbSJean Delvare }
3948d5d45fbSJean Delvare 
395c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_fan1_channel, S_IRUGO | S_IWUSR,
396c801082dSJean Delvare 		show_fan_auto_channel, set_fan_auto_channel, 0);
397c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_fan2_channel, S_IRUGO | S_IWUSR,
398c801082dSJean Delvare 		show_fan_auto_channel, set_fan_auto_channel, 1);
3998d5d45fbSJean Delvare 
4008d5d45fbSJean Delvare /* Auto Temps */
401c801082dSJean Delvare static ssize_t show_auto_temp_off(struct device *dev,
402c801082dSJean Delvare 				  struct device_attribute *attr, char *buf)
4038d5d45fbSJean Delvare {
404c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4058d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
4068d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
4078d5d45fbSJean Delvare 		       AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr]));
4088d5d45fbSJean Delvare }
409c801082dSJean Delvare static ssize_t show_auto_temp_min(struct device *dev,
410c801082dSJean Delvare 				  struct device_attribute *attr, char *buf)
4118d5d45fbSJean Delvare {
412c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4138d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
4148d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
4158d5d45fbSJean Delvare 		       AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr]));
4168d5d45fbSJean Delvare }
4178d5d45fbSJean Delvare static ssize_t
418c801082dSJean Delvare set_auto_temp_min(struct device *dev, struct device_attribute *attr,
419c801082dSJean Delvare 		  const char *buf, size_t count)
4208d5d45fbSJean Delvare {
421b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
422b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
423c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4241c720093SGuenter Roeck 	long val;
4251c720093SGuenter Roeck 	int ret;
4261c720093SGuenter Roeck 
4271c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
4281c720093SGuenter Roeck 	if (ret)
4291c720093SGuenter Roeck 		return ret;
4308d5d45fbSJean Delvare 
431145e74a4SGuenter Roeck 	val = clamp_val(val, 0, 127000);
4329a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4338d5d45fbSJean Delvare 	data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
4348d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
4358d5d45fbSJean Delvare 			    data->auto_temp[nr]);
4369a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4378d5d45fbSJean Delvare 	return count;
4388d5d45fbSJean Delvare }
439c801082dSJean Delvare static ssize_t show_auto_temp_max(struct device *dev,
440c801082dSJean Delvare 				  struct device_attribute *attr, char *buf)
4418d5d45fbSJean Delvare {
442c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4438d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
4448d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
4458d5d45fbSJean Delvare 		       AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr]));
4468d5d45fbSJean Delvare }
4478d5d45fbSJean Delvare static ssize_t
448c801082dSJean Delvare set_auto_temp_max(struct device *dev, struct device_attribute *attr,
449c801082dSJean Delvare 		  const char *buf, size_t count)
4508d5d45fbSJean Delvare {
451b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
452b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
453c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4541c720093SGuenter Roeck 	long val;
4551c720093SGuenter Roeck 	int ret;
4561c720093SGuenter Roeck 
4571c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
4581c720093SGuenter Roeck 	if (ret)
4591c720093SGuenter Roeck 		return ret;
4608d5d45fbSJean Delvare 
461145e74a4SGuenter Roeck 	val = clamp_val(val, 0, 127000);
4629a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4631c720093SGuenter Roeck 	data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr],
4641c720093SGuenter Roeck 						  data->pwm[nr]);
4658d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
4668d5d45fbSJean Delvare 			    data->temp_max[nr]);
4679a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4688d5d45fbSJean Delvare 	return count;
4698d5d45fbSJean Delvare }
4708d5d45fbSJean Delvare 
4718d5d45fbSJean Delvare #define auto_temp_reg(offset)						\
472c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO,		\
473c801082dSJean Delvare 		show_auto_temp_off, NULL, offset - 1);			\
474c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR,	\
475c801082dSJean Delvare 		show_auto_temp_min, set_auto_temp_min, offset - 1);	\
476c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR,	\
477c801082dSJean Delvare 		show_auto_temp_max, set_auto_temp_max, offset - 1)
4788d5d45fbSJean Delvare 
4798d5d45fbSJean Delvare auto_temp_reg(1);
4808d5d45fbSJean Delvare auto_temp_reg(2);
4818d5d45fbSJean Delvare auto_temp_reg(3);
4828d5d45fbSJean Delvare 
4838d5d45fbSJean Delvare /* pwm */
484c801082dSJean Delvare static ssize_t show_pwm(struct device *dev,
485c801082dSJean Delvare 			struct device_attribute *attr, char *buf)
4868d5d45fbSJean Delvare {
487c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4888d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
4898d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
4908d5d45fbSJean Delvare }
491c801082dSJean Delvare static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
492c801082dSJean Delvare 		       const char *buf, size_t count)
4938d5d45fbSJean Delvare {
494b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
495b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
496c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
4971c720093SGuenter Roeck 	long val;
4981c720093SGuenter Roeck 	int ret, reg;
4991c720093SGuenter Roeck 
5001c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
5011c720093SGuenter Roeck 	if (ret)
5021c720093SGuenter Roeck 		return ret;
5038d5d45fbSJean Delvare 
5049a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5058d5d45fbSJean Delvare 	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
5068d5d45fbSJean Delvare 	    (((val>>4) & 0xf) != 5)) {
5078d5d45fbSJean Delvare 		/* In automatic mode, the only PWM accepted is 33% */
5089a61bf63SIngo Molnar 		mutex_unlock(&data->update_lock);
5098d5d45fbSJean Delvare 		return -EINVAL;
5108d5d45fbSJean Delvare 	}
5118d5d45fbSJean Delvare 	data->pwm[nr] = PWM_TO_REG(val);
5128d5d45fbSJean Delvare 	reg = adm1031_read_value(client, ADM1031_REG_PWM);
5138d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_PWM,
5148d5d45fbSJean Delvare 			    nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf)
5158d5d45fbSJean Delvare 			    : (data->pwm[nr] & 0xf) | (reg & 0xf0));
5169a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5178d5d45fbSJean Delvare 	return count;
5188d5d45fbSJean Delvare }
5198d5d45fbSJean Delvare 
520c801082dSJean Delvare static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
521c801082dSJean Delvare static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
522c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_fan1_min_pwm, S_IRUGO | S_IWUSR,
523c801082dSJean Delvare 		show_pwm, set_pwm, 0);
524c801082dSJean Delvare static SENSOR_DEVICE_ATTR(auto_fan2_min_pwm, S_IRUGO | S_IWUSR,
525c801082dSJean Delvare 		show_pwm, set_pwm, 1);
5268d5d45fbSJean Delvare 
5278d5d45fbSJean Delvare /* Fans */
5288d5d45fbSJean Delvare 
5298d5d45fbSJean Delvare /*
5308d5d45fbSJean Delvare  * That function checks the cases where the fan reading is not
5318d5d45fbSJean Delvare  * relevant.  It is used to provide 0 as fan reading when the fan is
5328d5d45fbSJean Delvare  * not supposed to run
5338d5d45fbSJean Delvare  */
5348d5d45fbSJean Delvare static int trust_fan_readings(struct adm1031_data *data, int chan)
5358d5d45fbSJean Delvare {
5368d5d45fbSJean Delvare 	int res = 0;
5378d5d45fbSJean Delvare 
5388d5d45fbSJean Delvare 	if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
5398d5d45fbSJean Delvare 		switch (data->conf1 & 0x60) {
5401c720093SGuenter Roeck 		case 0x00:
5411c720093SGuenter Roeck 			/*
5421c720093SGuenter Roeck 			 * remote temp1 controls fan1,
5431c720093SGuenter Roeck 			 * remote temp2 controls fan2
5441c720093SGuenter Roeck 			 */
5458d5d45fbSJean Delvare 			res = data->temp[chan+1] >=
5468d5d45fbSJean Delvare 			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
5478d5d45fbSJean Delvare 			break;
5488d5d45fbSJean Delvare 		case 0x20:	/* remote temp1 controls both fans */
5498d5d45fbSJean Delvare 			res =
5508d5d45fbSJean Delvare 			    data->temp[1] >=
5518d5d45fbSJean Delvare 			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]);
5528d5d45fbSJean Delvare 			break;
5538d5d45fbSJean Delvare 		case 0x40:	/* remote temp2 controls both fans */
5548d5d45fbSJean Delvare 			res =
5558d5d45fbSJean Delvare 			    data->temp[2] >=
5568d5d45fbSJean Delvare 			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]);
5578d5d45fbSJean Delvare 			break;
5588d5d45fbSJean Delvare 		case 0x60:	/* max controls both fans */
5598d5d45fbSJean Delvare 			res =
5608d5d45fbSJean Delvare 			    data->temp[0] >=
5618d5d45fbSJean Delvare 			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0])
5628d5d45fbSJean Delvare 			    || data->temp[1] >=
5638d5d45fbSJean Delvare 			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1])
5648d5d45fbSJean Delvare 			    || (data->chip_type == adm1031
5658d5d45fbSJean Delvare 				&& data->temp[2] >=
5668d5d45fbSJean Delvare 				AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]));
5678d5d45fbSJean Delvare 			break;
5688d5d45fbSJean Delvare 		}
5698d5d45fbSJean Delvare 	} else {
5708d5d45fbSJean Delvare 		res = data->pwm[chan] > 0;
5718d5d45fbSJean Delvare 	}
5728d5d45fbSJean Delvare 	return res;
5738d5d45fbSJean Delvare }
5748d5d45fbSJean Delvare 
5758d5d45fbSJean Delvare 
576c801082dSJean Delvare static ssize_t show_fan(struct device *dev,
577c801082dSJean Delvare 			struct device_attribute *attr, char *buf)
5788d5d45fbSJean Delvare {
579c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
5808d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
5818d5d45fbSJean Delvare 	int value;
5828d5d45fbSJean Delvare 
5838d5d45fbSJean Delvare 	value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr],
5848d5d45fbSJean Delvare 				 FAN_DIV_FROM_REG(data->fan_div[nr])) : 0;
5858d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", value);
5868d5d45fbSJean Delvare }
5878d5d45fbSJean Delvare 
588c801082dSJean Delvare static ssize_t show_fan_div(struct device *dev,
589c801082dSJean Delvare 			    struct device_attribute *attr, char *buf)
5908d5d45fbSJean Delvare {
591c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
5928d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
5938d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr]));
5948d5d45fbSJean Delvare }
595c801082dSJean Delvare static ssize_t show_fan_min(struct device *dev,
596c801082dSJean Delvare 			    struct device_attribute *attr, char *buf)
5978d5d45fbSJean Delvare {
598c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
5998d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
6008d5d45fbSJean Delvare 	return sprintf(buf, "%d\n",
6018d5d45fbSJean Delvare 		       FAN_FROM_REG(data->fan_min[nr],
6028d5d45fbSJean Delvare 				    FAN_DIV_FROM_REG(data->fan_div[nr])));
6038d5d45fbSJean Delvare }
604c801082dSJean Delvare static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
605c801082dSJean Delvare 			   const char *buf, size_t count)
6068d5d45fbSJean Delvare {
607b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
608b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
609c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
6101c720093SGuenter Roeck 	long val;
6111c720093SGuenter Roeck 	int ret;
6121c720093SGuenter Roeck 
6131c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
6141c720093SGuenter Roeck 	if (ret)
6151c720093SGuenter Roeck 		return ret;
6168d5d45fbSJean Delvare 
6179a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6188d5d45fbSJean Delvare 	if (val) {
6198d5d45fbSJean Delvare 		data->fan_min[nr] =
6208d5d45fbSJean Delvare 			FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
6218d5d45fbSJean Delvare 	} else {
6228d5d45fbSJean Delvare 		data->fan_min[nr] = 0xff;
6238d5d45fbSJean Delvare 	}
6248d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]);
6259a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6268d5d45fbSJean Delvare 	return count;
6278d5d45fbSJean Delvare }
628c801082dSJean Delvare static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
629c801082dSJean Delvare 			   const char *buf, size_t count)
6308d5d45fbSJean Delvare {
631b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
632b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
633c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
6341c720093SGuenter Roeck 	long val;
6358d5d45fbSJean Delvare 	u8 tmp;
6368d5d45fbSJean Delvare 	int old_div;
6378d5d45fbSJean Delvare 	int new_min;
6381c720093SGuenter Roeck 	int ret;
6391c720093SGuenter Roeck 
6401c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
6411c720093SGuenter Roeck 	if (ret)
6421c720093SGuenter Roeck 		return ret;
6438d5d45fbSJean Delvare 
6448d5d45fbSJean Delvare 	tmp = val == 8 ? 0xc0 :
6458d5d45fbSJean Delvare 	      val == 4 ? 0x80 :
6468d5d45fbSJean Delvare 	      val == 2 ? 0x40 :
6478d5d45fbSJean Delvare 	      val == 1 ? 0x00 :
6488d5d45fbSJean Delvare 	      0xff;
6498d5d45fbSJean Delvare 	if (tmp == 0xff)
6508d5d45fbSJean Delvare 		return -EINVAL;
6518d5d45fbSJean Delvare 
6529a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
65338a1f0e9SJean Delvare 	/* Get fresh readings */
65438a1f0e9SJean Delvare 	data->fan_div[nr] = adm1031_read_value(client,
65538a1f0e9SJean Delvare 					       ADM1031_REG_FAN_DIV(nr));
65638a1f0e9SJean Delvare 	data->fan_min[nr] = adm1031_read_value(client,
65738a1f0e9SJean Delvare 					       ADM1031_REG_FAN_MIN(nr));
65838a1f0e9SJean Delvare 
65938a1f0e9SJean Delvare 	/* Write the new clock divider and fan min */
6608d5d45fbSJean Delvare 	old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
6616d6006b8SJean Delvare 	data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]);
6626d6006b8SJean Delvare 	new_min = data->fan_min[nr] * old_div / val;
6638d5d45fbSJean Delvare 	data->fan_min[nr] = new_min > 0xff ? 0xff : new_min;
6648d5d45fbSJean Delvare 
6658d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr),
6668d5d45fbSJean Delvare 			    data->fan_div[nr]);
6678d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr),
6688d5d45fbSJean Delvare 			    data->fan_min[nr]);
66938a1f0e9SJean Delvare 
67038a1f0e9SJean Delvare 	/* Invalidate the cache: fan speed is no longer valid */
67138a1f0e9SJean Delvare 	data->valid = 0;
6729a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6738d5d45fbSJean Delvare 	return count;
6748d5d45fbSJean Delvare }
6758d5d45fbSJean Delvare 
6768d5d45fbSJean Delvare #define fan_offset(offset)						\
677c801082dSJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
678c801082dSJean Delvare 		show_fan, NULL, offset - 1);				\
679c801082dSJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
680c801082dSJean Delvare 		show_fan_min, set_fan_min, offset - 1);			\
681c801082dSJean Delvare static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
682c801082dSJean Delvare 		show_fan_div, set_fan_div, offset - 1)
6838d5d45fbSJean Delvare 
6848d5d45fbSJean Delvare fan_offset(1);
6858d5d45fbSJean Delvare fan_offset(2);
6868d5d45fbSJean Delvare 
6878d5d45fbSJean Delvare 
6888d5d45fbSJean Delvare /* Temps */
689c801082dSJean Delvare static ssize_t show_temp(struct device *dev,
690c801082dSJean Delvare 			 struct device_attribute *attr, char *buf)
6918d5d45fbSJean Delvare {
692c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
6938d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
6948d5d45fbSJean Delvare 	int ext;
6958d5d45fbSJean Delvare 	ext = nr == 0 ?
6968d5d45fbSJean Delvare 	    ((data->ext_temp[nr] >> 6) & 0x3) * 2 :
6978d5d45fbSJean Delvare 	    (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7));
6988d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext));
6998d5d45fbSJean Delvare }
70049dc9efeSIra Snyder static ssize_t show_temp_offset(struct device *dev,
70149dc9efeSIra Snyder 				struct device_attribute *attr, char *buf)
70249dc9efeSIra Snyder {
70349dc9efeSIra Snyder 	int nr = to_sensor_dev_attr(attr)->index;
70449dc9efeSIra Snyder 	struct adm1031_data *data = adm1031_update_device(dev);
70549dc9efeSIra Snyder 	return sprintf(buf, "%d\n",
70649dc9efeSIra Snyder 		       TEMP_OFFSET_FROM_REG(data->temp_offset[nr]));
70749dc9efeSIra Snyder }
708c801082dSJean Delvare static ssize_t show_temp_min(struct device *dev,
709c801082dSJean Delvare 			     struct device_attribute *attr, char *buf)
7108d5d45fbSJean Delvare {
711c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
7128d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
7138d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
7148d5d45fbSJean Delvare }
715c801082dSJean Delvare static ssize_t show_temp_max(struct device *dev,
716c801082dSJean Delvare 			     struct device_attribute *attr, char *buf)
7178d5d45fbSJean Delvare {
718c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
7198d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
7208d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
7218d5d45fbSJean Delvare }
722c801082dSJean Delvare static ssize_t show_temp_crit(struct device *dev,
723c801082dSJean Delvare 			      struct device_attribute *attr, char *buf)
7248d5d45fbSJean Delvare {
725c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
7268d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
7278d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
7288d5d45fbSJean Delvare }
72949dc9efeSIra Snyder static ssize_t set_temp_offset(struct device *dev,
73049dc9efeSIra Snyder 			       struct device_attribute *attr, const char *buf,
73149dc9efeSIra Snyder 			       size_t count)
73249dc9efeSIra Snyder {
733b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
734b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
73549dc9efeSIra Snyder 	int nr = to_sensor_dev_attr(attr)->index;
7361c720093SGuenter Roeck 	long val;
7371c720093SGuenter Roeck 	int ret;
73849dc9efeSIra Snyder 
7391c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
7401c720093SGuenter Roeck 	if (ret)
7411c720093SGuenter Roeck 		return ret;
7421c720093SGuenter Roeck 
7432a844c14SGuenter Roeck 	val = clamp_val(val, -15000, 15000);
74449dc9efeSIra Snyder 	mutex_lock(&data->update_lock);
74549dc9efeSIra Snyder 	data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
74649dc9efeSIra Snyder 	adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
74749dc9efeSIra Snyder 			    data->temp_offset[nr]);
74849dc9efeSIra Snyder 	mutex_unlock(&data->update_lock);
74949dc9efeSIra Snyder 	return count;
75049dc9efeSIra Snyder }
751c801082dSJean Delvare static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
752c801082dSJean Delvare 			    const char *buf, size_t count)
7538d5d45fbSJean Delvare {
754b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
755b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
756c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
7571c720093SGuenter Roeck 	long val;
7581c720093SGuenter Roeck 	int ret;
7598d5d45fbSJean Delvare 
7601c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
7611c720093SGuenter Roeck 	if (ret)
7621c720093SGuenter Roeck 		return ret;
7631c720093SGuenter Roeck 
764145e74a4SGuenter Roeck 	val = clamp_val(val, -55000, 127000);
7659a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7668d5d45fbSJean Delvare 	data->temp_min[nr] = TEMP_TO_REG(val);
7678d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
7688d5d45fbSJean Delvare 			    data->temp_min[nr]);
7699a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7708d5d45fbSJean Delvare 	return count;
7718d5d45fbSJean Delvare }
772c801082dSJean Delvare static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
773c801082dSJean Delvare 			    const char *buf, 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_max[nr] = TEMP_TO_REG(val);
7888d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
7898d5d45fbSJean Delvare 			    data->temp_max[nr]);
7909a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7918d5d45fbSJean Delvare 	return count;
7928d5d45fbSJean Delvare }
793c801082dSJean Delvare static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
794c801082dSJean Delvare 			     const char *buf, size_t count)
7958d5d45fbSJean Delvare {
796b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
797b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
798c801082dSJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
7991c720093SGuenter Roeck 	long val;
8001c720093SGuenter Roeck 	int ret;
8018d5d45fbSJean Delvare 
8021c720093SGuenter Roeck 	ret = kstrtol(buf, 10, &val);
8031c720093SGuenter Roeck 	if (ret)
8041c720093SGuenter Roeck 		return ret;
8051c720093SGuenter Roeck 
806145e74a4SGuenter Roeck 	val = clamp_val(val, -55000, 127000);
8079a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
8088d5d45fbSJean Delvare 	data->temp_crit[nr] = TEMP_TO_REG(val);
8098d5d45fbSJean Delvare 	adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
8108d5d45fbSJean Delvare 			    data->temp_crit[nr]);
8119a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
8128d5d45fbSJean Delvare 	return count;
8138d5d45fbSJean Delvare }
8148d5d45fbSJean Delvare 
8158d5d45fbSJean Delvare #define temp_reg(offset)						\
816c801082dSJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
817c801082dSJean Delvare 		show_temp, NULL, offset - 1);				\
81849dc9efeSIra Snyder static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR,	\
81949dc9efeSIra Snyder 		show_temp_offset, set_temp_offset, offset - 1);		\
820c801082dSJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
821c801082dSJean Delvare 		show_temp_min, set_temp_min, offset - 1);		\
822c801082dSJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
823c801082dSJean Delvare 		show_temp_max, set_temp_max, offset - 1);		\
824c801082dSJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR,	\
825c801082dSJean Delvare 		show_temp_crit, set_temp_crit, offset - 1)
8268d5d45fbSJean Delvare 
8278d5d45fbSJean Delvare temp_reg(1);
8288d5d45fbSJean Delvare temp_reg(2);
8298d5d45fbSJean Delvare temp_reg(3);
8308d5d45fbSJean Delvare 
8318d5d45fbSJean Delvare /* Alarms */
832*bfb6b173SJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
8331c720093SGuenter Roeck 			   char *buf)
8348d5d45fbSJean Delvare {
8358d5d45fbSJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
8368d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->alarm);
8378d5d45fbSJean Delvare }
8388d5d45fbSJean Delvare 
839*bfb6b173SJulia Lawall static DEVICE_ATTR_RO(alarms);
8408d5d45fbSJean Delvare 
841050ab878SJean Delvare static ssize_t show_alarm(struct device *dev,
842050ab878SJean Delvare 			  struct device_attribute *attr, char *buf)
843050ab878SJean Delvare {
844050ab878SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
845050ab878SJean Delvare 	struct adm1031_data *data = adm1031_update_device(dev);
846050ab878SJean Delvare 	return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1);
847050ab878SJean Delvare }
848050ab878SJean Delvare 
849050ab878SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
850050ab878SJean Delvare static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_alarm, NULL, 1);
851050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 2);
852050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
853050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 4);
854050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 5);
855050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
856050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 7);
857050ab878SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 8);
858050ab878SJean Delvare static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_alarm, NULL, 9);
859050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 10);
860050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
861050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
862050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
863050ab878SJean Delvare static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
8648d5d45fbSJean Delvare 
865a51b9944SGuenter Roeck /* Update Interval */
866a51b9944SGuenter Roeck static const unsigned int update_intervals[] = {
86787c33daaSJean Delvare 	16000, 8000, 4000, 2000, 1000, 500, 250, 125,
86887c33daaSJean Delvare };
86987c33daaSJean Delvare 
870*bfb6b173SJulia Lawall static ssize_t update_interval_show(struct device *dev,
87187c33daaSJean Delvare 				    struct device_attribute *attr, char *buf)
87287c33daaSJean Delvare {
873b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
87487c33daaSJean Delvare 
875a51b9944SGuenter Roeck 	return sprintf(buf, "%u\n", data->update_interval);
87687c33daaSJean Delvare }
87787c33daaSJean Delvare 
878*bfb6b173SJulia Lawall static ssize_t update_interval_store(struct device *dev,
87987c33daaSJean Delvare 				     struct device_attribute *attr,
88087c33daaSJean Delvare 				     const char *buf, size_t count)
88187c33daaSJean Delvare {
882b060f3c4SAxel Lin 	struct adm1031_data *data = dev_get_drvdata(dev);
883b060f3c4SAxel Lin 	struct i2c_client *client = data->client;
88487c33daaSJean Delvare 	unsigned long val;
88587c33daaSJean Delvare 	int i, err;
88687c33daaSJean Delvare 	u8 reg;
88787c33daaSJean Delvare 
888179c4fdbSFrans Meulenbroeks 	err = kstrtoul(buf, 10, &val);
88987c33daaSJean Delvare 	if (err)
89087c33daaSJean Delvare 		return err;
89187c33daaSJean Delvare 
892a51b9944SGuenter Roeck 	/*
893a51b9944SGuenter Roeck 	 * Find the nearest update interval from the table.
894a51b9944SGuenter Roeck 	 * Use it to determine the matching update rate.
895a51b9944SGuenter Roeck 	 */
896a51b9944SGuenter Roeck 	for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) {
897a51b9944SGuenter Roeck 		if (val >= update_intervals[i])
89887c33daaSJean Delvare 			break;
89987c33daaSJean Delvare 	}
900a51b9944SGuenter Roeck 	/* if not found, we point to the last entry (lowest update interval) */
90187c33daaSJean Delvare 
90287c33daaSJean Delvare 	/* set the new update rate while preserving other settings */
90387c33daaSJean Delvare 	reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
90487c33daaSJean Delvare 	reg &= ~ADM1031_UPDATE_RATE_MASK;
90587c33daaSJean Delvare 	reg |= i << ADM1031_UPDATE_RATE_SHIFT;
90687c33daaSJean Delvare 	adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
90787c33daaSJean Delvare 
90887c33daaSJean Delvare 	mutex_lock(&data->update_lock);
909a51b9944SGuenter Roeck 	data->update_interval = update_intervals[i];
91087c33daaSJean Delvare 	mutex_unlock(&data->update_lock);
91187c33daaSJean Delvare 
91287c33daaSJean Delvare 	return count;
91387c33daaSJean Delvare }
91487c33daaSJean Delvare 
915*bfb6b173SJulia Lawall static DEVICE_ATTR_RW(update_interval);
91687c33daaSJean Delvare 
917681c6f7aSMark M. Hoffman static struct attribute *adm1031_attributes[] = {
918c801082dSJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
919c801082dSJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
920c801082dSJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
921050ab878SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
922050ab878SJean Delvare 	&sensor_dev_attr_fan1_fault.dev_attr.attr,
923c801082dSJean Delvare 	&sensor_dev_attr_pwm1.dev_attr.attr,
924c801082dSJean Delvare 	&sensor_dev_attr_auto_fan1_channel.dev_attr.attr,
925c801082dSJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
92649dc9efeSIra Snyder 	&sensor_dev_attr_temp1_offset.dev_attr.attr,
927c801082dSJean Delvare 	&sensor_dev_attr_temp1_min.dev_attr.attr,
928050ab878SJean Delvare 	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
929c801082dSJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
930050ab878SJean Delvare 	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
931c801082dSJean Delvare 	&sensor_dev_attr_temp1_crit.dev_attr.attr,
932050ab878SJean Delvare 	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
933c801082dSJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
93449dc9efeSIra Snyder 	&sensor_dev_attr_temp2_offset.dev_attr.attr,
935c801082dSJean Delvare 	&sensor_dev_attr_temp2_min.dev_attr.attr,
936050ab878SJean Delvare 	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
937c801082dSJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
938050ab878SJean Delvare 	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
939c801082dSJean Delvare 	&sensor_dev_attr_temp2_crit.dev_attr.attr,
940050ab878SJean Delvare 	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
941050ab878SJean Delvare 	&sensor_dev_attr_temp2_fault.dev_attr.attr,
942681c6f7aSMark M. Hoffman 
943c801082dSJean Delvare 	&sensor_dev_attr_auto_temp1_off.dev_attr.attr,
944c801082dSJean Delvare 	&sensor_dev_attr_auto_temp1_min.dev_attr.attr,
945c801082dSJean Delvare 	&sensor_dev_attr_auto_temp1_max.dev_attr.attr,
946681c6f7aSMark M. Hoffman 
947c801082dSJean Delvare 	&sensor_dev_attr_auto_temp2_off.dev_attr.attr,
948c801082dSJean Delvare 	&sensor_dev_attr_auto_temp2_min.dev_attr.attr,
949c801082dSJean Delvare 	&sensor_dev_attr_auto_temp2_max.dev_attr.attr,
950681c6f7aSMark M. Hoffman 
951c801082dSJean Delvare 	&sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
952681c6f7aSMark M. Hoffman 
953a51b9944SGuenter Roeck 	&dev_attr_update_interval.attr,
954681c6f7aSMark M. Hoffman 	&dev_attr_alarms.attr,
955681c6f7aSMark M. Hoffman 
956681c6f7aSMark M. Hoffman 	NULL
957681c6f7aSMark M. Hoffman };
958681c6f7aSMark M. Hoffman 
959681c6f7aSMark M. Hoffman static const struct attribute_group adm1031_group = {
960681c6f7aSMark M. Hoffman 	.attrs = adm1031_attributes,
961681c6f7aSMark M. Hoffman };
962681c6f7aSMark M. Hoffman 
963681c6f7aSMark M. Hoffman static struct attribute *adm1031_attributes_opt[] = {
964c801082dSJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
965c801082dSJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
966c801082dSJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
967050ab878SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
968050ab878SJean Delvare 	&sensor_dev_attr_fan2_fault.dev_attr.attr,
969c801082dSJean Delvare 	&sensor_dev_attr_pwm2.dev_attr.attr,
970c801082dSJean Delvare 	&sensor_dev_attr_auto_fan2_channel.dev_attr.attr,
971c801082dSJean Delvare 	&sensor_dev_attr_temp3_input.dev_attr.attr,
97249dc9efeSIra Snyder 	&sensor_dev_attr_temp3_offset.dev_attr.attr,
973c801082dSJean Delvare 	&sensor_dev_attr_temp3_min.dev_attr.attr,
974050ab878SJean Delvare 	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
975c801082dSJean Delvare 	&sensor_dev_attr_temp3_max.dev_attr.attr,
976050ab878SJean Delvare 	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
977c801082dSJean Delvare 	&sensor_dev_attr_temp3_crit.dev_attr.attr,
978050ab878SJean Delvare 	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
979050ab878SJean Delvare 	&sensor_dev_attr_temp3_fault.dev_attr.attr,
980c801082dSJean Delvare 	&sensor_dev_attr_auto_temp3_off.dev_attr.attr,
981c801082dSJean Delvare 	&sensor_dev_attr_auto_temp3_min.dev_attr.attr,
982c801082dSJean Delvare 	&sensor_dev_attr_auto_temp3_max.dev_attr.attr,
983c801082dSJean Delvare 	&sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr,
984681c6f7aSMark M. Hoffman 	NULL
985681c6f7aSMark M. Hoffman };
986681c6f7aSMark M. Hoffman 
987681c6f7aSMark M. Hoffman static const struct attribute_group adm1031_group_opt = {
988681c6f7aSMark M. Hoffman 	.attrs = adm1031_attributes_opt,
989681c6f7aSMark M. Hoffman };
990681c6f7aSMark M. Hoffman 
991af200f88SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */
992310ec792SJean Delvare static int adm1031_detect(struct i2c_client *client,
993af200f88SJean Delvare 			  struct i2c_board_info *info)
9948d5d45fbSJean Delvare {
995af200f88SJean Delvare 	struct i2c_adapter *adapter = client->adapter;
99652df6440SJean Delvare 	const char *name;
99752df6440SJean Delvare 	int id, co;
9988d5d45fbSJean Delvare 
9998d5d45fbSJean Delvare 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1000af200f88SJean Delvare 		return -ENODEV;
10018d5d45fbSJean Delvare 
10026d6006b8SJean Delvare 	id = i2c_smbus_read_byte_data(client, 0x3d);
10036d6006b8SJean Delvare 	co = i2c_smbus_read_byte_data(client, 0x3e);
10048d5d45fbSJean Delvare 
10058d5d45fbSJean Delvare 	if (!((id == 0x31 || id == 0x30) && co == 0x41))
1006af200f88SJean Delvare 		return -ENODEV;
100752df6440SJean Delvare 	name = (id == 0x30) ? "adm1030" : "adm1031";
10088d5d45fbSJean Delvare 
1009af200f88SJean Delvare 	strlcpy(info->type, name, I2C_NAME_SIZE);
10108d5d45fbSJean Delvare 
1011af200f88SJean Delvare 	return 0;
1012af200f88SJean Delvare }
1013af200f88SJean Delvare 
1014278ee1c8SAxel Lin static void adm1031_init_client(struct i2c_client *client)
1015278ee1c8SAxel Lin {
1016278ee1c8SAxel Lin 	unsigned int read_val;
1017278ee1c8SAxel Lin 	unsigned int mask;
1018278ee1c8SAxel Lin 	int i;
1019278ee1c8SAxel Lin 	struct adm1031_data *data = i2c_get_clientdata(client);
1020278ee1c8SAxel Lin 
1021278ee1c8SAxel Lin 	mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
1022278ee1c8SAxel Lin 	if (data->chip_type == adm1031) {
1023278ee1c8SAxel Lin 		mask |= (ADM1031_CONF2_PWM2_ENABLE |
1024278ee1c8SAxel Lin 			ADM1031_CONF2_TACH2_ENABLE);
1025278ee1c8SAxel Lin 	}
1026278ee1c8SAxel Lin 	/* Initialize the ADM1031 chip (enables fan speed reading ) */
1027278ee1c8SAxel Lin 	read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
1028278ee1c8SAxel Lin 	if ((read_val | mask) != read_val)
1029278ee1c8SAxel Lin 		adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
1030278ee1c8SAxel Lin 
1031278ee1c8SAxel Lin 	read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
1032278ee1c8SAxel Lin 	if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
1033278ee1c8SAxel Lin 		adm1031_write_value(client, ADM1031_REG_CONF1,
1034278ee1c8SAxel Lin 				    read_val | ADM1031_CONF1_MONITOR_ENABLE);
1035278ee1c8SAxel Lin 	}
1036278ee1c8SAxel Lin 
1037278ee1c8SAxel Lin 	/* Read the chip's update rate */
1038278ee1c8SAxel Lin 	mask = ADM1031_UPDATE_RATE_MASK;
1039278ee1c8SAxel Lin 	read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
1040278ee1c8SAxel Lin 	i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
1041278ee1c8SAxel Lin 	/* Save it as update interval */
1042278ee1c8SAxel Lin 	data->update_interval = update_intervals[i];
1043278ee1c8SAxel Lin }
1044278ee1c8SAxel Lin 
1045af200f88SJean Delvare static int adm1031_probe(struct i2c_client *client,
1046af200f88SJean Delvare 			 const struct i2c_device_id *id)
1047af200f88SJean Delvare {
1048b060f3c4SAxel Lin 	struct device *dev = &client->dev;
1049b060f3c4SAxel Lin 	struct device *hwmon_dev;
1050af200f88SJean Delvare 	struct adm1031_data *data;
1051af200f88SJean Delvare 
1052b060f3c4SAxel Lin 	data = devm_kzalloc(dev, sizeof(struct adm1031_data), GFP_KERNEL);
1053dc2fd663SGuenter Roeck 	if (!data)
1054dc2fd663SGuenter Roeck 		return -ENOMEM;
1055af200f88SJean Delvare 
1056af200f88SJean Delvare 	i2c_set_clientdata(client, data);
1057b060f3c4SAxel Lin 	data->client = client;
1058af200f88SJean Delvare 	data->chip_type = id->driver_data;
10599a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
10608d5d45fbSJean Delvare 
1061af200f88SJean Delvare 	if (data->chip_type == adm1030)
1062af200f88SJean Delvare 		data->chan_select_table = &auto_channel_select_table_adm1030;
1063af200f88SJean Delvare 	else
1064af200f88SJean Delvare 		data->chan_select_table = &auto_channel_select_table_adm1031;
10658d5d45fbSJean Delvare 
10668d5d45fbSJean Delvare 	/* Initialize the ADM1031 chip */
10676d6006b8SJean Delvare 	adm1031_init_client(client);
10688d5d45fbSJean Delvare 
1069b060f3c4SAxel Lin 	/* sysfs hooks */
1070b060f3c4SAxel Lin 	data->groups[0] = &adm1031_group;
1071b060f3c4SAxel Lin 	if (data->chip_type == adm1031)
1072b060f3c4SAxel Lin 		data->groups[1] = &adm1031_group_opt;
1073681c6f7aSMark M. Hoffman 
1074b060f3c4SAxel Lin 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
1075b060f3c4SAxel Lin 							   data, data->groups);
1076b060f3c4SAxel Lin 	return PTR_ERR_OR_ZERO(hwmon_dev);
10778d5d45fbSJean Delvare }
10788d5d45fbSJean Delvare 
1079278ee1c8SAxel Lin static const struct i2c_device_id adm1031_id[] = {
1080278ee1c8SAxel Lin 	{ "adm1030", adm1030 },
1081278ee1c8SAxel Lin 	{ "adm1031", adm1031 },
1082278ee1c8SAxel Lin 	{ }
1083278ee1c8SAxel Lin };
1084278ee1c8SAxel Lin MODULE_DEVICE_TABLE(i2c, adm1031_id);
10858d5d45fbSJean Delvare 
1086278ee1c8SAxel Lin static struct i2c_driver adm1031_driver = {
1087278ee1c8SAxel Lin 	.class		= I2C_CLASS_HWMON,
1088278ee1c8SAxel Lin 	.driver = {
1089278ee1c8SAxel Lin 		.name = "adm1031",
1090278ee1c8SAxel Lin 	},
1091278ee1c8SAxel Lin 	.probe		= adm1031_probe,
1092278ee1c8SAxel Lin 	.id_table	= adm1031_id,
1093278ee1c8SAxel Lin 	.detect		= adm1031_detect,
1094278ee1c8SAxel Lin 	.address_list	= normal_i2c,
1095278ee1c8SAxel Lin };
10968d5d45fbSJean Delvare 
1097f0967eeaSAxel Lin module_i2c_driver(adm1031_driver);
10988d5d45fbSJean Delvare 
10998d5d45fbSJean Delvare MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");
11008d5d45fbSJean Delvare MODULE_DESCRIPTION("ADM1031/ADM1030 driver");
11018d5d45fbSJean Delvare MODULE_LICENSE("GPL");
1102