xref: /linux/drivers/hwmon/max6639.c (revision 0f33272b60ed87a2609542a6851361f35b83c6ba)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a5b79d62Sstigge@antcom.de /*
3a5b79d62Sstigge@antcom.de  * max6639.c - Support for Maxim MAX6639
4a5b79d62Sstigge@antcom.de  *
5a5b79d62Sstigge@antcom.de  * 2-Channel Temperature Monitor with Dual PWM Fan-Speed Controller
6a5b79d62Sstigge@antcom.de  *
7a5b79d62Sstigge@antcom.de  * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
8a5b79d62Sstigge@antcom.de  *
9a5b79d62Sstigge@antcom.de  * based on the initial MAX6639 support from semptian.net
10a5b79d62Sstigge@antcom.de  * by He Changqing <hechangqing@semptian.com>
11a5b79d62Sstigge@antcom.de  */
12a5b79d62Sstigge@antcom.de 
13a5b79d62Sstigge@antcom.de #include <linux/module.h>
14a5b79d62Sstigge@antcom.de #include <linux/init.h>
15a5b79d62Sstigge@antcom.de #include <linux/slab.h>
16a5b79d62Sstigge@antcom.de #include <linux/jiffies.h>
17a5b79d62Sstigge@antcom.de #include <linux/i2c.h>
18a5b79d62Sstigge@antcom.de #include <linux/hwmon.h>
19a5b79d62Sstigge@antcom.de #include <linux/hwmon-sysfs.h>
20a5b79d62Sstigge@antcom.de #include <linux/err.h>
21a5b79d62Sstigge@antcom.de #include <linux/mutex.h>
220c9fe161SWolfram Sang #include <linux/platform_data/max6639.h>
2345bf8305SNaresh Solanki #include <linux/regmap.h>
24*0f33272bSNaresh Solanki #include <linux/util_macros.h>
25a5b79d62Sstigge@antcom.de 
26a5b79d62Sstigge@antcom.de /* Addresses to scan */
277edc8cc1SAxel Lin static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
28a5b79d62Sstigge@antcom.de 
29a5b79d62Sstigge@antcom.de /* The MAX6639 registers, valid channel numbers: 0, 1 */
30a5b79d62Sstigge@antcom.de #define MAX6639_REG_TEMP(ch)			(0x00 + (ch))
31a5b79d62Sstigge@antcom.de #define MAX6639_REG_STATUS			0x02
32a5b79d62Sstigge@antcom.de #define MAX6639_REG_OUTPUT_MASK			0x03
33a5b79d62Sstigge@antcom.de #define MAX6639_REG_GCONFIG			0x04
34a5b79d62Sstigge@antcom.de #define MAX6639_REG_TEMP_EXT(ch)		(0x05 + (ch))
35a5b79d62Sstigge@antcom.de #define MAX6639_REG_ALERT_LIMIT(ch)		(0x08 + (ch))
36a5b79d62Sstigge@antcom.de #define MAX6639_REG_OT_LIMIT(ch)		(0x0A + (ch))
37a5b79d62Sstigge@antcom.de #define MAX6639_REG_THERM_LIMIT(ch)		(0x0C + (ch))
38a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG1(ch)		(0x10 + (ch) * 4)
39a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG2a(ch)		(0x11 + (ch) * 4)
40a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG2b(ch)		(0x12 + (ch) * 4)
41a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CONFIG3(ch)		(0x13 + (ch) * 4)
42a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_CNT(ch)			(0x20 + (ch))
43a5b79d62Sstigge@antcom.de #define MAX6639_REG_TARGET_CNT(ch)		(0x22 + (ch))
44a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_PPR(ch)			(0x24 + (ch))
45a5b79d62Sstigge@antcom.de #define MAX6639_REG_TARGTDUTY(ch)		(0x26 + (ch))
46a5b79d62Sstigge@antcom.de #define MAX6639_REG_FAN_START_TEMP(ch)		(0x28 + (ch))
47a5b79d62Sstigge@antcom.de #define MAX6639_REG_DEVID			0x3D
48a5b79d62Sstigge@antcom.de #define MAX6639_REG_MANUID			0x3E
49a5b79d62Sstigge@antcom.de #define MAX6639_REG_DEVREV			0x3F
50a5b79d62Sstigge@antcom.de 
51a5b79d62Sstigge@antcom.de /* Register bits */
52a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_STANDBY			0x80
53a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_POR			0x40
54a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_DISABLE_TIMEOUT		0x20
55a5b79d62Sstigge@antcom.de #define MAX6639_GCONFIG_CH2_LOCAL		0x10
56177f3b92Sstigge@antcom.de #define MAX6639_GCONFIG_PWM_FREQ_HI		0x08
57a5b79d62Sstigge@antcom.de 
58a5b79d62Sstigge@antcom.de #define MAX6639_FAN_CONFIG1_PWM			0x80
59*0f33272bSNaresh Solanki #define MAX6639_FAN_CONFIG3_FREQ_MASK		0x03
60177f3b92Sstigge@antcom.de #define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED	0x40
61177f3b92Sstigge@antcom.de 
6245bf8305SNaresh Solanki #define MAX6639_NUM_CHANNELS			2
6345bf8305SNaresh Solanki 
64a5b79d62Sstigge@antcom.de static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
65a5b79d62Sstigge@antcom.de 
66*0f33272bSNaresh Solanki /* Supported PWM frequency */
67*0f33272bSNaresh Solanki static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500,
68*0f33272bSNaresh Solanki 					   25000 };
69*0f33272bSNaresh Solanki 
70b63d97a3SChris D Schimp #define FAN_FROM_REG(val, rpm_range)	((val) == 0 || (val) == 255 ? \
71b63d97a3SChris D Schimp 				0 : (rpm_ranges[rpm_range] * 30) / (val))
722a844c14SGuenter Roeck #define TEMP_LIMIT_TO_REG(val)	clamp_val((val) / 1000, 0, 255)
73a5b79d62Sstigge@antcom.de 
74a5b79d62Sstigge@antcom.de /*
75a5b79d62Sstigge@antcom.de  * Client data (each client gets its own)
76a5b79d62Sstigge@antcom.de  */
77a5b79d62Sstigge@antcom.de struct max6639_data {
7845bf8305SNaresh Solanki 	struct regmap *regmap;
79a5b79d62Sstigge@antcom.de 
80a5b79d62Sstigge@antcom.de 	/* Register values initialized only once */
81*0f33272bSNaresh Solanki 	u8 ppr[MAX6639_NUM_CHANNELS];	/* Pulses per rotation 0..3 for 1..4 ppr */
82*0f33272bSNaresh Solanki 	u8 rpm_range[MAX6639_NUM_CHANNELS]; /* Index in above rpm_ranges table */
834e2271eaSMarcello Sylvester Bauer 
844e2271eaSMarcello Sylvester Bauer 	/* Optional regulator for FAN supply */
854e2271eaSMarcello Sylvester Bauer 	struct regulator *reg;
86a5b79d62Sstigge@antcom.de };
87a5b79d62Sstigge@antcom.de 
88*0f33272bSNaresh Solanki static int max6639_temp_read_input(struct device *dev, int channel, long *temp)
89a5b79d62Sstigge@antcom.de {
9045bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
9145bf8305SNaresh Solanki 	unsigned int val;
9245bf8305SNaresh Solanki 	int res;
93a5b79d62Sstigge@antcom.de 
9445bf8305SNaresh Solanki 	/*
9545bf8305SNaresh Solanki 	 * Lock isn't needed as MAX6639_REG_TEMP wpnt change for at least 250ms after reading
9645bf8305SNaresh Solanki 	 * MAX6639_REG_TEMP_EXT
9745bf8305SNaresh Solanki 	 */
98*0f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val);
9945bf8305SNaresh Solanki 	if (res < 0)
10045bf8305SNaresh Solanki 		return res;
101a5b79d62Sstigge@antcom.de 
102*0f33272bSNaresh Solanki 	*temp = val >> 5;
103*0f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP(channel), &val);
10445bf8305SNaresh Solanki 	if (res < 0)
10545bf8305SNaresh Solanki 		return res;
10645bf8305SNaresh Solanki 
107*0f33272bSNaresh Solanki 	*temp |= val << 3;
108*0f33272bSNaresh Solanki 	*temp *= 125;
10945bf8305SNaresh Solanki 
110*0f33272bSNaresh Solanki 	return 0;
111a5b79d62Sstigge@antcom.de }
112a5b79d62Sstigge@antcom.de 
113*0f33272bSNaresh Solanki static int max6639_temp_read_fault(struct device *dev, int channel, long *fault)
114a5b79d62Sstigge@antcom.de {
11545bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
11645bf8305SNaresh Solanki 	unsigned int val;
11745bf8305SNaresh Solanki 	int res;
118a5b79d62Sstigge@antcom.de 
119*0f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val);
12045bf8305SNaresh Solanki 	if (res < 0)
12145bf8305SNaresh Solanki 		return res;
12245bf8305SNaresh Solanki 
123*0f33272bSNaresh Solanki 	*fault = val & 1;
124*0f33272bSNaresh Solanki 
125*0f33272bSNaresh Solanki 	return 0;
126a5b79d62Sstigge@antcom.de }
127a5b79d62Sstigge@antcom.de 
128*0f33272bSNaresh Solanki static int max6639_temp_read_max(struct device *dev, int channel, long *max)
129a5b79d62Sstigge@antcom.de {
1307981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
13145bf8305SNaresh Solanki 	unsigned int val;
13245bf8305SNaresh Solanki 	int res;
133a5b79d62Sstigge@antcom.de 
134*0f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(channel), &val);
13545bf8305SNaresh Solanki 	if (res < 0)
13645bf8305SNaresh Solanki 		return res;
13745bf8305SNaresh Solanki 
138*0f33272bSNaresh Solanki 	*max = (long)val * 1000;
139*0f33272bSNaresh Solanki 
140*0f33272bSNaresh Solanki 	return 0;
141a5b79d62Sstigge@antcom.de }
142a5b79d62Sstigge@antcom.de 
143*0f33272bSNaresh Solanki static int max6639_temp_read_crit(struct device *dev, int channel, long *crit)
144a5b79d62Sstigge@antcom.de {
1457981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
14645bf8305SNaresh Solanki 	unsigned int val;
14745bf8305SNaresh Solanki 	int res;
148a5b79d62Sstigge@antcom.de 
149*0f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), &val);
15045bf8305SNaresh Solanki 	if (res < 0)
15145bf8305SNaresh Solanki 		return res;
15245bf8305SNaresh Solanki 
153*0f33272bSNaresh Solanki 	*crit = (long)val * 1000;
154*0f33272bSNaresh Solanki 
155*0f33272bSNaresh Solanki 	return 0;
156a5b79d62Sstigge@antcom.de }
157a5b79d62Sstigge@antcom.de 
158*0f33272bSNaresh Solanki static int max6639_temp_read_emergency(struct device *dev, int channel, long *emerg)
159a5b79d62Sstigge@antcom.de {
1607981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
16145bf8305SNaresh Solanki 	unsigned int val;
16245bf8305SNaresh Solanki 	int res;
163a5b79d62Sstigge@antcom.de 
164*0f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(channel), &val);
16545bf8305SNaresh Solanki 	if (res < 0)
16645bf8305SNaresh Solanki 		return res;
16745bf8305SNaresh Solanki 
168*0f33272bSNaresh Solanki 	*emerg = (long)val * 1000;
169*0f33272bSNaresh Solanki 
170*0f33272bSNaresh Solanki 	return 0;
171a5b79d62Sstigge@antcom.de }
172a5b79d62Sstigge@antcom.de 
173*0f33272bSNaresh Solanki static int max6639_get_status(struct device *dev, unsigned int *status)
174a5b79d62Sstigge@antcom.de {
17545bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
17645bf8305SNaresh Solanki 	unsigned int val;
17745bf8305SNaresh Solanki 	int res;
178a5b79d62Sstigge@antcom.de 
17945bf8305SNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val);
18045bf8305SNaresh Solanki 	if (res < 0)
18145bf8305SNaresh Solanki 		return res;
182a5b79d62Sstigge@antcom.de 
183*0f33272bSNaresh Solanki 	*status = val;
184*0f33272bSNaresh Solanki 
185*0f33272bSNaresh Solanki 	return 0;
186a5b79d62Sstigge@antcom.de }
187a5b79d62Sstigge@antcom.de 
188*0f33272bSNaresh Solanki static int max6639_temp_set_max(struct max6639_data *data, int channel, long val)
189*0f33272bSNaresh Solanki {
190*0f33272bSNaresh Solanki 	int res;
191a5b79d62Sstigge@antcom.de 
192*0f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel),
193*0f33272bSNaresh Solanki 			   TEMP_LIMIT_TO_REG(val));
194*0f33272bSNaresh Solanki 	return res;
195*0f33272bSNaresh Solanki }
196a5b79d62Sstigge@antcom.de 
197*0f33272bSNaresh Solanki static int max6639_temp_set_crit(struct max6639_data *data, int channel, long val)
198*0f33272bSNaresh Solanki {
199*0f33272bSNaresh Solanki 	int res;
200*0f33272bSNaresh Solanki 
201*0f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
202*0f33272bSNaresh Solanki 
203*0f33272bSNaresh Solanki 	return res;
204*0f33272bSNaresh Solanki }
205*0f33272bSNaresh Solanki 
206*0f33272bSNaresh Solanki static int max6639_temp_set_emergency(struct max6639_data *data, int channel, long val)
207*0f33272bSNaresh Solanki {
208*0f33272bSNaresh Solanki 	int res;
209*0f33272bSNaresh Solanki 
210*0f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
211*0f33272bSNaresh Solanki 
212*0f33272bSNaresh Solanki 	return res;
213*0f33272bSNaresh Solanki }
214*0f33272bSNaresh Solanki 
215*0f33272bSNaresh Solanki static int max6639_read_fan(struct device *dev, u32 attr, int channel,
216*0f33272bSNaresh Solanki 			    long *fan_val)
217*0f33272bSNaresh Solanki {
218*0f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
219*0f33272bSNaresh Solanki 	unsigned int val;
220*0f33272bSNaresh Solanki 	int res;
221*0f33272bSNaresh Solanki 
222*0f33272bSNaresh Solanki 	switch (attr) {
223*0f33272bSNaresh Solanki 	case hwmon_fan_input:
224*0f33272bSNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val);
225*0f33272bSNaresh Solanki 		if (res < 0)
226*0f33272bSNaresh Solanki 			return res;
227*0f33272bSNaresh Solanki 		*fan_val = FAN_FROM_REG(val, data->rpm_range[channel]);
228*0f33272bSNaresh Solanki 		return 0;
229*0f33272bSNaresh Solanki 	case hwmon_fan_fault:
230*0f33272bSNaresh Solanki 		res = max6639_get_status(dev, &val);
231*0f33272bSNaresh Solanki 		if (res < 0)
232*0f33272bSNaresh Solanki 			return res;
233*0f33272bSNaresh Solanki 		*fan_val = !!(val & BIT(1 - channel));
234*0f33272bSNaresh Solanki 		return 0;
235*0f33272bSNaresh Solanki 	default:
236*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
237*0f33272bSNaresh Solanki 	}
238*0f33272bSNaresh Solanki }
239*0f33272bSNaresh Solanki 
240*0f33272bSNaresh Solanki static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr)
241*0f33272bSNaresh Solanki {
242*0f33272bSNaresh Solanki 	/* Decrement the PPR value and shift left by 6 to match the register format */
243*0f33272bSNaresh Solanki 	return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6);
244*0f33272bSNaresh Solanki }
245*0f33272bSNaresh Solanki 
246*0f33272bSNaresh Solanki static umode_t max6639_fan_is_visible(const void *_data, u32 attr, int channel)
247*0f33272bSNaresh Solanki {
248*0f33272bSNaresh Solanki 	switch (attr) {
249*0f33272bSNaresh Solanki 	case hwmon_fan_input:
250*0f33272bSNaresh Solanki 	case hwmon_fan_fault:
251*0f33272bSNaresh Solanki 		return 0444;
252*0f33272bSNaresh Solanki 	case hwmon_fan_pulses:
253*0f33272bSNaresh Solanki 		return 0644;
254*0f33272bSNaresh Solanki 	default:
255*0f33272bSNaresh Solanki 		return 0;
256*0f33272bSNaresh Solanki 	}
257*0f33272bSNaresh Solanki }
258*0f33272bSNaresh Solanki 
259*0f33272bSNaresh Solanki static int max6639_read_pwm(struct device *dev, u32 attr, int channel,
260*0f33272bSNaresh Solanki 			    long *pwm_val)
261*0f33272bSNaresh Solanki {
262*0f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
263*0f33272bSNaresh Solanki 	unsigned int val;
264*0f33272bSNaresh Solanki 	int res;
265*0f33272bSNaresh Solanki 
266*0f33272bSNaresh Solanki 	switch (attr) {
267*0f33272bSNaresh Solanki 	case hwmon_pwm_input:
268*0f33272bSNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(channel), &val);
269*0f33272bSNaresh Solanki 		if (res < 0)
270*0f33272bSNaresh Solanki 			return res;
271*0f33272bSNaresh Solanki 		*pwm_val = val * 255 / 120;
272*0f33272bSNaresh Solanki 		return 0;
273*0f33272bSNaresh Solanki 	default:
274*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
275*0f33272bSNaresh Solanki 	}
276*0f33272bSNaresh Solanki }
277*0f33272bSNaresh Solanki 
278*0f33272bSNaresh Solanki static int max6639_write_pwm(struct device *dev, u32 attr, int channel,
279*0f33272bSNaresh Solanki 			     long val)
280*0f33272bSNaresh Solanki {
281*0f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
282*0f33272bSNaresh Solanki 	int err;
283*0f33272bSNaresh Solanki 
284*0f33272bSNaresh Solanki 	switch (attr) {
285*0f33272bSNaresh Solanki 	case hwmon_pwm_input:
286*0f33272bSNaresh Solanki 		if (val < 0 || val > 255)
287*0f33272bSNaresh Solanki 			return -EINVAL;
288*0f33272bSNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel),
289*0f33272bSNaresh Solanki 				   val * 120 / 255);
290*0f33272bSNaresh Solanki 		return err;
291*0f33272bSNaresh Solanki 	default:
292*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
293*0f33272bSNaresh Solanki 	}
294*0f33272bSNaresh Solanki }
295*0f33272bSNaresh Solanki 
296*0f33272bSNaresh Solanki static umode_t max6639_pwm_is_visible(const void *_data, u32 attr, int channel)
297*0f33272bSNaresh Solanki {
298*0f33272bSNaresh Solanki 	switch (attr) {
299*0f33272bSNaresh Solanki 	case hwmon_pwm_input:
300*0f33272bSNaresh Solanki 		return 0644;
301*0f33272bSNaresh Solanki 	default:
302*0f33272bSNaresh Solanki 		return 0;
303*0f33272bSNaresh Solanki 	}
304*0f33272bSNaresh Solanki }
305*0f33272bSNaresh Solanki 
306*0f33272bSNaresh Solanki static int max6639_read_temp(struct device *dev, u32 attr, int channel,
307*0f33272bSNaresh Solanki 			     long *val)
308*0f33272bSNaresh Solanki {
309*0f33272bSNaresh Solanki 	unsigned int status;
310*0f33272bSNaresh Solanki 	int res;
311*0f33272bSNaresh Solanki 
312*0f33272bSNaresh Solanki 	switch (attr) {
313*0f33272bSNaresh Solanki 	case hwmon_temp_input:
314*0f33272bSNaresh Solanki 		res = max6639_temp_read_input(dev, channel, val);
315*0f33272bSNaresh Solanki 		return res;
316*0f33272bSNaresh Solanki 	case hwmon_temp_fault:
317*0f33272bSNaresh Solanki 		res = max6639_temp_read_fault(dev, channel, val);
318*0f33272bSNaresh Solanki 		return res;
319*0f33272bSNaresh Solanki 	case hwmon_temp_max:
320*0f33272bSNaresh Solanki 		res = max6639_temp_read_max(dev, channel, val);
321*0f33272bSNaresh Solanki 		return res;
322*0f33272bSNaresh Solanki 	case hwmon_temp_crit:
323*0f33272bSNaresh Solanki 		res = max6639_temp_read_crit(dev, channel, val);
324*0f33272bSNaresh Solanki 		return res;
325*0f33272bSNaresh Solanki 	case hwmon_temp_emergency:
326*0f33272bSNaresh Solanki 		res = max6639_temp_read_emergency(dev, channel, val);
327*0f33272bSNaresh Solanki 		return res;
328*0f33272bSNaresh Solanki 	case hwmon_temp_max_alarm:
329*0f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
330*0f33272bSNaresh Solanki 		if (res < 0)
331*0f33272bSNaresh Solanki 			return res;
332*0f33272bSNaresh Solanki 		*val = !!(status & BIT(3 - channel));
333*0f33272bSNaresh Solanki 		return 0;
334*0f33272bSNaresh Solanki 	case hwmon_temp_crit_alarm:
335*0f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
336*0f33272bSNaresh Solanki 		if (res < 0)
337*0f33272bSNaresh Solanki 			return res;
338*0f33272bSNaresh Solanki 		*val = !!(status & BIT(7 - channel));
339*0f33272bSNaresh Solanki 		return 0;
340*0f33272bSNaresh Solanki 	case hwmon_temp_emergency_alarm:
341*0f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
342*0f33272bSNaresh Solanki 		if (res < 0)
343*0f33272bSNaresh Solanki 			return res;
344*0f33272bSNaresh Solanki 		*val = !!(status & BIT(5 - channel));
345*0f33272bSNaresh Solanki 		return 0;
346*0f33272bSNaresh Solanki 	default:
347*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
348*0f33272bSNaresh Solanki 	}
349*0f33272bSNaresh Solanki }
350*0f33272bSNaresh Solanki 
351*0f33272bSNaresh Solanki static int max6639_write_temp(struct device *dev, u32 attr, int channel,
352*0f33272bSNaresh Solanki 			      long val)
353*0f33272bSNaresh Solanki {
354*0f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
355*0f33272bSNaresh Solanki 
356*0f33272bSNaresh Solanki 	switch (attr) {
357*0f33272bSNaresh Solanki 	case hwmon_temp_max:
358*0f33272bSNaresh Solanki 		return max6639_temp_set_max(data, channel, val);
359*0f33272bSNaresh Solanki 	case hwmon_temp_crit:
360*0f33272bSNaresh Solanki 		return max6639_temp_set_crit(data, channel, val);
361*0f33272bSNaresh Solanki 	case hwmon_temp_emergency:
362*0f33272bSNaresh Solanki 		return max6639_temp_set_emergency(data, channel, val);
363*0f33272bSNaresh Solanki 	default:
364*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
365*0f33272bSNaresh Solanki 	}
366*0f33272bSNaresh Solanki }
367*0f33272bSNaresh Solanki 
368*0f33272bSNaresh Solanki static umode_t max6639_temp_is_visible(const void *_data, u32 attr, int channel)
369*0f33272bSNaresh Solanki {
370*0f33272bSNaresh Solanki 	switch (attr) {
371*0f33272bSNaresh Solanki 	case hwmon_temp_input:
372*0f33272bSNaresh Solanki 	case hwmon_temp_fault:
373*0f33272bSNaresh Solanki 	case hwmon_temp_max_alarm:
374*0f33272bSNaresh Solanki 	case hwmon_temp_crit_alarm:
375*0f33272bSNaresh Solanki 	case hwmon_temp_emergency_alarm:
376*0f33272bSNaresh Solanki 		return 0444;
377*0f33272bSNaresh Solanki 	case hwmon_temp_max:
378*0f33272bSNaresh Solanki 	case hwmon_temp_crit:
379*0f33272bSNaresh Solanki 	case hwmon_temp_emergency:
380*0f33272bSNaresh Solanki 		return 0644;
381*0f33272bSNaresh Solanki 	default:
382*0f33272bSNaresh Solanki 		return 0;
383*0f33272bSNaresh Solanki 	}
384*0f33272bSNaresh Solanki }
385*0f33272bSNaresh Solanki 
386*0f33272bSNaresh Solanki static int max6639_read(struct device *dev, enum hwmon_sensor_types type,
387*0f33272bSNaresh Solanki 			u32 attr, int channel, long *val)
388*0f33272bSNaresh Solanki {
389*0f33272bSNaresh Solanki 	switch (type) {
390*0f33272bSNaresh Solanki 	case hwmon_fan:
391*0f33272bSNaresh Solanki 		return max6639_read_fan(dev, attr, channel, val);
392*0f33272bSNaresh Solanki 	case hwmon_pwm:
393*0f33272bSNaresh Solanki 		return max6639_read_pwm(dev, attr, channel, val);
394*0f33272bSNaresh Solanki 	case hwmon_temp:
395*0f33272bSNaresh Solanki 		return max6639_read_temp(dev, attr, channel, val);
396*0f33272bSNaresh Solanki 	default:
397*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
398*0f33272bSNaresh Solanki 	}
399*0f33272bSNaresh Solanki }
400*0f33272bSNaresh Solanki 
401*0f33272bSNaresh Solanki static int max6639_write(struct device *dev, enum hwmon_sensor_types type,
402*0f33272bSNaresh Solanki 			 u32 attr, int channel, long val)
403*0f33272bSNaresh Solanki {
404*0f33272bSNaresh Solanki 	switch (type) {
405*0f33272bSNaresh Solanki 	case hwmon_pwm:
406*0f33272bSNaresh Solanki 		return max6639_write_pwm(dev, attr, channel, val);
407*0f33272bSNaresh Solanki 	case hwmon_temp:
408*0f33272bSNaresh Solanki 		return max6639_write_temp(dev, attr, channel, val);
409*0f33272bSNaresh Solanki 	default:
410*0f33272bSNaresh Solanki 		return -EOPNOTSUPP;
411*0f33272bSNaresh Solanki 	}
412*0f33272bSNaresh Solanki }
413*0f33272bSNaresh Solanki 
414*0f33272bSNaresh Solanki static umode_t max6639_is_visible(const void *data,
415*0f33272bSNaresh Solanki 				  enum hwmon_sensor_types type,
416*0f33272bSNaresh Solanki 				  u32 attr, int channel)
417*0f33272bSNaresh Solanki {
418*0f33272bSNaresh Solanki 	switch (type) {
419*0f33272bSNaresh Solanki 	case hwmon_fan:
420*0f33272bSNaresh Solanki 		return max6639_fan_is_visible(data, attr, channel);
421*0f33272bSNaresh Solanki 	case hwmon_pwm:
422*0f33272bSNaresh Solanki 		return max6639_pwm_is_visible(data, attr, channel);
423*0f33272bSNaresh Solanki 	case hwmon_temp:
424*0f33272bSNaresh Solanki 		return max6639_temp_is_visible(data, attr, channel);
425*0f33272bSNaresh Solanki 	default:
426*0f33272bSNaresh Solanki 		return 0;
427*0f33272bSNaresh Solanki 	}
428*0f33272bSNaresh Solanki }
429*0f33272bSNaresh Solanki 
430*0f33272bSNaresh Solanki static const struct hwmon_channel_info * const max6639_info[] = {
431*0f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(fan,
432*0f33272bSNaresh Solanki 			   HWMON_F_INPUT | HWMON_F_FAULT,
433*0f33272bSNaresh Solanki 			   HWMON_F_INPUT | HWMON_F_FAULT),
434*0f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(pwm,
435*0f33272bSNaresh Solanki 			   HWMON_PWM_INPUT,
436*0f33272bSNaresh Solanki 			   HWMON_PWM_INPUT),
437*0f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(temp,
438*0f33272bSNaresh Solanki 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM |
439*0f33272bSNaresh Solanki 			   HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY |
440*0f33272bSNaresh Solanki 			   HWMON_T_EMERGENCY_ALARM,
441*0f33272bSNaresh Solanki 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM |
442*0f33272bSNaresh Solanki 			   HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY |
443*0f33272bSNaresh Solanki 			   HWMON_T_EMERGENCY_ALARM),
444a5b79d62Sstigge@antcom.de 	NULL
445a5b79d62Sstigge@antcom.de };
446*0f33272bSNaresh Solanki 
447*0f33272bSNaresh Solanki static const struct hwmon_ops max6639_hwmon_ops = {
448*0f33272bSNaresh Solanki 	.is_visible = max6639_is_visible,
449*0f33272bSNaresh Solanki 	.read = max6639_read,
450*0f33272bSNaresh Solanki 	.write = max6639_write,
451*0f33272bSNaresh Solanki };
452*0f33272bSNaresh Solanki 
453*0f33272bSNaresh Solanki static const struct hwmon_chip_info max6639_chip_info = {
454*0f33272bSNaresh Solanki 	.ops = &max6639_hwmon_ops,
455*0f33272bSNaresh Solanki 	.info = max6639_info,
456*0f33272bSNaresh Solanki };
457a5b79d62Sstigge@antcom.de 
458a5b79d62Sstigge@antcom.de /*
459a5b79d62Sstigge@antcom.de  *  returns respective index in rpm_ranges table
460a5b79d62Sstigge@antcom.de  *  1 by default on invalid range
461a5b79d62Sstigge@antcom.de  */
462a5b79d62Sstigge@antcom.de static int rpm_range_to_reg(int range)
463a5b79d62Sstigge@antcom.de {
464a5b79d62Sstigge@antcom.de 	int i;
465a5b79d62Sstigge@antcom.de 
466a5b79d62Sstigge@antcom.de 	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
467a5b79d62Sstigge@antcom.de 		if (rpm_ranges[i] == range)
468a5b79d62Sstigge@antcom.de 			return i;
469a5b79d62Sstigge@antcom.de 	}
470a5b79d62Sstigge@antcom.de 
471a5b79d62Sstigge@antcom.de 	return 1; /* default: 4000 RPM */
472a5b79d62Sstigge@antcom.de }
473a5b79d62Sstigge@antcom.de 
4747981c584SGuenter Roeck static int max6639_init_client(struct i2c_client *client,
4757981c584SGuenter Roeck 			       struct max6639_data *data)
476a5b79d62Sstigge@antcom.de {
477a5b79d62Sstigge@antcom.de 	struct max6639_platform_data *max6639_info =
478a8b3a3a5SJingoo Han 		dev_get_platdata(&client->dev);
4792f2da1acSChris D Schimp 	int i;
480a5b79d62Sstigge@antcom.de 	int rpm_range = 1; /* default: 4000 RPM */
48145bf8305SNaresh Solanki 	int err, ppr;
482a5b79d62Sstigge@antcom.de 
483177f3b92Sstigge@antcom.de 	/* Reset chip to default values, see below for GCONFIG setup */
48445bf8305SNaresh Solanki 	err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR);
485a5b79d62Sstigge@antcom.de 	if (err)
48645bf8305SNaresh Solanki 		return err;
487a5b79d62Sstigge@antcom.de 
488a5b79d62Sstigge@antcom.de 	/* Fans pulse per revolution is 2 by default */
489a5b79d62Sstigge@antcom.de 	if (max6639_info && max6639_info->ppr > 0 &&
490a5b79d62Sstigge@antcom.de 			max6639_info->ppr < 5)
49145bf8305SNaresh Solanki 		ppr = max6639_info->ppr;
492a5b79d62Sstigge@antcom.de 	else
49345bf8305SNaresh Solanki 		ppr = 2;
494*0f33272bSNaresh Solanki 
495*0f33272bSNaresh Solanki 	data->ppr[0] = ppr;
496*0f33272bSNaresh Solanki 	data->ppr[1] = ppr;
497a5b79d62Sstigge@antcom.de 
498a5b79d62Sstigge@antcom.de 	if (max6639_info)
499a5b79d62Sstigge@antcom.de 		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
500*0f33272bSNaresh Solanki 	data->rpm_range[0] = rpm_range;
501*0f33272bSNaresh Solanki 	data->rpm_range[1] = rpm_range;
502a5b79d62Sstigge@antcom.de 
50345bf8305SNaresh Solanki 	for (i = 0; i < MAX6639_NUM_CHANNELS; i++) {
5042f2da1acSChris D Schimp 		/* Set Fan pulse per revolution */
505*0f33272bSNaresh Solanki 		err = max6639_set_ppr(data, i, data->ppr[i]);
5062f2da1acSChris D Schimp 		if (err)
50745bf8305SNaresh Solanki 			return err;
5082f2da1acSChris D Schimp 
509a5b79d62Sstigge@antcom.de 		/* Fans config PWM, RPM */
51045bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i),
511*0f33272bSNaresh Solanki 				   MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]);
512a5b79d62Sstigge@antcom.de 		if (err)
51345bf8305SNaresh Solanki 			return err;
514a5b79d62Sstigge@antcom.de 
515a5b79d62Sstigge@antcom.de 		/* Fans PWM polarity high by default */
516*0f33272bSNaresh Solanki 		if (max6639_info) {
517*0f33272bSNaresh Solanki 			if (max6639_info->pwm_polarity == 0)
51845bf8305SNaresh Solanki 				err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
519a5b79d62Sstigge@antcom.de 			else
52045bf8305SNaresh Solanki 				err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
521*0f33272bSNaresh Solanki 		}
522a5b79d62Sstigge@antcom.de 		if (err)
52345bf8305SNaresh Solanki 			return err;
524a5b79d62Sstigge@antcom.de 
525177f3b92Sstigge@antcom.de 		/*
526177f3b92Sstigge@antcom.de 		 * /THERM full speed enable,
527177f3b92Sstigge@antcom.de 		 * PWM frequency 25kHz, see also GCONFIG below
528177f3b92Sstigge@antcom.de 		 */
52945bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i),
530177f3b92Sstigge@antcom.de 				   MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
531177f3b92Sstigge@antcom.de 		if (err)
53245bf8305SNaresh Solanki 			return err;
533177f3b92Sstigge@antcom.de 
534a5b79d62Sstigge@antcom.de 		/* Max. temp. 80C/90C/100C */
53545bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80);
536a5b79d62Sstigge@antcom.de 		if (err)
53745bf8305SNaresh Solanki 			return err;
53845bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90);
539a5b79d62Sstigge@antcom.de 		if (err)
54045bf8305SNaresh Solanki 			return err;
54145bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100);
542a5b79d62Sstigge@antcom.de 		if (err)
54345bf8305SNaresh Solanki 			return err;
544a5b79d62Sstigge@antcom.de 
545a5b79d62Sstigge@antcom.de 		/* PWM 120/120 (i.e. 100%) */
54645bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120);
547a5b79d62Sstigge@antcom.de 		if (err)
54845bf8305SNaresh Solanki 			return err;
549a5b79d62Sstigge@antcom.de 	}
550a5b79d62Sstigge@antcom.de 	/* Start monitoring */
55145bf8305SNaresh Solanki 	return regmap_write(data->regmap, MAX6639_REG_GCONFIG,
552177f3b92Sstigge@antcom.de 			    MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
553177f3b92Sstigge@antcom.de 			    MAX6639_GCONFIG_PWM_FREQ_HI);
55445bf8305SNaresh Solanki 
555a5b79d62Sstigge@antcom.de }
556a5b79d62Sstigge@antcom.de 
557a5b79d62Sstigge@antcom.de /* Return 0 if detection is successful, -ENODEV otherwise */
558a5b79d62Sstigge@antcom.de static int max6639_detect(struct i2c_client *client,
559a5b79d62Sstigge@antcom.de 			  struct i2c_board_info *info)
560a5b79d62Sstigge@antcom.de {
561a5b79d62Sstigge@antcom.de 	struct i2c_adapter *adapter = client->adapter;
562a5b79d62Sstigge@antcom.de 	int dev_id, manu_id;
563a5b79d62Sstigge@antcom.de 
564a5b79d62Sstigge@antcom.de 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
565a5b79d62Sstigge@antcom.de 		return -ENODEV;
566a5b79d62Sstigge@antcom.de 
567a5b79d62Sstigge@antcom.de 	/* Actual detection via device and manufacturer ID */
568a5b79d62Sstigge@antcom.de 	dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID);
569a5b79d62Sstigge@antcom.de 	manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID);
570a5b79d62Sstigge@antcom.de 	if (dev_id != 0x58 || manu_id != 0x4D)
571a5b79d62Sstigge@antcom.de 		return -ENODEV;
572a5b79d62Sstigge@antcom.de 
573f2f394dbSWolfram Sang 	strscpy(info->type, "max6639", I2C_NAME_SIZE);
574a5b79d62Sstigge@antcom.de 
575a5b79d62Sstigge@antcom.de 	return 0;
576a5b79d62Sstigge@antcom.de }
577a5b79d62Sstigge@antcom.de 
5784e2271eaSMarcello Sylvester Bauer static void max6639_regulator_disable(void *data)
5794e2271eaSMarcello Sylvester Bauer {
5804e2271eaSMarcello Sylvester Bauer 	regulator_disable(data);
5814e2271eaSMarcello Sylvester Bauer }
5824e2271eaSMarcello Sylvester Bauer 
58345bf8305SNaresh Solanki static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg)
58445bf8305SNaresh Solanki {
58545bf8305SNaresh Solanki 	switch (reg) {
58645bf8305SNaresh Solanki 	case MAX6639_REG_TEMP(0):
58745bf8305SNaresh Solanki 	case MAX6639_REG_TEMP_EXT(0):
58845bf8305SNaresh Solanki 	case MAX6639_REG_TEMP(1):
58945bf8305SNaresh Solanki 	case MAX6639_REG_TEMP_EXT(1):
59045bf8305SNaresh Solanki 	case MAX6639_REG_STATUS:
59145bf8305SNaresh Solanki 	case MAX6639_REG_FAN_CNT(0):
59245bf8305SNaresh Solanki 	case MAX6639_REG_FAN_CNT(1):
59345bf8305SNaresh Solanki 	case MAX6639_REG_TARGTDUTY(0):
59445bf8305SNaresh Solanki 	case MAX6639_REG_TARGTDUTY(1):
59545bf8305SNaresh Solanki 		return true;
59645bf8305SNaresh Solanki 	default:
59745bf8305SNaresh Solanki 		return false;
59845bf8305SNaresh Solanki 	}
59945bf8305SNaresh Solanki }
60045bf8305SNaresh Solanki 
60145bf8305SNaresh Solanki static const struct regmap_config max6639_regmap_config = {
60245bf8305SNaresh Solanki 	.reg_bits = 8,
60345bf8305SNaresh Solanki 	.val_bits = 8,
60445bf8305SNaresh Solanki 	.max_register = MAX6639_REG_DEVREV,
60545bf8305SNaresh Solanki 	.cache_type = REGCACHE_MAPLE,
60645bf8305SNaresh Solanki 	.volatile_reg = max6639_regmap_is_volatile,
60745bf8305SNaresh Solanki };
60845bf8305SNaresh Solanki 
60967487038SStephen Kitt static int max6639_probe(struct i2c_client *client)
610a5b79d62Sstigge@antcom.de {
611c1ea0a04SGuenter Roeck 	struct device *dev = &client->dev;
612a5b79d62Sstigge@antcom.de 	struct max6639_data *data;
6137981c584SGuenter Roeck 	struct device *hwmon_dev;
614a5b79d62Sstigge@antcom.de 	int err;
615a5b79d62Sstigge@antcom.de 
616c1ea0a04SGuenter Roeck 	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
617b07405fbSGuenter Roeck 	if (!data)
618b07405fbSGuenter Roeck 		return -ENOMEM;
619a5b79d62Sstigge@antcom.de 
62045bf8305SNaresh Solanki 	data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config);
62145bf8305SNaresh Solanki 	if (IS_ERR(data->regmap))
62245bf8305SNaresh Solanki 		return dev_err_probe(dev,
62345bf8305SNaresh Solanki 				     PTR_ERR(data->regmap),
62445bf8305SNaresh Solanki 				     "regmap initialization failed\n");
6254e2271eaSMarcello Sylvester Bauer 
6264e2271eaSMarcello Sylvester Bauer 	data->reg = devm_regulator_get_optional(dev, "fan");
6274e2271eaSMarcello Sylvester Bauer 	if (IS_ERR(data->reg)) {
6284e2271eaSMarcello Sylvester Bauer 		if (PTR_ERR(data->reg) != -ENODEV)
6294e2271eaSMarcello Sylvester Bauer 			return PTR_ERR(data->reg);
6304e2271eaSMarcello Sylvester Bauer 
6314e2271eaSMarcello Sylvester Bauer 		data->reg = NULL;
6324e2271eaSMarcello Sylvester Bauer 	} else {
6334e2271eaSMarcello Sylvester Bauer 		/* Spin up fans */
6344e2271eaSMarcello Sylvester Bauer 		err = regulator_enable(data->reg);
6354e2271eaSMarcello Sylvester Bauer 		if (err) {
6364e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to enable fan supply: %d\n", err);
6374e2271eaSMarcello Sylvester Bauer 			return err;
6384e2271eaSMarcello Sylvester Bauer 		}
6394e2271eaSMarcello Sylvester Bauer 		err = devm_add_action_or_reset(dev, max6639_regulator_disable,
6404e2271eaSMarcello Sylvester Bauer 					       data->reg);
6414e2271eaSMarcello Sylvester Bauer 		if (err) {
6424e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to register action: %d\n", err);
6434e2271eaSMarcello Sylvester Bauer 			return err;
6444e2271eaSMarcello Sylvester Bauer 		}
6454e2271eaSMarcello Sylvester Bauer 	}
6464e2271eaSMarcello Sylvester Bauer 
647a5b79d62Sstigge@antcom.de 	/* Initialize the max6639 chip */
6487981c584SGuenter Roeck 	err = max6639_init_client(client, data);
649a5b79d62Sstigge@antcom.de 	if (err < 0)
650b07405fbSGuenter Roeck 		return err;
651a5b79d62Sstigge@antcom.de 
652*0f33272bSNaresh Solanki 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
653*0f33272bSNaresh Solanki 							 data, &max6639_chip_info,
654*0f33272bSNaresh Solanki 							 NULL);
655*0f33272bSNaresh Solanki 
6567981c584SGuenter Roeck 	return PTR_ERR_OR_ZERO(hwmon_dev);
657a5b79d62Sstigge@antcom.de }
658a5b79d62Sstigge@antcom.de 
65952f30f77SMark Brown static int max6639_suspend(struct device *dev)
660a5b79d62Sstigge@antcom.de {
6614e2271eaSMarcello Sylvester Bauer 	struct max6639_data *data = dev_get_drvdata(dev);
6624e2271eaSMarcello Sylvester Bauer 
6634e2271eaSMarcello Sylvester Bauer 	if (data->reg)
6644e2271eaSMarcello Sylvester Bauer 		regulator_disable(data->reg);
665a5b79d62Sstigge@antcom.de 
66645bf8305SNaresh Solanki 	return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
66745bf8305SNaresh Solanki 				 MAX6639_GCONFIG_STANDBY);
668a5b79d62Sstigge@antcom.de }
669a5b79d62Sstigge@antcom.de 
67052f30f77SMark Brown static int max6639_resume(struct device *dev)
671a5b79d62Sstigge@antcom.de {
6724e2271eaSMarcello Sylvester Bauer 	struct max6639_data *data = dev_get_drvdata(dev);
6734e2271eaSMarcello Sylvester Bauer 	int ret;
6744e2271eaSMarcello Sylvester Bauer 
6754e2271eaSMarcello Sylvester Bauer 	if (data->reg) {
6764e2271eaSMarcello Sylvester Bauer 		ret = regulator_enable(data->reg);
6774e2271eaSMarcello Sylvester Bauer 		if (ret) {
6784e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to enable fan supply: %d\n", ret);
6794e2271eaSMarcello Sylvester Bauer 			return ret;
6804e2271eaSMarcello Sylvester Bauer 		}
6814e2271eaSMarcello Sylvester Bauer 	}
6824e2271eaSMarcello Sylvester Bauer 
68345bf8305SNaresh Solanki 	return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
68445bf8305SNaresh Solanki 				 ~MAX6639_GCONFIG_STANDBY);
685a5b79d62Sstigge@antcom.de }
686a5b79d62Sstigge@antcom.de 
687a5b79d62Sstigge@antcom.de static const struct i2c_device_id max6639_id[] = {
688d8a66f36SUwe Kleine-König 	{"max6639"},
689a5b79d62Sstigge@antcom.de 	{ }
690a5b79d62Sstigge@antcom.de };
691a5b79d62Sstigge@antcom.de 
692a5b79d62Sstigge@antcom.de MODULE_DEVICE_TABLE(i2c, max6639_id);
693a5b79d62Sstigge@antcom.de 
69477563092SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
69552f30f77SMark Brown 
696f11e2738SNaresh Solanki static const struct of_device_id max6639_of_match[] = {
697f11e2738SNaresh Solanki 	{ .compatible = "maxim,max6639", },
698f11e2738SNaresh Solanki 	{ },
699f11e2738SNaresh Solanki };
700f11e2738SNaresh Solanki 
701a5b79d62Sstigge@antcom.de static struct i2c_driver max6639_driver = {
702a5b79d62Sstigge@antcom.de 	.class = I2C_CLASS_HWMON,
703a5b79d62Sstigge@antcom.de 	.driver = {
704a5b79d62Sstigge@antcom.de 		   .name = "max6639",
70577563092SJonathan Cameron 		   .pm = pm_sleep_ptr(&max6639_pm_ops),
706f11e2738SNaresh Solanki 		   .of_match_table = max6639_of_match,
707a5b79d62Sstigge@antcom.de 		   },
7081975d167SUwe Kleine-König 	.probe = max6639_probe,
709a5b79d62Sstigge@antcom.de 	.id_table = max6639_id,
710a5b79d62Sstigge@antcom.de 	.detect = max6639_detect,
711a5b79d62Sstigge@antcom.de 	.address_list = normal_i2c,
712a5b79d62Sstigge@antcom.de };
713a5b79d62Sstigge@antcom.de 
714f0967eeaSAxel Lin module_i2c_driver(max6639_driver);
715a5b79d62Sstigge@antcom.de 
716a5b79d62Sstigge@antcom.de MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
717a5b79d62Sstigge@antcom.de MODULE_DESCRIPTION("max6639 driver");
718a5b79d62Sstigge@antcom.de MODULE_LICENSE("GPL");
719