xref: /linux/drivers/hwmon/adt7470.c (revision 6f9703d0be16f694ce24dde1ce1fc4a4e4e5ed55)
1*6f9703d0SDarrick J. Wong /*
2*6f9703d0SDarrick J. Wong  * A hwmon driver for the Analog Devices ADT7470
3*6f9703d0SDarrick J. Wong  * Copyright (C) 2007 IBM
4*6f9703d0SDarrick J. Wong  *
5*6f9703d0SDarrick J. Wong  * Author: Darrick J. Wong <djwong@us.ibm.com>
6*6f9703d0SDarrick J. Wong  *
7*6f9703d0SDarrick J. Wong  * This program is free software; you can redistribute it and/or modify
8*6f9703d0SDarrick J. Wong  * it under the terms of the GNU General Public License as published by
9*6f9703d0SDarrick J. Wong  * the Free Software Foundation; either version 2 of the License, or
10*6f9703d0SDarrick J. Wong  * (at your option) any later version.
11*6f9703d0SDarrick J. Wong  *
12*6f9703d0SDarrick J. Wong  * This program is distributed in the hope that it will be useful,
13*6f9703d0SDarrick J. Wong  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*6f9703d0SDarrick J. Wong  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*6f9703d0SDarrick J. Wong  * GNU General Public License for more details.
16*6f9703d0SDarrick J. Wong  *
17*6f9703d0SDarrick J. Wong  * You should have received a copy of the GNU General Public License
18*6f9703d0SDarrick J. Wong  * along with this program; if not, write to the Free Software
19*6f9703d0SDarrick J. Wong  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20*6f9703d0SDarrick J. Wong  */
21*6f9703d0SDarrick J. Wong 
22*6f9703d0SDarrick J. Wong #include <linux/module.h>
23*6f9703d0SDarrick J. Wong #include <linux/jiffies.h>
24*6f9703d0SDarrick J. Wong #include <linux/i2c.h>
25*6f9703d0SDarrick J. Wong #include <linux/hwmon.h>
26*6f9703d0SDarrick J. Wong #include <linux/hwmon-sysfs.h>
27*6f9703d0SDarrick J. Wong #include <linux/err.h>
28*6f9703d0SDarrick J. Wong #include <linux/mutex.h>
29*6f9703d0SDarrick J. Wong #include <linux/delay.h>
30*6f9703d0SDarrick J. Wong #include <linux/log2.h>
31*6f9703d0SDarrick J. Wong 
32*6f9703d0SDarrick J. Wong /* Addresses to scan */
33*6f9703d0SDarrick J. Wong static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
34*6f9703d0SDarrick J. Wong 
35*6f9703d0SDarrick J. Wong /* Insmod parameters */
36*6f9703d0SDarrick J. Wong I2C_CLIENT_INSMOD_1(adt7470);
37*6f9703d0SDarrick J. Wong 
38*6f9703d0SDarrick J. Wong /* ADT7470 registers */
39*6f9703d0SDarrick J. Wong #define ADT7470_REG_BASE_ADDR			0x20
40*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_BASE_ADDR		0x20
41*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_MAX_ADDR		0x29
42*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_BASE_ADDR		0x2A
43*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX_ADDR		0x31
44*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_BASE_ADDR		0x32
45*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX_ADDR		0x35
46*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX_BASE_ADDR		0x38
47*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX_MAX_ADDR		0x3B
48*6f9703d0SDarrick J. Wong #define ADT7470_REG_CFG				0x40
49*6f9703d0SDarrick J. Wong #define		ADT7470_FSPD_MASK		0x04
50*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM1			0x41
51*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM2			0x42
52*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_LIMITS_BASE_ADDR	0x44
53*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_LIMITS_MAX_ADDR	0x57
54*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MIN_BASE_ADDR		0x58
55*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MIN_MAX_ADDR		0x5F
56*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX_BASE_ADDR		0x60
57*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX_MAX_ADDR		0x67
58*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_CFG_BASE_ADDR		0x68
59*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM12_CFG			0x68
60*6f9703d0SDarrick J. Wong #define		ADT7470_PWM2_AUTO_MASK		0x40
61*6f9703d0SDarrick J. Wong #define		ADT7470_PWM1_AUTO_MASK		0x80
62*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM34_CFG			0x69
63*6f9703d0SDarrick J. Wong #define		ADT7470_PWM3_AUTO_MASK		0x40
64*6f9703d0SDarrick J. Wong #define		ADT7470_PWM4_AUTO_MASK		0x80
65*6f9703d0SDarrick J. Wong #define	ADT7470_REG_PWM_MIN_BASE_ADDR		0x6A
66*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MIN_MAX_ADDR		0x6D
67*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR	0x6E
68*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR	0x71
69*6f9703d0SDarrick J. Wong #define ADT7470_REG_ACOUSTICS12			0x75
70*6f9703d0SDarrick J. Wong #define ADT7470_REG_ACOUSTICS34			0x76
71*6f9703d0SDarrick J. Wong #define ADT7470_REG_DEVICE			0x3D
72*6f9703d0SDarrick J. Wong #define ADT7470_REG_VENDOR			0x3E
73*6f9703d0SDarrick J. Wong #define ADT7470_REG_REVISION			0x3F
74*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM1_MASK			0x72
75*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM2_MASK			0x73
76*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR	0x7C
77*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR	0x7D
78*6f9703d0SDarrick J. Wong #define ADT7470_REG_MAX_ADDR			0x81
79*6f9703d0SDarrick J. Wong 
80*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_COUNT	10
81*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_REG(x)	(ADT7470_REG_TEMP_BASE_ADDR + (x))
82*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
83*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \
84*6f9703d0SDarrick J. Wong 				((x) * 2) + 1)
85*6f9703d0SDarrick J. Wong 
86*6f9703d0SDarrick J. Wong #define ADT7470_FAN_COUNT	4
87*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN(x)	(ADT7470_REG_FAN_BASE_ADDR + ((x) * 2))
88*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MIN(x)	(ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
89*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX(x)	(ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2))
90*6f9703d0SDarrick J. Wong 
91*6f9703d0SDarrick J. Wong #define ADT7470_PWM_COUNT	4
92*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM(x)	(ADT7470_REG_PWM_BASE_ADDR + (x))
93*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX(x)	(ADT7470_REG_PWM_MAX_BASE_ADDR + (x))
94*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MIN(x)	(ADT7470_REG_PWM_MIN_BASE_ADDR + (x))
95*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_TMIN(x)	(ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
96*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_CFG(x)	(ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2))
97*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_AUTO_TEMP(x)	(ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
98*6f9703d0SDarrick J. Wong 					((x) / 2))
99*6f9703d0SDarrick J. Wong 
100*6f9703d0SDarrick J. Wong #define ADT7470_VENDOR		0x41
101*6f9703d0SDarrick J. Wong #define ADT7470_DEVICE		0x70
102*6f9703d0SDarrick J. Wong /* datasheet only mentions a revision 2 */
103*6f9703d0SDarrick J. Wong #define ADT7470_REVISION	0x02
104*6f9703d0SDarrick J. Wong 
105*6f9703d0SDarrick J. Wong /* "all temps" according to hwmon sysfs interface spec */
106*6f9703d0SDarrick J. Wong #define ADT7470_PWM_ALL_TEMPS	0x3FF
107*6f9703d0SDarrick J. Wong 
108*6f9703d0SDarrick J. Wong /* How often do we reread sensors values? (In jiffies) */
109*6f9703d0SDarrick J. Wong #define SENSOR_REFRESH_INTERVAL	(5 * HZ)
110*6f9703d0SDarrick J. Wong 
111*6f9703d0SDarrick J. Wong /* How often do we reread sensor limit values? (In jiffies) */
112*6f9703d0SDarrick J. Wong #define LIMIT_REFRESH_INTERVAL	(60 * HZ)
113*6f9703d0SDarrick J. Wong 
114*6f9703d0SDarrick J. Wong /* sleep 1s while gathering temperature data */
115*6f9703d0SDarrick J. Wong #define TEMP_COLLECTION_TIME	1000
116*6f9703d0SDarrick J. Wong 
117*6f9703d0SDarrick J. Wong #define power_of_2(x)	(((x) & ((x) - 1)) == 0)
118*6f9703d0SDarrick J. Wong 
119*6f9703d0SDarrick J. Wong /* datasheet says to divide this number by the fan reading to get fan rpm */
120*6f9703d0SDarrick J. Wong #define FAN_PERIOD_TO_RPM(x)	((90000 * 60) / (x))
121*6f9703d0SDarrick J. Wong #define FAN_RPM_TO_PERIOD	FAN_PERIOD_TO_RPM
122*6f9703d0SDarrick J. Wong #define FAN_PERIOD_INVALID	65535
123*6f9703d0SDarrick J. Wong #define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)
124*6f9703d0SDarrick J. Wong 
125*6f9703d0SDarrick J. Wong struct adt7470_data {
126*6f9703d0SDarrick J. Wong 	struct i2c_client	client;
127*6f9703d0SDarrick J. Wong 	struct class_device	*class_dev;
128*6f9703d0SDarrick J. Wong 	struct attribute_group	attrs;
129*6f9703d0SDarrick J. Wong 	struct mutex		lock;
130*6f9703d0SDarrick J. Wong 	char			sensors_valid;
131*6f9703d0SDarrick J. Wong 	char			limits_valid;
132*6f9703d0SDarrick J. Wong 	unsigned long		sensors_last_updated;	/* In jiffies */
133*6f9703d0SDarrick J. Wong 	unsigned long		limits_last_updated;	/* In jiffies */
134*6f9703d0SDarrick J. Wong 
135*6f9703d0SDarrick J. Wong 	s8			temp[ADT7470_TEMP_COUNT];
136*6f9703d0SDarrick J. Wong 	s8			temp_min[ADT7470_TEMP_COUNT];
137*6f9703d0SDarrick J. Wong 	s8			temp_max[ADT7470_TEMP_COUNT];
138*6f9703d0SDarrick J. Wong 	u16			fan[ADT7470_FAN_COUNT];
139*6f9703d0SDarrick J. Wong 	u16			fan_min[ADT7470_FAN_COUNT];
140*6f9703d0SDarrick J. Wong 	u16			fan_max[ADT7470_FAN_COUNT];
141*6f9703d0SDarrick J. Wong 	u16			alarms, alarms_mask;
142*6f9703d0SDarrick J. Wong 	u8			force_pwm_max;
143*6f9703d0SDarrick J. Wong 	u8			pwm[ADT7470_PWM_COUNT];
144*6f9703d0SDarrick J. Wong 	u8			pwm_max[ADT7470_PWM_COUNT];
145*6f9703d0SDarrick J. Wong 	u8			pwm_automatic[ADT7470_PWM_COUNT];
146*6f9703d0SDarrick J. Wong 	u8			pwm_min[ADT7470_PWM_COUNT];
147*6f9703d0SDarrick J. Wong 	s8			pwm_tmin[ADT7470_PWM_COUNT];
148*6f9703d0SDarrick J. Wong 	u8			pwm_auto_temp[ADT7470_PWM_COUNT];
149*6f9703d0SDarrick J. Wong };
150*6f9703d0SDarrick J. Wong 
151*6f9703d0SDarrick J. Wong static int adt7470_attach_adapter(struct i2c_adapter *adapter);
152*6f9703d0SDarrick J. Wong static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind);
153*6f9703d0SDarrick J. Wong static int adt7470_detach_client(struct i2c_client *client);
154*6f9703d0SDarrick J. Wong 
155*6f9703d0SDarrick J. Wong static struct i2c_driver adt7470_driver = {
156*6f9703d0SDarrick J. Wong 	.driver = {
157*6f9703d0SDarrick J. Wong 		.name	= "adt7470",
158*6f9703d0SDarrick J. Wong 	},
159*6f9703d0SDarrick J. Wong 	.attach_adapter	= adt7470_attach_adapter,
160*6f9703d0SDarrick J. Wong 	.detach_client	= adt7470_detach_client,
161*6f9703d0SDarrick J. Wong };
162*6f9703d0SDarrick J. Wong 
163*6f9703d0SDarrick J. Wong /*
164*6f9703d0SDarrick J. Wong  * 16-bit registers on the ADT7470 are low-byte first.  The data sheet says
165*6f9703d0SDarrick J. Wong  * that the low byte must be read before the high byte.
166*6f9703d0SDarrick J. Wong  */
167*6f9703d0SDarrick J. Wong static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg)
168*6f9703d0SDarrick J. Wong {
169*6f9703d0SDarrick J. Wong 	u16 foo;
170*6f9703d0SDarrick J. Wong 	foo = i2c_smbus_read_byte_data(client, reg);
171*6f9703d0SDarrick J. Wong 	foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
172*6f9703d0SDarrick J. Wong 	return foo;
173*6f9703d0SDarrick J. Wong }
174*6f9703d0SDarrick J. Wong 
175*6f9703d0SDarrick J. Wong static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
176*6f9703d0SDarrick J. Wong 					  u16 value)
177*6f9703d0SDarrick J. Wong {
178*6f9703d0SDarrick J. Wong 	return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
179*6f9703d0SDarrick J. Wong 	       && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
180*6f9703d0SDarrick J. Wong }
181*6f9703d0SDarrick J. Wong 
182*6f9703d0SDarrick J. Wong static void adt7470_init_client(struct i2c_client *client)
183*6f9703d0SDarrick J. Wong {
184*6f9703d0SDarrick J. Wong 	int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
185*6f9703d0SDarrick J. Wong 
186*6f9703d0SDarrick J. Wong 	if (reg < 0) {
187*6f9703d0SDarrick J. Wong 		dev_err(&client->dev, "cannot read configuration register\n");
188*6f9703d0SDarrick J. Wong 	} else {
189*6f9703d0SDarrick J. Wong 		/* start monitoring (and do a self-test) */
190*6f9703d0SDarrick J. Wong 		i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
191*6f9703d0SDarrick J. Wong 	}
192*6f9703d0SDarrick J. Wong }
193*6f9703d0SDarrick J. Wong 
194*6f9703d0SDarrick J. Wong static struct adt7470_data *adt7470_update_device(struct device *dev)
195*6f9703d0SDarrick J. Wong {
196*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
197*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
198*6f9703d0SDarrick J. Wong 	unsigned long local_jiffies = jiffies;
199*6f9703d0SDarrick J. Wong 	u8 cfg;
200*6f9703d0SDarrick J. Wong 	int i;
201*6f9703d0SDarrick J. Wong 
202*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
203*6f9703d0SDarrick J. Wong 	if (time_before(local_jiffies, data->sensors_last_updated +
204*6f9703d0SDarrick J. Wong 		SENSOR_REFRESH_INTERVAL)
205*6f9703d0SDarrick J. Wong 		&& data->sensors_valid)
206*6f9703d0SDarrick J. Wong 		goto no_sensor_update;
207*6f9703d0SDarrick J. Wong 
208*6f9703d0SDarrick J. Wong 	/* start reading temperature sensors */
209*6f9703d0SDarrick J. Wong 	cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
210*6f9703d0SDarrick J. Wong 	cfg |= 0x80;
211*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
212*6f9703d0SDarrick J. Wong 
213*6f9703d0SDarrick J. Wong 	/*
214*6f9703d0SDarrick J. Wong 	 * Delay is 200ms * number of tmp05 sensors.  Too bad
215*6f9703d0SDarrick J. Wong 	 * there's no way to figure out how many are connected.
216*6f9703d0SDarrick J. Wong 	 * For now, assume 1s will work.
217*6f9703d0SDarrick J. Wong 	 */
218*6f9703d0SDarrick J. Wong 	msleep(TEMP_COLLECTION_TIME);
219*6f9703d0SDarrick J. Wong 
220*6f9703d0SDarrick J. Wong 	/* done reading temperature sensors */
221*6f9703d0SDarrick J. Wong 	cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
222*6f9703d0SDarrick J. Wong 	cfg &= ~0x80;
223*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
224*6f9703d0SDarrick J. Wong 
225*6f9703d0SDarrick J. Wong 	for (i = 0; i < ADT7470_TEMP_COUNT; i++)
226*6f9703d0SDarrick J. Wong 		data->temp[i] = i2c_smbus_read_byte_data(client,
227*6f9703d0SDarrick J. Wong 						ADT7470_TEMP_REG(i));
228*6f9703d0SDarrick J. Wong 
229*6f9703d0SDarrick J. Wong 	for (i = 0; i < ADT7470_FAN_COUNT; i++)
230*6f9703d0SDarrick J. Wong 		data->fan[i] = adt7470_read_word_data(client,
231*6f9703d0SDarrick J. Wong 						ADT7470_REG_FAN(i));
232*6f9703d0SDarrick J. Wong 
233*6f9703d0SDarrick J. Wong 	for (i = 0; i < ADT7470_PWM_COUNT; i++) {
234*6f9703d0SDarrick J. Wong 		int reg;
235*6f9703d0SDarrick J. Wong 		int reg_mask;
236*6f9703d0SDarrick J. Wong 
237*6f9703d0SDarrick J. Wong 		data->pwm[i] = i2c_smbus_read_byte_data(client,
238*6f9703d0SDarrick J. Wong 						ADT7470_REG_PWM(i));
239*6f9703d0SDarrick J. Wong 
240*6f9703d0SDarrick J. Wong 		if (i % 2)
241*6f9703d0SDarrick J. Wong 			reg_mask = ADT7470_PWM2_AUTO_MASK;
242*6f9703d0SDarrick J. Wong 		else
243*6f9703d0SDarrick J. Wong 			reg_mask = ADT7470_PWM1_AUTO_MASK;
244*6f9703d0SDarrick J. Wong 
245*6f9703d0SDarrick J. Wong 		reg = ADT7470_REG_PWM_CFG(i);
246*6f9703d0SDarrick J. Wong 		if (i2c_smbus_read_byte_data(client, reg) & reg_mask)
247*6f9703d0SDarrick J. Wong 			data->pwm_automatic[i] = 1;
248*6f9703d0SDarrick J. Wong 		else
249*6f9703d0SDarrick J. Wong 			data->pwm_automatic[i] = 0;
250*6f9703d0SDarrick J. Wong 
251*6f9703d0SDarrick J. Wong 		reg = ADT7470_REG_PWM_AUTO_TEMP(i);
252*6f9703d0SDarrick J. Wong 		cfg = i2c_smbus_read_byte_data(client, reg);
253*6f9703d0SDarrick J. Wong 		if (!(i % 2))
254*6f9703d0SDarrick J. Wong 			data->pwm_auto_temp[i] = cfg >> 4;
255*6f9703d0SDarrick J. Wong 		else
256*6f9703d0SDarrick J. Wong 			data->pwm_auto_temp[i] = cfg & 0xF;
257*6f9703d0SDarrick J. Wong 	}
258*6f9703d0SDarrick J. Wong 
259*6f9703d0SDarrick J. Wong 	if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) &
260*6f9703d0SDarrick J. Wong 	    ADT7470_FSPD_MASK)
261*6f9703d0SDarrick J. Wong 		data->force_pwm_max = 1;
262*6f9703d0SDarrick J. Wong 	else
263*6f9703d0SDarrick J. Wong 		data->force_pwm_max = 0;
264*6f9703d0SDarrick J. Wong 
265*6f9703d0SDarrick J. Wong 	data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1);
266*6f9703d0SDarrick J. Wong 	data->alarms_mask = adt7470_read_word_data(client,
267*6f9703d0SDarrick J. Wong 						   ADT7470_REG_ALARM1_MASK);
268*6f9703d0SDarrick J. Wong 
269*6f9703d0SDarrick J. Wong 	data->sensors_last_updated = local_jiffies;
270*6f9703d0SDarrick J. Wong 	data->sensors_valid = 1;
271*6f9703d0SDarrick J. Wong 
272*6f9703d0SDarrick J. Wong no_sensor_update:
273*6f9703d0SDarrick J. Wong 	if (time_before(local_jiffies, data->limits_last_updated +
274*6f9703d0SDarrick J. Wong 		LIMIT_REFRESH_INTERVAL)
275*6f9703d0SDarrick J. Wong 		&& data->limits_valid)
276*6f9703d0SDarrick J. Wong 		goto out;
277*6f9703d0SDarrick J. Wong 
278*6f9703d0SDarrick J. Wong 	for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
279*6f9703d0SDarrick J. Wong 		data->temp_min[i] = i2c_smbus_read_byte_data(client,
280*6f9703d0SDarrick J. Wong 						ADT7470_TEMP_MIN_REG(i));
281*6f9703d0SDarrick J. Wong 		data->temp_max[i] = i2c_smbus_read_byte_data(client,
282*6f9703d0SDarrick J. Wong 						ADT7470_TEMP_MAX_REG(i));
283*6f9703d0SDarrick J. Wong 	}
284*6f9703d0SDarrick J. Wong 
285*6f9703d0SDarrick J. Wong 	for (i = 0; i < ADT7470_FAN_COUNT; i++) {
286*6f9703d0SDarrick J. Wong 		data->fan_min[i] = adt7470_read_word_data(client,
287*6f9703d0SDarrick J. Wong 						ADT7470_REG_FAN_MIN(i));
288*6f9703d0SDarrick J. Wong 		data->fan_max[i] = adt7470_read_word_data(client,
289*6f9703d0SDarrick J. Wong 						ADT7470_REG_FAN_MAX(i));
290*6f9703d0SDarrick J. Wong 	}
291*6f9703d0SDarrick J. Wong 
292*6f9703d0SDarrick J. Wong 	for (i = 0; i < ADT7470_PWM_COUNT; i++) {
293*6f9703d0SDarrick J. Wong 		data->pwm_max[i] = i2c_smbus_read_byte_data(client,
294*6f9703d0SDarrick J. Wong 						ADT7470_REG_PWM_MAX(i));
295*6f9703d0SDarrick J. Wong 		data->pwm_min[i] = i2c_smbus_read_byte_data(client,
296*6f9703d0SDarrick J. Wong 						ADT7470_REG_PWM_MIN(i));
297*6f9703d0SDarrick J. Wong 		data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
298*6f9703d0SDarrick J. Wong 						ADT7470_REG_PWM_TMIN(i));
299*6f9703d0SDarrick J. Wong 	}
300*6f9703d0SDarrick J. Wong 
301*6f9703d0SDarrick J. Wong 	data->limits_last_updated = local_jiffies;
302*6f9703d0SDarrick J. Wong 	data->limits_valid = 1;
303*6f9703d0SDarrick J. Wong 
304*6f9703d0SDarrick J. Wong out:
305*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
306*6f9703d0SDarrick J. Wong 	return data;
307*6f9703d0SDarrick J. Wong }
308*6f9703d0SDarrick J. Wong 
309*6f9703d0SDarrick J. Wong static ssize_t show_temp_min(struct device *dev,
310*6f9703d0SDarrick J. Wong 			     struct device_attribute *devattr,
311*6f9703d0SDarrick J. Wong 			     char *buf)
312*6f9703d0SDarrick J. Wong {
313*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
314*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
315*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
316*6f9703d0SDarrick J. Wong }
317*6f9703d0SDarrick J. Wong 
318*6f9703d0SDarrick J. Wong static ssize_t set_temp_min(struct device *dev,
319*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
320*6f9703d0SDarrick J. Wong 			    const char *buf,
321*6f9703d0SDarrick J. Wong 			    size_t count)
322*6f9703d0SDarrick J. Wong {
323*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
324*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
325*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
326*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10) / 1000;
327*6f9703d0SDarrick J. Wong 
328*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
329*6f9703d0SDarrick J. Wong 	data->temp_min[attr->index] = temp;
330*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index),
331*6f9703d0SDarrick J. Wong 				  temp);
332*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
333*6f9703d0SDarrick J. Wong 
334*6f9703d0SDarrick J. Wong 	return count;
335*6f9703d0SDarrick J. Wong }
336*6f9703d0SDarrick J. Wong 
337*6f9703d0SDarrick J. Wong static ssize_t show_temp_max(struct device *dev,
338*6f9703d0SDarrick J. Wong 			     struct device_attribute *devattr,
339*6f9703d0SDarrick J. Wong 			     char *buf)
340*6f9703d0SDarrick J. Wong {
341*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
342*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
343*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
344*6f9703d0SDarrick J. Wong }
345*6f9703d0SDarrick J. Wong 
346*6f9703d0SDarrick J. Wong static ssize_t set_temp_max(struct device *dev,
347*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
348*6f9703d0SDarrick J. Wong 			    const char *buf,
349*6f9703d0SDarrick J. Wong 			    size_t count)
350*6f9703d0SDarrick J. Wong {
351*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
352*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
353*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
354*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10) / 1000;
355*6f9703d0SDarrick J. Wong 
356*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
357*6f9703d0SDarrick J. Wong 	data->temp_max[attr->index] = temp;
358*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index),
359*6f9703d0SDarrick J. Wong 				  temp);
360*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
361*6f9703d0SDarrick J. Wong 
362*6f9703d0SDarrick J. Wong 	return count;
363*6f9703d0SDarrick J. Wong }
364*6f9703d0SDarrick J. Wong 
365*6f9703d0SDarrick J. Wong static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
366*6f9703d0SDarrick J. Wong 			 char *buf)
367*6f9703d0SDarrick J. Wong {
368*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
369*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
370*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
371*6f9703d0SDarrick J. Wong }
372*6f9703d0SDarrick J. Wong 
373*6f9703d0SDarrick J. Wong static ssize_t show_alarms(struct device *dev,
374*6f9703d0SDarrick J. Wong 			   struct device_attribute *devattr,
375*6f9703d0SDarrick J. Wong 			   char *buf)
376*6f9703d0SDarrick J. Wong {
377*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
378*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
379*6f9703d0SDarrick J. Wong 
380*6f9703d0SDarrick J. Wong 	if (attr->index)
381*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%x\n", data->alarms);
382*6f9703d0SDarrick J. Wong 	else
383*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%x\n", data->alarms_mask);
384*6f9703d0SDarrick J. Wong }
385*6f9703d0SDarrick J. Wong 
386*6f9703d0SDarrick J. Wong static ssize_t show_fan_max(struct device *dev,
387*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
388*6f9703d0SDarrick J. Wong 			    char *buf)
389*6f9703d0SDarrick J. Wong {
390*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
391*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
392*6f9703d0SDarrick J. Wong 
393*6f9703d0SDarrick J. Wong 	if (FAN_DATA_VALID(data->fan_max[attr->index]))
394*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%d\n",
395*6f9703d0SDarrick J. Wong 			       FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
396*6f9703d0SDarrick J. Wong 	else
397*6f9703d0SDarrick J. Wong 		return sprintf(buf, "0\n");
398*6f9703d0SDarrick J. Wong }
399*6f9703d0SDarrick J. Wong 
400*6f9703d0SDarrick J. Wong static ssize_t set_fan_max(struct device *dev,
401*6f9703d0SDarrick J. Wong 			   struct device_attribute *devattr,
402*6f9703d0SDarrick J. Wong 			   const char *buf, size_t count)
403*6f9703d0SDarrick J. Wong {
404*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
405*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
406*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
407*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
408*6f9703d0SDarrick J. Wong 
409*6f9703d0SDarrick J. Wong 	if (!temp)
410*6f9703d0SDarrick J. Wong 		return -EINVAL;
411*6f9703d0SDarrick J. Wong 	temp = FAN_RPM_TO_PERIOD(temp);
412*6f9703d0SDarrick J. Wong 
413*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
414*6f9703d0SDarrick J. Wong 	data->fan_max[attr->index] = temp;
415*6f9703d0SDarrick J. Wong 	adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp);
416*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
417*6f9703d0SDarrick J. Wong 
418*6f9703d0SDarrick J. Wong 	return count;
419*6f9703d0SDarrick J. Wong }
420*6f9703d0SDarrick J. Wong 
421*6f9703d0SDarrick J. Wong static ssize_t show_fan_min(struct device *dev,
422*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
423*6f9703d0SDarrick J. Wong 			    char *buf)
424*6f9703d0SDarrick J. Wong {
425*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
426*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
427*6f9703d0SDarrick J. Wong 
428*6f9703d0SDarrick J. Wong 	if (FAN_DATA_VALID(data->fan_min[attr->index]))
429*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%d\n",
430*6f9703d0SDarrick J. Wong 			       FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
431*6f9703d0SDarrick J. Wong 	else
432*6f9703d0SDarrick J. Wong 		return sprintf(buf, "0\n");
433*6f9703d0SDarrick J. Wong }
434*6f9703d0SDarrick J. Wong 
435*6f9703d0SDarrick J. Wong static ssize_t set_fan_min(struct device *dev,
436*6f9703d0SDarrick J. Wong 			   struct device_attribute *devattr,
437*6f9703d0SDarrick J. Wong 			   const char *buf, size_t count)
438*6f9703d0SDarrick J. Wong {
439*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
440*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
441*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
442*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
443*6f9703d0SDarrick J. Wong 
444*6f9703d0SDarrick J. Wong 	if (!temp)
445*6f9703d0SDarrick J. Wong 		return -EINVAL;
446*6f9703d0SDarrick J. Wong 	temp = FAN_RPM_TO_PERIOD(temp);
447*6f9703d0SDarrick J. Wong 
448*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
449*6f9703d0SDarrick J. Wong 	data->fan_min[attr->index] = temp;
450*6f9703d0SDarrick J. Wong 	adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp);
451*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
452*6f9703d0SDarrick J. Wong 
453*6f9703d0SDarrick J. Wong 	return count;
454*6f9703d0SDarrick J. Wong }
455*6f9703d0SDarrick J. Wong 
456*6f9703d0SDarrick J. Wong static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
457*6f9703d0SDarrick J. Wong 			char *buf)
458*6f9703d0SDarrick J. Wong {
459*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
460*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
461*6f9703d0SDarrick J. Wong 
462*6f9703d0SDarrick J. Wong 	if (FAN_DATA_VALID(data->fan[attr->index]))
463*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%d\n",
464*6f9703d0SDarrick J. Wong 			       FAN_PERIOD_TO_RPM(data->fan[attr->index]));
465*6f9703d0SDarrick J. Wong 	else
466*6f9703d0SDarrick J. Wong 		return sprintf(buf, "0\n");
467*6f9703d0SDarrick J. Wong }
468*6f9703d0SDarrick J. Wong 
469*6f9703d0SDarrick J. Wong static ssize_t show_force_pwm_max(struct device *dev,
470*6f9703d0SDarrick J. Wong 				  struct device_attribute *devattr,
471*6f9703d0SDarrick J. Wong 				  char *buf)
472*6f9703d0SDarrick J. Wong {
473*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
474*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", data->force_pwm_max);
475*6f9703d0SDarrick J. Wong }
476*6f9703d0SDarrick J. Wong 
477*6f9703d0SDarrick J. Wong static ssize_t set_force_pwm_max(struct device *dev,
478*6f9703d0SDarrick J. Wong 				 struct device_attribute *devattr,
479*6f9703d0SDarrick J. Wong 				 const char *buf,
480*6f9703d0SDarrick J. Wong 				 size_t count)
481*6f9703d0SDarrick J. Wong {
482*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
483*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
484*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
485*6f9703d0SDarrick J. Wong 	u8 reg;
486*6f9703d0SDarrick J. Wong 
487*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
488*6f9703d0SDarrick J. Wong 	data->force_pwm_max = temp;
489*6f9703d0SDarrick J. Wong 	reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
490*6f9703d0SDarrick J. Wong 	if (temp)
491*6f9703d0SDarrick J. Wong 		reg |= ADT7470_FSPD_MASK;
492*6f9703d0SDarrick J. Wong 	else
493*6f9703d0SDarrick J. Wong 		reg &= ~ADT7470_FSPD_MASK;
494*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg);
495*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
496*6f9703d0SDarrick J. Wong 
497*6f9703d0SDarrick J. Wong 	return count;
498*6f9703d0SDarrick J. Wong }
499*6f9703d0SDarrick J. Wong 
500*6f9703d0SDarrick J. Wong static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
501*6f9703d0SDarrick J. Wong 			char *buf)
502*6f9703d0SDarrick J. Wong {
503*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
504*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
505*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", data->pwm[attr->index]);
506*6f9703d0SDarrick J. Wong }
507*6f9703d0SDarrick J. Wong 
508*6f9703d0SDarrick J. Wong static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
509*6f9703d0SDarrick J. Wong 			const char *buf, size_t count)
510*6f9703d0SDarrick J. Wong {
511*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
512*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
513*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
514*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
515*6f9703d0SDarrick J. Wong 
516*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
517*6f9703d0SDarrick J. Wong 	data->pwm[attr->index] = temp;
518*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp);
519*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
520*6f9703d0SDarrick J. Wong 
521*6f9703d0SDarrick J. Wong 	return count;
522*6f9703d0SDarrick J. Wong }
523*6f9703d0SDarrick J. Wong 
524*6f9703d0SDarrick J. Wong static ssize_t show_pwm_max(struct device *dev,
525*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
526*6f9703d0SDarrick J. Wong 			    char *buf)
527*6f9703d0SDarrick J. Wong {
528*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
529*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
530*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
531*6f9703d0SDarrick J. Wong }
532*6f9703d0SDarrick J. Wong 
533*6f9703d0SDarrick J. Wong static ssize_t set_pwm_max(struct device *dev,
534*6f9703d0SDarrick J. Wong 			   struct device_attribute *devattr,
535*6f9703d0SDarrick J. Wong 			   const char *buf,
536*6f9703d0SDarrick J. Wong 			   size_t count)
537*6f9703d0SDarrick J. Wong {
538*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
539*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
540*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
541*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
542*6f9703d0SDarrick J. Wong 
543*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
544*6f9703d0SDarrick J. Wong 	data->pwm_max[attr->index] = temp;
545*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index),
546*6f9703d0SDarrick J. Wong 				  temp);
547*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
548*6f9703d0SDarrick J. Wong 
549*6f9703d0SDarrick J. Wong 	return count;
550*6f9703d0SDarrick J. Wong }
551*6f9703d0SDarrick J. Wong 
552*6f9703d0SDarrick J. Wong static ssize_t show_pwm_min(struct device *dev,
553*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
554*6f9703d0SDarrick J. Wong 			    char *buf)
555*6f9703d0SDarrick J. Wong {
556*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
557*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
558*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
559*6f9703d0SDarrick J. Wong }
560*6f9703d0SDarrick J. Wong 
561*6f9703d0SDarrick J. Wong static ssize_t set_pwm_min(struct device *dev,
562*6f9703d0SDarrick J. Wong 			   struct device_attribute *devattr,
563*6f9703d0SDarrick J. Wong 			   const char *buf,
564*6f9703d0SDarrick J. Wong 			   size_t count)
565*6f9703d0SDarrick J. Wong {
566*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
567*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
568*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
569*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
570*6f9703d0SDarrick J. Wong 
571*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
572*6f9703d0SDarrick J. Wong 	data->pwm_min[attr->index] = temp;
573*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index),
574*6f9703d0SDarrick J. Wong 				  temp);
575*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
576*6f9703d0SDarrick J. Wong 
577*6f9703d0SDarrick J. Wong 	return count;
578*6f9703d0SDarrick J. Wong }
579*6f9703d0SDarrick J. Wong 
580*6f9703d0SDarrick J. Wong static ssize_t show_pwm_tmax(struct device *dev,
581*6f9703d0SDarrick J. Wong 			     struct device_attribute *devattr,
582*6f9703d0SDarrick J. Wong 			     char *buf)
583*6f9703d0SDarrick J. Wong {
584*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
585*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
586*6f9703d0SDarrick J. Wong 	/* the datasheet says that tmax = tmin + 20C */
587*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
588*6f9703d0SDarrick J. Wong }
589*6f9703d0SDarrick J. Wong 
590*6f9703d0SDarrick J. Wong static ssize_t show_pwm_tmin(struct device *dev,
591*6f9703d0SDarrick J. Wong 			     struct device_attribute *devattr,
592*6f9703d0SDarrick J. Wong 			     char *buf)
593*6f9703d0SDarrick J. Wong {
594*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
595*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
596*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
597*6f9703d0SDarrick J. Wong }
598*6f9703d0SDarrick J. Wong 
599*6f9703d0SDarrick J. Wong static ssize_t set_pwm_tmin(struct device *dev,
600*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
601*6f9703d0SDarrick J. Wong 			    const char *buf,
602*6f9703d0SDarrick J. Wong 			    size_t count)
603*6f9703d0SDarrick J. Wong {
604*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
605*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
606*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
607*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10) / 1000;
608*6f9703d0SDarrick J. Wong 
609*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
610*6f9703d0SDarrick J. Wong 	data->pwm_tmin[attr->index] = temp;
611*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index),
612*6f9703d0SDarrick J. Wong 				  temp);
613*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
614*6f9703d0SDarrick J. Wong 
615*6f9703d0SDarrick J. Wong 	return count;
616*6f9703d0SDarrick J. Wong }
617*6f9703d0SDarrick J. Wong 
618*6f9703d0SDarrick J. Wong static ssize_t show_pwm_auto(struct device *dev,
619*6f9703d0SDarrick J. Wong 			     struct device_attribute *devattr,
620*6f9703d0SDarrick J. Wong 			     char *buf)
621*6f9703d0SDarrick J. Wong {
622*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
623*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
624*6f9703d0SDarrick J. Wong 	return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
625*6f9703d0SDarrick J. Wong }
626*6f9703d0SDarrick J. Wong 
627*6f9703d0SDarrick J. Wong static ssize_t set_pwm_auto(struct device *dev,
628*6f9703d0SDarrick J. Wong 			    struct device_attribute *devattr,
629*6f9703d0SDarrick J. Wong 			    const char *buf,
630*6f9703d0SDarrick J. Wong 			    size_t count)
631*6f9703d0SDarrick J. Wong {
632*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
633*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
634*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
635*6f9703d0SDarrick J. Wong 	int temp = simple_strtol(buf, NULL, 10);
636*6f9703d0SDarrick J. Wong 	int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
637*6f9703d0SDarrick J. Wong 	int pwm_auto_reg_mask;
638*6f9703d0SDarrick J. Wong 	u8 reg;
639*6f9703d0SDarrick J. Wong 
640*6f9703d0SDarrick J. Wong 	if (attr->index % 2)
641*6f9703d0SDarrick J. Wong 		pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
642*6f9703d0SDarrick J. Wong 	else
643*6f9703d0SDarrick J. Wong 		pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
644*6f9703d0SDarrick J. Wong 
645*6f9703d0SDarrick J. Wong 	if (temp != 2 && temp != 1)
646*6f9703d0SDarrick J. Wong 		return -EINVAL;
647*6f9703d0SDarrick J. Wong 	temp--;
648*6f9703d0SDarrick J. Wong 
649*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
650*6f9703d0SDarrick J. Wong 	data->pwm_automatic[attr->index] = temp;
651*6f9703d0SDarrick J. Wong 	reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
652*6f9703d0SDarrick J. Wong 	if (temp)
653*6f9703d0SDarrick J. Wong 		reg |= pwm_auto_reg_mask;
654*6f9703d0SDarrick J. Wong 	else
655*6f9703d0SDarrick J. Wong 		reg &= ~pwm_auto_reg_mask;
656*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
657*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
658*6f9703d0SDarrick J. Wong 
659*6f9703d0SDarrick J. Wong 	return count;
660*6f9703d0SDarrick J. Wong }
661*6f9703d0SDarrick J. Wong 
662*6f9703d0SDarrick J. Wong static ssize_t show_pwm_auto_temp(struct device *dev,
663*6f9703d0SDarrick J. Wong 				  struct device_attribute *devattr,
664*6f9703d0SDarrick J. Wong 				  char *buf)
665*6f9703d0SDarrick J. Wong {
666*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
667*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = adt7470_update_device(dev);
668*6f9703d0SDarrick J. Wong 	u8 ctrl = data->pwm_auto_temp[attr->index];
669*6f9703d0SDarrick J. Wong 
670*6f9703d0SDarrick J. Wong 	if (ctrl)
671*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%d\n", 1 << (ctrl - 1));
672*6f9703d0SDarrick J. Wong 	else
673*6f9703d0SDarrick J. Wong 		return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS);
674*6f9703d0SDarrick J. Wong }
675*6f9703d0SDarrick J. Wong 
676*6f9703d0SDarrick J. Wong static int cvt_auto_temp(int input)
677*6f9703d0SDarrick J. Wong {
678*6f9703d0SDarrick J. Wong 	if (input == ADT7470_PWM_ALL_TEMPS)
679*6f9703d0SDarrick J. Wong 		return 0;
680*6f9703d0SDarrick J. Wong 	if (input < 1 || !power_of_2(input))
681*6f9703d0SDarrick J. Wong 		return -EINVAL;
682*6f9703d0SDarrick J. Wong 	return ilog2(input) + 1;
683*6f9703d0SDarrick J. Wong }
684*6f9703d0SDarrick J. Wong 
685*6f9703d0SDarrick J. Wong static ssize_t set_pwm_auto_temp(struct device *dev,
686*6f9703d0SDarrick J. Wong 				 struct device_attribute *devattr,
687*6f9703d0SDarrick J. Wong 				 const char *buf,
688*6f9703d0SDarrick J. Wong 				 size_t count)
689*6f9703d0SDarrick J. Wong {
690*6f9703d0SDarrick J. Wong 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
691*6f9703d0SDarrick J. Wong 	struct i2c_client *client = to_i2c_client(dev);
692*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
693*6f9703d0SDarrick J. Wong 	int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10));
694*6f9703d0SDarrick J. Wong 	int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
695*6f9703d0SDarrick J. Wong 	u8 reg;
696*6f9703d0SDarrick J. Wong 
697*6f9703d0SDarrick J. Wong 	if (temp < 0)
698*6f9703d0SDarrick J. Wong 		return temp;
699*6f9703d0SDarrick J. Wong 
700*6f9703d0SDarrick J. Wong 	mutex_lock(&data->lock);
701*6f9703d0SDarrick J. Wong 	data->pwm_automatic[attr->index] = temp;
702*6f9703d0SDarrick J. Wong 	reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
703*6f9703d0SDarrick J. Wong 
704*6f9703d0SDarrick J. Wong 	if (!(attr->index % 2)) {
705*6f9703d0SDarrick J. Wong 		reg &= 0xF;
706*6f9703d0SDarrick J. Wong 		reg |= (temp << 4) & 0xF0;
707*6f9703d0SDarrick J. Wong 	} else {
708*6f9703d0SDarrick J. Wong 		reg &= 0xF0;
709*6f9703d0SDarrick J. Wong 		reg |= temp & 0xF;
710*6f9703d0SDarrick J. Wong 	}
711*6f9703d0SDarrick J. Wong 
712*6f9703d0SDarrick J. Wong 	i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
713*6f9703d0SDarrick J. Wong 	mutex_unlock(&data->lock);
714*6f9703d0SDarrick J. Wong 
715*6f9703d0SDarrick J. Wong 	return count;
716*6f9703d0SDarrick J. Wong }
717*6f9703d0SDarrick J. Wong 
718*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0);
719*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1);
720*6f9703d0SDarrick J. Wong 
721*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
722*6f9703d0SDarrick J. Wong 		    set_temp_max, 0);
723*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
724*6f9703d0SDarrick J. Wong 		    set_temp_max, 1);
725*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
726*6f9703d0SDarrick J. Wong 		    set_temp_max, 2);
727*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
728*6f9703d0SDarrick J. Wong 		    set_temp_max, 3);
729*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max,
730*6f9703d0SDarrick J. Wong 		    set_temp_max, 4);
731*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max,
732*6f9703d0SDarrick J. Wong 		    set_temp_max, 5);
733*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max,
734*6f9703d0SDarrick J. Wong 		    set_temp_max, 6);
735*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max,
736*6f9703d0SDarrick J. Wong 		    set_temp_max, 7);
737*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max,
738*6f9703d0SDarrick J. Wong 		    set_temp_max, 8);
739*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max,
740*6f9703d0SDarrick J. Wong 		    set_temp_max, 9);
741*6f9703d0SDarrick J. Wong 
742*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
743*6f9703d0SDarrick J. Wong 		    set_temp_min, 0);
744*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
745*6f9703d0SDarrick J. Wong 		    set_temp_min, 1);
746*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
747*6f9703d0SDarrick J. Wong 		    set_temp_min, 2);
748*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
749*6f9703d0SDarrick J. Wong 		    set_temp_min, 3);
750*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min,
751*6f9703d0SDarrick J. Wong 		    set_temp_min, 4);
752*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min,
753*6f9703d0SDarrick J. Wong 		    set_temp_min, 5);
754*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min,
755*6f9703d0SDarrick J. Wong 		    set_temp_min, 6);
756*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min,
757*6f9703d0SDarrick J. Wong 		    set_temp_min, 7);
758*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min,
759*6f9703d0SDarrick J. Wong 		    set_temp_min, 8);
760*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min,
761*6f9703d0SDarrick J. Wong 		    set_temp_min, 9);
762*6f9703d0SDarrick J. Wong 
763*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
764*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
765*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
766*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
767*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
768*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
769*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
770*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
771*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8);
772*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9);
773*6f9703d0SDarrick J. Wong 
774*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
775*6f9703d0SDarrick J. Wong 		    set_fan_max, 0);
776*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
777*6f9703d0SDarrick J. Wong 		    set_fan_max, 1);
778*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max,
779*6f9703d0SDarrick J. Wong 		    set_fan_max, 2);
780*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max,
781*6f9703d0SDarrick J. Wong 		    set_fan_max, 3);
782*6f9703d0SDarrick J. Wong 
783*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
784*6f9703d0SDarrick J. Wong 		    set_fan_min, 0);
785*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
786*6f9703d0SDarrick J. Wong 		    set_fan_min, 1);
787*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
788*6f9703d0SDarrick J. Wong 		    set_fan_min, 2);
789*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
790*6f9703d0SDarrick J. Wong 		    set_fan_min, 3);
791*6f9703d0SDarrick J. Wong 
792*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
793*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
794*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
795*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
796*6f9703d0SDarrick J. Wong 
797*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
798*6f9703d0SDarrick J. Wong 		    show_force_pwm_max, set_force_pwm_max, 0);
799*6f9703d0SDarrick J. Wong 
800*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
801*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
802*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
803*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
804*6f9703d0SDarrick J. Wong 
805*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
806*6f9703d0SDarrick J. Wong 		    show_pwm_min, set_pwm_min, 0);
807*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
808*6f9703d0SDarrick J. Wong 		    show_pwm_min, set_pwm_min, 1);
809*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
810*6f9703d0SDarrick J. Wong 		    show_pwm_min, set_pwm_min, 2);
811*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
812*6f9703d0SDarrick J. Wong 		    show_pwm_min, set_pwm_min, 3);
813*6f9703d0SDarrick J. Wong 
814*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
815*6f9703d0SDarrick J. Wong 		    show_pwm_max, set_pwm_max, 0);
816*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
817*6f9703d0SDarrick J. Wong 		    show_pwm_max, set_pwm_max, 1);
818*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
819*6f9703d0SDarrick J. Wong 		    show_pwm_max, set_pwm_max, 2);
820*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
821*6f9703d0SDarrick J. Wong 		    show_pwm_max, set_pwm_max, 3);
822*6f9703d0SDarrick J. Wong 
823*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
824*6f9703d0SDarrick J. Wong 		    show_pwm_tmin, set_pwm_tmin, 0);
825*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
826*6f9703d0SDarrick J. Wong 		    show_pwm_tmin, set_pwm_tmin, 1);
827*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
828*6f9703d0SDarrick J. Wong 		    show_pwm_tmin, set_pwm_tmin, 2);
829*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
830*6f9703d0SDarrick J. Wong 		    show_pwm_tmin, set_pwm_tmin, 3);
831*6f9703d0SDarrick J. Wong 
832*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax,
833*6f9703d0SDarrick J. Wong 		    NULL, 0);
834*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax,
835*6f9703d0SDarrick J. Wong 		    NULL, 1);
836*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax,
837*6f9703d0SDarrick J. Wong 		    NULL, 2);
838*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax,
839*6f9703d0SDarrick J. Wong 		    NULL, 3);
840*6f9703d0SDarrick J. Wong 
841*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
842*6f9703d0SDarrick J. Wong 		    set_pwm_auto, 0);
843*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
844*6f9703d0SDarrick J. Wong 		    set_pwm_auto, 1);
845*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
846*6f9703d0SDarrick J. Wong 		    set_pwm_auto, 2);
847*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
848*6f9703d0SDarrick J. Wong 		    set_pwm_auto, 3);
849*6f9703d0SDarrick J. Wong 
850*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
851*6f9703d0SDarrick J. Wong 		    show_pwm_auto_temp, set_pwm_auto_temp, 0);
852*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
853*6f9703d0SDarrick J. Wong 		    show_pwm_auto_temp, set_pwm_auto_temp, 1);
854*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
855*6f9703d0SDarrick J. Wong 		    show_pwm_auto_temp, set_pwm_auto_temp, 2);
856*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
857*6f9703d0SDarrick J. Wong 		    show_pwm_auto_temp, set_pwm_auto_temp, 3);
858*6f9703d0SDarrick J. Wong 
859*6f9703d0SDarrick J. Wong static struct attribute *adt7470_attr[] =
860*6f9703d0SDarrick J. Wong {
861*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_alarms.dev_attr.attr,
862*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_alarm_mask.dev_attr.attr,
863*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp1_max.dev_attr.attr,
864*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp2_max.dev_attr.attr,
865*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp3_max.dev_attr.attr,
866*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp4_max.dev_attr.attr,
867*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp5_max.dev_attr.attr,
868*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp6_max.dev_attr.attr,
869*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp7_max.dev_attr.attr,
870*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp8_max.dev_attr.attr,
871*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp9_max.dev_attr.attr,
872*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp10_max.dev_attr.attr,
873*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp1_min.dev_attr.attr,
874*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp2_min.dev_attr.attr,
875*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp3_min.dev_attr.attr,
876*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp4_min.dev_attr.attr,
877*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp5_min.dev_attr.attr,
878*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp6_min.dev_attr.attr,
879*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp7_min.dev_attr.attr,
880*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp8_min.dev_attr.attr,
881*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp9_min.dev_attr.attr,
882*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp10_min.dev_attr.attr,
883*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp1_input.dev_attr.attr,
884*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp2_input.dev_attr.attr,
885*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp3_input.dev_attr.attr,
886*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp4_input.dev_attr.attr,
887*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp5_input.dev_attr.attr,
888*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp6_input.dev_attr.attr,
889*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp7_input.dev_attr.attr,
890*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp8_input.dev_attr.attr,
891*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp9_input.dev_attr.attr,
892*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_temp10_input.dev_attr.attr,
893*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan1_max.dev_attr.attr,
894*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan2_max.dev_attr.attr,
895*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan3_max.dev_attr.attr,
896*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan4_max.dev_attr.attr,
897*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan1_min.dev_attr.attr,
898*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan2_min.dev_attr.attr,
899*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan3_min.dev_attr.attr,
900*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan4_min.dev_attr.attr,
901*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan1_input.dev_attr.attr,
902*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan2_input.dev_attr.attr,
903*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan3_input.dev_attr.attr,
904*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_fan4_input.dev_attr.attr,
905*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_force_pwm_max.dev_attr.attr,
906*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1.dev_attr.attr,
907*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2.dev_attr.attr,
908*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3.dev_attr.attr,
909*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4.dev_attr.attr,
910*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
911*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
912*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
913*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
914*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
915*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
916*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
917*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
918*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
919*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
920*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
921*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,
922*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
923*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
924*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
925*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
926*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
927*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
928*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
929*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
930*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
931*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
932*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
933*6f9703d0SDarrick J. Wong 	&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
934*6f9703d0SDarrick J. Wong 	NULL
935*6f9703d0SDarrick J. Wong };
936*6f9703d0SDarrick J. Wong 
937*6f9703d0SDarrick J. Wong static int adt7470_attach_adapter(struct i2c_adapter *adapter)
938*6f9703d0SDarrick J. Wong {
939*6f9703d0SDarrick J. Wong 	if (!(adapter->class & I2C_CLASS_HWMON))
940*6f9703d0SDarrick J. Wong 		return 0;
941*6f9703d0SDarrick J. Wong 	return i2c_probe(adapter, &addr_data, adt7470_detect);
942*6f9703d0SDarrick J. Wong }
943*6f9703d0SDarrick J. Wong 
944*6f9703d0SDarrick J. Wong static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
945*6f9703d0SDarrick J. Wong {
946*6f9703d0SDarrick J. Wong 	struct i2c_client *client;
947*6f9703d0SDarrick J. Wong 	struct adt7470_data *data;
948*6f9703d0SDarrick J. Wong 	int err = 0;
949*6f9703d0SDarrick J. Wong 
950*6f9703d0SDarrick J. Wong 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
951*6f9703d0SDarrick J. Wong 		goto exit;
952*6f9703d0SDarrick J. Wong 
953*6f9703d0SDarrick J. Wong 	if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) {
954*6f9703d0SDarrick J. Wong 		err = -ENOMEM;
955*6f9703d0SDarrick J. Wong 		goto exit;
956*6f9703d0SDarrick J. Wong 	}
957*6f9703d0SDarrick J. Wong 
958*6f9703d0SDarrick J. Wong 	client = &data->client;
959*6f9703d0SDarrick J. Wong 	client->addr = address;
960*6f9703d0SDarrick J. Wong 	client->adapter = adapter;
961*6f9703d0SDarrick J. Wong 	client->driver = &adt7470_driver;
962*6f9703d0SDarrick J. Wong 
963*6f9703d0SDarrick J. Wong 	i2c_set_clientdata(client, data);
964*6f9703d0SDarrick J. Wong 
965*6f9703d0SDarrick J. Wong 	mutex_init(&data->lock);
966*6f9703d0SDarrick J. Wong 
967*6f9703d0SDarrick J. Wong 	if (kind <= 0) {
968*6f9703d0SDarrick J. Wong 		int vendor, device, revision;
969*6f9703d0SDarrick J. Wong 
970*6f9703d0SDarrick J. Wong 		vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
971*6f9703d0SDarrick J. Wong 		if (vendor != ADT7470_VENDOR) {
972*6f9703d0SDarrick J. Wong 			err = -ENODEV;
973*6f9703d0SDarrick J. Wong 			goto exit_free;
974*6f9703d0SDarrick J. Wong 		}
975*6f9703d0SDarrick J. Wong 
976*6f9703d0SDarrick J. Wong 		device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
977*6f9703d0SDarrick J. Wong 		if (device != ADT7470_DEVICE) {
978*6f9703d0SDarrick J. Wong 			err = -ENODEV;
979*6f9703d0SDarrick J. Wong 			goto exit_free;
980*6f9703d0SDarrick J. Wong 		}
981*6f9703d0SDarrick J. Wong 
982*6f9703d0SDarrick J. Wong 		revision = i2c_smbus_read_byte_data(client,
983*6f9703d0SDarrick J. Wong 						    ADT7470_REG_REVISION);
984*6f9703d0SDarrick J. Wong 		if (revision != ADT7470_REVISION) {
985*6f9703d0SDarrick J. Wong 			err = -ENODEV;
986*6f9703d0SDarrick J. Wong 			goto exit_free;
987*6f9703d0SDarrick J. Wong 		}
988*6f9703d0SDarrick J. Wong 	} else
989*6f9703d0SDarrick J. Wong 		dev_dbg(&adapter->dev, "detection forced\n");
990*6f9703d0SDarrick J. Wong 
991*6f9703d0SDarrick J. Wong 	strlcpy(client->name, "adt7470", I2C_NAME_SIZE);
992*6f9703d0SDarrick J. Wong 
993*6f9703d0SDarrick J. Wong 	if ((err = i2c_attach_client(client)))
994*6f9703d0SDarrick J. Wong 		goto exit_free;
995*6f9703d0SDarrick J. Wong 
996*6f9703d0SDarrick J. Wong 	dev_info(&client->dev, "%s chip found\n", client->name);
997*6f9703d0SDarrick J. Wong 
998*6f9703d0SDarrick J. Wong 	/* Initialize the ADT7470 chip */
999*6f9703d0SDarrick J. Wong 	adt7470_init_client(client);
1000*6f9703d0SDarrick J. Wong 
1001*6f9703d0SDarrick J. Wong 	/* Register sysfs hooks */
1002*6f9703d0SDarrick J. Wong 	data->attrs.attrs = adt7470_attr;
1003*6f9703d0SDarrick J. Wong 	if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
1004*6f9703d0SDarrick J. Wong 		goto exit_detach;
1005*6f9703d0SDarrick J. Wong 
1006*6f9703d0SDarrick J. Wong 	data->class_dev = hwmon_device_register(&client->dev);
1007*6f9703d0SDarrick J. Wong 	if (IS_ERR(data->class_dev)) {
1008*6f9703d0SDarrick J. Wong 		err = PTR_ERR(data->class_dev);
1009*6f9703d0SDarrick J. Wong 		goto exit_remove;
1010*6f9703d0SDarrick J. Wong 	}
1011*6f9703d0SDarrick J. Wong 
1012*6f9703d0SDarrick J. Wong 	return 0;
1013*6f9703d0SDarrick J. Wong 
1014*6f9703d0SDarrick J. Wong exit_remove:
1015*6f9703d0SDarrick J. Wong 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
1016*6f9703d0SDarrick J. Wong exit_detach:
1017*6f9703d0SDarrick J. Wong 	i2c_detach_client(client);
1018*6f9703d0SDarrick J. Wong exit_free:
1019*6f9703d0SDarrick J. Wong 	kfree(data);
1020*6f9703d0SDarrick J. Wong exit:
1021*6f9703d0SDarrick J. Wong 	return err;
1022*6f9703d0SDarrick J. Wong }
1023*6f9703d0SDarrick J. Wong 
1024*6f9703d0SDarrick J. Wong static int adt7470_detach_client(struct i2c_client *client)
1025*6f9703d0SDarrick J. Wong {
1026*6f9703d0SDarrick J. Wong 	struct adt7470_data *data = i2c_get_clientdata(client);
1027*6f9703d0SDarrick J. Wong 
1028*6f9703d0SDarrick J. Wong 	hwmon_device_unregister(data->class_dev);
1029*6f9703d0SDarrick J. Wong 	sysfs_remove_group(&client->dev.kobj, &data->attrs);
1030*6f9703d0SDarrick J. Wong 	i2c_detach_client(client);
1031*6f9703d0SDarrick J. Wong 	kfree(data);
1032*6f9703d0SDarrick J. Wong 	return 0;
1033*6f9703d0SDarrick J. Wong }
1034*6f9703d0SDarrick J. Wong 
1035*6f9703d0SDarrick J. Wong static int __init adt7470_init(void)
1036*6f9703d0SDarrick J. Wong {
1037*6f9703d0SDarrick J. Wong 	return i2c_add_driver(&adt7470_driver);
1038*6f9703d0SDarrick J. Wong }
1039*6f9703d0SDarrick J. Wong 
1040*6f9703d0SDarrick J. Wong static void __exit adt7470_exit(void)
1041*6f9703d0SDarrick J. Wong {
1042*6f9703d0SDarrick J. Wong 	i2c_del_driver(&adt7470_driver);
1043*6f9703d0SDarrick J. Wong }
1044*6f9703d0SDarrick J. Wong 
1045*6f9703d0SDarrick J. Wong MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
1046*6f9703d0SDarrick J. Wong MODULE_DESCRIPTION("ADT7470 driver");
1047*6f9703d0SDarrick J. Wong MODULE_LICENSE("GPL");
1048*6f9703d0SDarrick J. Wong 
1049*6f9703d0SDarrick J. Wong module_init(adt7470_init);
1050*6f9703d0SDarrick J. Wong module_exit(adt7470_exit);
1051