xref: /linux/drivers/hwmon/max6639.c (revision 842b4d98ae338522babab38347297f0932fa7afd)
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>
240f33272bSNaresh 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
590f33272bSNaresh 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 
660f33272bSNaresh Solanki /* Supported PWM frequency */
670f33272bSNaresh Solanki static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500,
680f33272bSNaresh Solanki 					   25000 };
690f33272bSNaresh 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;
79*842b4d98SNaresh Solanki 	struct mutex update_lock;
80a5b79d62Sstigge@antcom.de 
81a5b79d62Sstigge@antcom.de 	/* Register values initialized only once */
820f33272bSNaresh Solanki 	u8 ppr[MAX6639_NUM_CHANNELS];	/* Pulses per rotation 0..3 for 1..4 ppr */
830f33272bSNaresh Solanki 	u8 rpm_range[MAX6639_NUM_CHANNELS]; /* Index in above rpm_ranges table */
844e2271eaSMarcello Sylvester Bauer 
854e2271eaSMarcello Sylvester Bauer 	/* Optional regulator for FAN supply */
864e2271eaSMarcello Sylvester Bauer 	struct regulator *reg;
87a5b79d62Sstigge@antcom.de };
88a5b79d62Sstigge@antcom.de 
890f33272bSNaresh Solanki static int max6639_temp_read_input(struct device *dev, int channel, long *temp)
90a5b79d62Sstigge@antcom.de {
9145bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
9245bf8305SNaresh Solanki 	unsigned int val;
9345bf8305SNaresh Solanki 	int res;
94a5b79d62Sstigge@antcom.de 
9545bf8305SNaresh Solanki 	/*
9645bf8305SNaresh Solanki 	 * Lock isn't needed as MAX6639_REG_TEMP wpnt change for at least 250ms after reading
9745bf8305SNaresh Solanki 	 * MAX6639_REG_TEMP_EXT
9845bf8305SNaresh Solanki 	 */
990f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val);
10045bf8305SNaresh Solanki 	if (res < 0)
10145bf8305SNaresh Solanki 		return res;
102a5b79d62Sstigge@antcom.de 
1030f33272bSNaresh Solanki 	*temp = val >> 5;
1040f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP(channel), &val);
10545bf8305SNaresh Solanki 	if (res < 0)
10645bf8305SNaresh Solanki 		return res;
10745bf8305SNaresh Solanki 
1080f33272bSNaresh Solanki 	*temp |= val << 3;
1090f33272bSNaresh Solanki 	*temp *= 125;
11045bf8305SNaresh Solanki 
1110f33272bSNaresh Solanki 	return 0;
112a5b79d62Sstigge@antcom.de }
113a5b79d62Sstigge@antcom.de 
1140f33272bSNaresh Solanki static int max6639_temp_read_fault(struct device *dev, int channel, long *fault)
115a5b79d62Sstigge@antcom.de {
11645bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
11745bf8305SNaresh Solanki 	unsigned int val;
11845bf8305SNaresh Solanki 	int res;
119a5b79d62Sstigge@antcom.de 
1200f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val);
12145bf8305SNaresh Solanki 	if (res < 0)
12245bf8305SNaresh Solanki 		return res;
12345bf8305SNaresh Solanki 
1240f33272bSNaresh Solanki 	*fault = val & 1;
1250f33272bSNaresh Solanki 
1260f33272bSNaresh Solanki 	return 0;
127a5b79d62Sstigge@antcom.de }
128a5b79d62Sstigge@antcom.de 
1290f33272bSNaresh Solanki static int max6639_temp_read_max(struct device *dev, int channel, long *max)
130a5b79d62Sstigge@antcom.de {
1317981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
13245bf8305SNaresh Solanki 	unsigned int val;
13345bf8305SNaresh Solanki 	int res;
134a5b79d62Sstigge@antcom.de 
1350f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(channel), &val);
13645bf8305SNaresh Solanki 	if (res < 0)
13745bf8305SNaresh Solanki 		return res;
13845bf8305SNaresh Solanki 
1390f33272bSNaresh Solanki 	*max = (long)val * 1000;
1400f33272bSNaresh Solanki 
1410f33272bSNaresh Solanki 	return 0;
142a5b79d62Sstigge@antcom.de }
143a5b79d62Sstigge@antcom.de 
1440f33272bSNaresh Solanki static int max6639_temp_read_crit(struct device *dev, int channel, long *crit)
145a5b79d62Sstigge@antcom.de {
1467981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
14745bf8305SNaresh Solanki 	unsigned int val;
14845bf8305SNaresh Solanki 	int res;
149a5b79d62Sstigge@antcom.de 
1500f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), &val);
15145bf8305SNaresh Solanki 	if (res < 0)
15245bf8305SNaresh Solanki 		return res;
15345bf8305SNaresh Solanki 
1540f33272bSNaresh Solanki 	*crit = (long)val * 1000;
1550f33272bSNaresh Solanki 
1560f33272bSNaresh Solanki 	return 0;
157a5b79d62Sstigge@antcom.de }
158a5b79d62Sstigge@antcom.de 
1590f33272bSNaresh Solanki static int max6639_temp_read_emergency(struct device *dev, int channel, long *emerg)
160a5b79d62Sstigge@antcom.de {
1617981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
16245bf8305SNaresh Solanki 	unsigned int val;
16345bf8305SNaresh Solanki 	int res;
164a5b79d62Sstigge@antcom.de 
1650f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(channel), &val);
16645bf8305SNaresh Solanki 	if (res < 0)
16745bf8305SNaresh Solanki 		return res;
16845bf8305SNaresh Solanki 
1690f33272bSNaresh Solanki 	*emerg = (long)val * 1000;
1700f33272bSNaresh Solanki 
1710f33272bSNaresh Solanki 	return 0;
172a5b79d62Sstigge@antcom.de }
173a5b79d62Sstigge@antcom.de 
1740f33272bSNaresh Solanki static int max6639_get_status(struct device *dev, unsigned int *status)
175a5b79d62Sstigge@antcom.de {
17645bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
17745bf8305SNaresh Solanki 	unsigned int val;
17845bf8305SNaresh Solanki 	int res;
179a5b79d62Sstigge@antcom.de 
18045bf8305SNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val);
18145bf8305SNaresh Solanki 	if (res < 0)
18245bf8305SNaresh Solanki 		return res;
183a5b79d62Sstigge@antcom.de 
1840f33272bSNaresh Solanki 	*status = val;
1850f33272bSNaresh Solanki 
1860f33272bSNaresh Solanki 	return 0;
187a5b79d62Sstigge@antcom.de }
188a5b79d62Sstigge@antcom.de 
1890f33272bSNaresh Solanki static int max6639_temp_set_max(struct max6639_data *data, int channel, long val)
1900f33272bSNaresh Solanki {
1910f33272bSNaresh Solanki 	int res;
192a5b79d62Sstigge@antcom.de 
1930f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel),
1940f33272bSNaresh Solanki 			   TEMP_LIMIT_TO_REG(val));
1950f33272bSNaresh Solanki 	return res;
1960f33272bSNaresh Solanki }
197a5b79d62Sstigge@antcom.de 
1980f33272bSNaresh Solanki static int max6639_temp_set_crit(struct max6639_data *data, int channel, long val)
1990f33272bSNaresh Solanki {
2000f33272bSNaresh Solanki 	int res;
2010f33272bSNaresh Solanki 
2020f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
2030f33272bSNaresh Solanki 
2040f33272bSNaresh Solanki 	return res;
2050f33272bSNaresh Solanki }
2060f33272bSNaresh Solanki 
2070f33272bSNaresh Solanki static int max6639_temp_set_emergency(struct max6639_data *data, int channel, long val)
2080f33272bSNaresh Solanki {
2090f33272bSNaresh Solanki 	int res;
2100f33272bSNaresh Solanki 
2110f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
2120f33272bSNaresh Solanki 
2130f33272bSNaresh Solanki 	return res;
2140f33272bSNaresh Solanki }
2150f33272bSNaresh Solanki 
2160f33272bSNaresh Solanki static int max6639_read_fan(struct device *dev, u32 attr, int channel,
2170f33272bSNaresh Solanki 			    long *fan_val)
2180f33272bSNaresh Solanki {
2190f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
2200f33272bSNaresh Solanki 	unsigned int val;
2210f33272bSNaresh Solanki 	int res;
2220f33272bSNaresh Solanki 
2230f33272bSNaresh Solanki 	switch (attr) {
2240f33272bSNaresh Solanki 	case hwmon_fan_input:
2250f33272bSNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val);
2260f33272bSNaresh Solanki 		if (res < 0)
2270f33272bSNaresh Solanki 			return res;
2280f33272bSNaresh Solanki 		*fan_val = FAN_FROM_REG(val, data->rpm_range[channel]);
2290f33272bSNaresh Solanki 		return 0;
2300f33272bSNaresh Solanki 	case hwmon_fan_fault:
2310f33272bSNaresh Solanki 		res = max6639_get_status(dev, &val);
2320f33272bSNaresh Solanki 		if (res < 0)
2330f33272bSNaresh Solanki 			return res;
2340f33272bSNaresh Solanki 		*fan_val = !!(val & BIT(1 - channel));
2350f33272bSNaresh Solanki 		return 0;
236*842b4d98SNaresh Solanki 	case hwmon_fan_pulses:
237*842b4d98SNaresh Solanki 		*fan_val = data->ppr[channel];
238*842b4d98SNaresh Solanki 		return 0;
2390f33272bSNaresh Solanki 	default:
2400f33272bSNaresh Solanki 		return -EOPNOTSUPP;
2410f33272bSNaresh Solanki 	}
2420f33272bSNaresh Solanki }
2430f33272bSNaresh Solanki 
2440f33272bSNaresh Solanki static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr)
2450f33272bSNaresh Solanki {
2460f33272bSNaresh Solanki 	/* Decrement the PPR value and shift left by 6 to match the register format */
2470f33272bSNaresh Solanki 	return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6);
2480f33272bSNaresh Solanki }
2490f33272bSNaresh Solanki 
250*842b4d98SNaresh Solanki static int max6639_write_fan(struct device *dev, u32 attr, int channel,
251*842b4d98SNaresh Solanki 			     long val)
252*842b4d98SNaresh Solanki {
253*842b4d98SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
254*842b4d98SNaresh Solanki 	int err;
255*842b4d98SNaresh Solanki 
256*842b4d98SNaresh Solanki 	switch (attr) {
257*842b4d98SNaresh Solanki 	case hwmon_fan_pulses:
258*842b4d98SNaresh Solanki 		if (val <= 0 || val > 4)
259*842b4d98SNaresh Solanki 			return -EINVAL;
260*842b4d98SNaresh Solanki 
261*842b4d98SNaresh Solanki 		mutex_lock(&data->update_lock);
262*842b4d98SNaresh Solanki 		/* Set Fan pulse per revolution */
263*842b4d98SNaresh Solanki 		err = max6639_set_ppr(data, channel, val);
264*842b4d98SNaresh Solanki 		if (err < 0) {
265*842b4d98SNaresh Solanki 			mutex_unlock(&data->update_lock);
266*842b4d98SNaresh Solanki 			return err;
267*842b4d98SNaresh Solanki 		}
268*842b4d98SNaresh Solanki 		data->ppr[channel] = val;
269*842b4d98SNaresh Solanki 
270*842b4d98SNaresh Solanki 		mutex_unlock(&data->update_lock);
271*842b4d98SNaresh Solanki 		return 0;
272*842b4d98SNaresh Solanki 	default:
273*842b4d98SNaresh Solanki 		return -EOPNOTSUPP;
274*842b4d98SNaresh Solanki 	}
275*842b4d98SNaresh Solanki }
276*842b4d98SNaresh Solanki 
2770f33272bSNaresh Solanki static umode_t max6639_fan_is_visible(const void *_data, u32 attr, int channel)
2780f33272bSNaresh Solanki {
2790f33272bSNaresh Solanki 	switch (attr) {
2800f33272bSNaresh Solanki 	case hwmon_fan_input:
2810f33272bSNaresh Solanki 	case hwmon_fan_fault:
2820f33272bSNaresh Solanki 		return 0444;
2830f33272bSNaresh Solanki 	case hwmon_fan_pulses:
2840f33272bSNaresh Solanki 		return 0644;
2850f33272bSNaresh Solanki 	default:
2860f33272bSNaresh Solanki 		return 0;
2870f33272bSNaresh Solanki 	}
2880f33272bSNaresh Solanki }
2890f33272bSNaresh Solanki 
2900f33272bSNaresh Solanki static int max6639_read_pwm(struct device *dev, u32 attr, int channel,
2910f33272bSNaresh Solanki 			    long *pwm_val)
2920f33272bSNaresh Solanki {
2930f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
2940f33272bSNaresh Solanki 	unsigned int val;
2950f33272bSNaresh Solanki 	int res;
296*842b4d98SNaresh Solanki 	u8 i;
2970f33272bSNaresh Solanki 
2980f33272bSNaresh Solanki 	switch (attr) {
2990f33272bSNaresh Solanki 	case hwmon_pwm_input:
3000f33272bSNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(channel), &val);
3010f33272bSNaresh Solanki 		if (res < 0)
3020f33272bSNaresh Solanki 			return res;
3030f33272bSNaresh Solanki 		*pwm_val = val * 255 / 120;
3040f33272bSNaresh Solanki 		return 0;
305*842b4d98SNaresh Solanki 	case hwmon_pwm_freq:
306*842b4d98SNaresh Solanki 		mutex_lock(&data->update_lock);
307*842b4d98SNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG3(channel), &val);
308*842b4d98SNaresh Solanki 		if (res < 0) {
309*842b4d98SNaresh Solanki 			mutex_unlock(&data->update_lock);
310*842b4d98SNaresh Solanki 			return res;
311*842b4d98SNaresh Solanki 		}
312*842b4d98SNaresh Solanki 		i = val & MAX6639_FAN_CONFIG3_FREQ_MASK;
313*842b4d98SNaresh Solanki 
314*842b4d98SNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_GCONFIG, &val);
315*842b4d98SNaresh Solanki 		if (res < 0) {
316*842b4d98SNaresh Solanki 			mutex_unlock(&data->update_lock);
317*842b4d98SNaresh Solanki 			return res;
318*842b4d98SNaresh Solanki 		}
319*842b4d98SNaresh Solanki 
320*842b4d98SNaresh Solanki 		if (val & MAX6639_GCONFIG_PWM_FREQ_HI)
321*842b4d98SNaresh Solanki 			i |= 0x4;
322*842b4d98SNaresh Solanki 		i &= 0x7;
323*842b4d98SNaresh Solanki 		*pwm_val = freq_table[i];
324*842b4d98SNaresh Solanki 
325*842b4d98SNaresh Solanki 		mutex_unlock(&data->update_lock);
326*842b4d98SNaresh Solanki 		return 0;
3270f33272bSNaresh Solanki 	default:
3280f33272bSNaresh Solanki 		return -EOPNOTSUPP;
3290f33272bSNaresh Solanki 	}
3300f33272bSNaresh Solanki }
3310f33272bSNaresh Solanki 
3320f33272bSNaresh Solanki static int max6639_write_pwm(struct device *dev, u32 attr, int channel,
3330f33272bSNaresh Solanki 			     long val)
3340f33272bSNaresh Solanki {
3350f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
3360f33272bSNaresh Solanki 	int err;
337*842b4d98SNaresh Solanki 	u8 i;
3380f33272bSNaresh Solanki 
3390f33272bSNaresh Solanki 	switch (attr) {
3400f33272bSNaresh Solanki 	case hwmon_pwm_input:
3410f33272bSNaresh Solanki 		if (val < 0 || val > 255)
3420f33272bSNaresh Solanki 			return -EINVAL;
3430f33272bSNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel),
3440f33272bSNaresh Solanki 				   val * 120 / 255);
3450f33272bSNaresh Solanki 		return err;
346*842b4d98SNaresh Solanki 	case hwmon_pwm_freq:
347*842b4d98SNaresh Solanki 		val = clamp_val(val, 0, 25000);
348*842b4d98SNaresh Solanki 
349*842b4d98SNaresh Solanki 		i = find_closest(val, freq_table, ARRAY_SIZE(freq_table));
350*842b4d98SNaresh Solanki 
351*842b4d98SNaresh Solanki 		mutex_lock(&data->update_lock);
352*842b4d98SNaresh Solanki 		err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel),
353*842b4d98SNaresh Solanki 					 MAX6639_FAN_CONFIG3_FREQ_MASK, i);
354*842b4d98SNaresh Solanki 		if (err < 0) {
355*842b4d98SNaresh Solanki 			mutex_unlock(&data->update_lock);
356*842b4d98SNaresh Solanki 			return err;
357*842b4d98SNaresh Solanki 		}
358*842b4d98SNaresh Solanki 
359*842b4d98SNaresh Solanki 		if (i >> 2)
360*842b4d98SNaresh Solanki 			err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG,
361*842b4d98SNaresh Solanki 					      MAX6639_GCONFIG_PWM_FREQ_HI);
362*842b4d98SNaresh Solanki 		else
363*842b4d98SNaresh Solanki 			err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG,
364*842b4d98SNaresh Solanki 						MAX6639_GCONFIG_PWM_FREQ_HI);
365*842b4d98SNaresh Solanki 
366*842b4d98SNaresh Solanki 		mutex_unlock(&data->update_lock);
367*842b4d98SNaresh Solanki 		return err;
3680f33272bSNaresh Solanki 	default:
3690f33272bSNaresh Solanki 		return -EOPNOTSUPP;
3700f33272bSNaresh Solanki 	}
3710f33272bSNaresh Solanki }
3720f33272bSNaresh Solanki 
3730f33272bSNaresh Solanki static umode_t max6639_pwm_is_visible(const void *_data, u32 attr, int channel)
3740f33272bSNaresh Solanki {
3750f33272bSNaresh Solanki 	switch (attr) {
3760f33272bSNaresh Solanki 	case hwmon_pwm_input:
377*842b4d98SNaresh Solanki 	case hwmon_pwm_freq:
3780f33272bSNaresh Solanki 		return 0644;
3790f33272bSNaresh Solanki 	default:
3800f33272bSNaresh Solanki 		return 0;
3810f33272bSNaresh Solanki 	}
3820f33272bSNaresh Solanki }
3830f33272bSNaresh Solanki 
3840f33272bSNaresh Solanki static int max6639_read_temp(struct device *dev, u32 attr, int channel,
3850f33272bSNaresh Solanki 			     long *val)
3860f33272bSNaresh Solanki {
3870f33272bSNaresh Solanki 	unsigned int status;
3880f33272bSNaresh Solanki 	int res;
3890f33272bSNaresh Solanki 
3900f33272bSNaresh Solanki 	switch (attr) {
3910f33272bSNaresh Solanki 	case hwmon_temp_input:
3920f33272bSNaresh Solanki 		res = max6639_temp_read_input(dev, channel, val);
3930f33272bSNaresh Solanki 		return res;
3940f33272bSNaresh Solanki 	case hwmon_temp_fault:
3950f33272bSNaresh Solanki 		res = max6639_temp_read_fault(dev, channel, val);
3960f33272bSNaresh Solanki 		return res;
3970f33272bSNaresh Solanki 	case hwmon_temp_max:
3980f33272bSNaresh Solanki 		res = max6639_temp_read_max(dev, channel, val);
3990f33272bSNaresh Solanki 		return res;
4000f33272bSNaresh Solanki 	case hwmon_temp_crit:
4010f33272bSNaresh Solanki 		res = max6639_temp_read_crit(dev, channel, val);
4020f33272bSNaresh Solanki 		return res;
4030f33272bSNaresh Solanki 	case hwmon_temp_emergency:
4040f33272bSNaresh Solanki 		res = max6639_temp_read_emergency(dev, channel, val);
4050f33272bSNaresh Solanki 		return res;
4060f33272bSNaresh Solanki 	case hwmon_temp_max_alarm:
4070f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
4080f33272bSNaresh Solanki 		if (res < 0)
4090f33272bSNaresh Solanki 			return res;
4100f33272bSNaresh Solanki 		*val = !!(status & BIT(3 - channel));
4110f33272bSNaresh Solanki 		return 0;
4120f33272bSNaresh Solanki 	case hwmon_temp_crit_alarm:
4130f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
4140f33272bSNaresh Solanki 		if (res < 0)
4150f33272bSNaresh Solanki 			return res;
4160f33272bSNaresh Solanki 		*val = !!(status & BIT(7 - channel));
4170f33272bSNaresh Solanki 		return 0;
4180f33272bSNaresh Solanki 	case hwmon_temp_emergency_alarm:
4190f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
4200f33272bSNaresh Solanki 		if (res < 0)
4210f33272bSNaresh Solanki 			return res;
4220f33272bSNaresh Solanki 		*val = !!(status & BIT(5 - channel));
4230f33272bSNaresh Solanki 		return 0;
4240f33272bSNaresh Solanki 	default:
4250f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4260f33272bSNaresh Solanki 	}
4270f33272bSNaresh Solanki }
4280f33272bSNaresh Solanki 
4290f33272bSNaresh Solanki static int max6639_write_temp(struct device *dev, u32 attr, int channel,
4300f33272bSNaresh Solanki 			      long val)
4310f33272bSNaresh Solanki {
4320f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
4330f33272bSNaresh Solanki 
4340f33272bSNaresh Solanki 	switch (attr) {
4350f33272bSNaresh Solanki 	case hwmon_temp_max:
4360f33272bSNaresh Solanki 		return max6639_temp_set_max(data, channel, val);
4370f33272bSNaresh Solanki 	case hwmon_temp_crit:
4380f33272bSNaresh Solanki 		return max6639_temp_set_crit(data, channel, val);
4390f33272bSNaresh Solanki 	case hwmon_temp_emergency:
4400f33272bSNaresh Solanki 		return max6639_temp_set_emergency(data, channel, val);
4410f33272bSNaresh Solanki 	default:
4420f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4430f33272bSNaresh Solanki 	}
4440f33272bSNaresh Solanki }
4450f33272bSNaresh Solanki 
4460f33272bSNaresh Solanki static umode_t max6639_temp_is_visible(const void *_data, u32 attr, int channel)
4470f33272bSNaresh Solanki {
4480f33272bSNaresh Solanki 	switch (attr) {
4490f33272bSNaresh Solanki 	case hwmon_temp_input:
4500f33272bSNaresh Solanki 	case hwmon_temp_fault:
4510f33272bSNaresh Solanki 	case hwmon_temp_max_alarm:
4520f33272bSNaresh Solanki 	case hwmon_temp_crit_alarm:
4530f33272bSNaresh Solanki 	case hwmon_temp_emergency_alarm:
4540f33272bSNaresh Solanki 		return 0444;
4550f33272bSNaresh Solanki 	case hwmon_temp_max:
4560f33272bSNaresh Solanki 	case hwmon_temp_crit:
4570f33272bSNaresh Solanki 	case hwmon_temp_emergency:
4580f33272bSNaresh Solanki 		return 0644;
4590f33272bSNaresh Solanki 	default:
4600f33272bSNaresh Solanki 		return 0;
4610f33272bSNaresh Solanki 	}
4620f33272bSNaresh Solanki }
4630f33272bSNaresh Solanki 
4640f33272bSNaresh Solanki static int max6639_read(struct device *dev, enum hwmon_sensor_types type,
4650f33272bSNaresh Solanki 			u32 attr, int channel, long *val)
4660f33272bSNaresh Solanki {
4670f33272bSNaresh Solanki 	switch (type) {
4680f33272bSNaresh Solanki 	case hwmon_fan:
4690f33272bSNaresh Solanki 		return max6639_read_fan(dev, attr, channel, val);
4700f33272bSNaresh Solanki 	case hwmon_pwm:
4710f33272bSNaresh Solanki 		return max6639_read_pwm(dev, attr, channel, val);
4720f33272bSNaresh Solanki 	case hwmon_temp:
4730f33272bSNaresh Solanki 		return max6639_read_temp(dev, attr, channel, val);
4740f33272bSNaresh Solanki 	default:
4750f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4760f33272bSNaresh Solanki 	}
4770f33272bSNaresh Solanki }
4780f33272bSNaresh Solanki 
4790f33272bSNaresh Solanki static int max6639_write(struct device *dev, enum hwmon_sensor_types type,
4800f33272bSNaresh Solanki 			 u32 attr, int channel, long val)
4810f33272bSNaresh Solanki {
4820f33272bSNaresh Solanki 	switch (type) {
483*842b4d98SNaresh Solanki 	case hwmon_fan:
484*842b4d98SNaresh Solanki 		return max6639_write_fan(dev, attr, channel, val);
4850f33272bSNaresh Solanki 	case hwmon_pwm:
4860f33272bSNaresh Solanki 		return max6639_write_pwm(dev, attr, channel, val);
4870f33272bSNaresh Solanki 	case hwmon_temp:
4880f33272bSNaresh Solanki 		return max6639_write_temp(dev, attr, channel, val);
4890f33272bSNaresh Solanki 	default:
4900f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4910f33272bSNaresh Solanki 	}
4920f33272bSNaresh Solanki }
4930f33272bSNaresh Solanki 
4940f33272bSNaresh Solanki static umode_t max6639_is_visible(const void *data,
4950f33272bSNaresh Solanki 				  enum hwmon_sensor_types type,
4960f33272bSNaresh Solanki 				  u32 attr, int channel)
4970f33272bSNaresh Solanki {
4980f33272bSNaresh Solanki 	switch (type) {
4990f33272bSNaresh Solanki 	case hwmon_fan:
5000f33272bSNaresh Solanki 		return max6639_fan_is_visible(data, attr, channel);
5010f33272bSNaresh Solanki 	case hwmon_pwm:
5020f33272bSNaresh Solanki 		return max6639_pwm_is_visible(data, attr, channel);
5030f33272bSNaresh Solanki 	case hwmon_temp:
5040f33272bSNaresh Solanki 		return max6639_temp_is_visible(data, attr, channel);
5050f33272bSNaresh Solanki 	default:
5060f33272bSNaresh Solanki 		return 0;
5070f33272bSNaresh Solanki 	}
5080f33272bSNaresh Solanki }
5090f33272bSNaresh Solanki 
5100f33272bSNaresh Solanki static const struct hwmon_channel_info * const max6639_info[] = {
5110f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(fan,
512*842b4d98SNaresh Solanki 			   HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES,
513*842b4d98SNaresh Solanki 			   HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES),
5140f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(pwm,
515*842b4d98SNaresh Solanki 			   HWMON_PWM_INPUT | HWMON_PWM_FREQ,
516*842b4d98SNaresh Solanki 			   HWMON_PWM_INPUT | HWMON_PWM_FREQ),
5170f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(temp,
5180f33272bSNaresh Solanki 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM |
5190f33272bSNaresh Solanki 			   HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY |
5200f33272bSNaresh Solanki 			   HWMON_T_EMERGENCY_ALARM,
5210f33272bSNaresh Solanki 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM |
5220f33272bSNaresh Solanki 			   HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY |
5230f33272bSNaresh Solanki 			   HWMON_T_EMERGENCY_ALARM),
524a5b79d62Sstigge@antcom.de 	NULL
525a5b79d62Sstigge@antcom.de };
5260f33272bSNaresh Solanki 
5270f33272bSNaresh Solanki static const struct hwmon_ops max6639_hwmon_ops = {
5280f33272bSNaresh Solanki 	.is_visible = max6639_is_visible,
5290f33272bSNaresh Solanki 	.read = max6639_read,
5300f33272bSNaresh Solanki 	.write = max6639_write,
5310f33272bSNaresh Solanki };
5320f33272bSNaresh Solanki 
5330f33272bSNaresh Solanki static const struct hwmon_chip_info max6639_chip_info = {
5340f33272bSNaresh Solanki 	.ops = &max6639_hwmon_ops,
5350f33272bSNaresh Solanki 	.info = max6639_info,
5360f33272bSNaresh Solanki };
537a5b79d62Sstigge@antcom.de 
538a5b79d62Sstigge@antcom.de /*
539a5b79d62Sstigge@antcom.de  *  returns respective index in rpm_ranges table
540a5b79d62Sstigge@antcom.de  *  1 by default on invalid range
541a5b79d62Sstigge@antcom.de  */
542a5b79d62Sstigge@antcom.de static int rpm_range_to_reg(int range)
543a5b79d62Sstigge@antcom.de {
544a5b79d62Sstigge@antcom.de 	int i;
545a5b79d62Sstigge@antcom.de 
546a5b79d62Sstigge@antcom.de 	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
547a5b79d62Sstigge@antcom.de 		if (rpm_ranges[i] == range)
548a5b79d62Sstigge@antcom.de 			return i;
549a5b79d62Sstigge@antcom.de 	}
550a5b79d62Sstigge@antcom.de 
551a5b79d62Sstigge@antcom.de 	return 1; /* default: 4000 RPM */
552a5b79d62Sstigge@antcom.de }
553a5b79d62Sstigge@antcom.de 
5547981c584SGuenter Roeck static int max6639_init_client(struct i2c_client *client,
5557981c584SGuenter Roeck 			       struct max6639_data *data)
556a5b79d62Sstigge@antcom.de {
557a5b79d62Sstigge@antcom.de 	struct max6639_platform_data *max6639_info =
558a8b3a3a5SJingoo Han 		dev_get_platdata(&client->dev);
5592f2da1acSChris D Schimp 	int i;
560a5b79d62Sstigge@antcom.de 	int rpm_range = 1; /* default: 4000 RPM */
56145bf8305SNaresh Solanki 	int err, ppr;
562a5b79d62Sstigge@antcom.de 
563177f3b92Sstigge@antcom.de 	/* Reset chip to default values, see below for GCONFIG setup */
56445bf8305SNaresh Solanki 	err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR);
565a5b79d62Sstigge@antcom.de 	if (err)
56645bf8305SNaresh Solanki 		return err;
567a5b79d62Sstigge@antcom.de 
568a5b79d62Sstigge@antcom.de 	/* Fans pulse per revolution is 2 by default */
569a5b79d62Sstigge@antcom.de 	if (max6639_info && max6639_info->ppr > 0 &&
570a5b79d62Sstigge@antcom.de 			max6639_info->ppr < 5)
57145bf8305SNaresh Solanki 		ppr = max6639_info->ppr;
572a5b79d62Sstigge@antcom.de 	else
57345bf8305SNaresh Solanki 		ppr = 2;
5740f33272bSNaresh Solanki 
5750f33272bSNaresh Solanki 	data->ppr[0] = ppr;
5760f33272bSNaresh Solanki 	data->ppr[1] = ppr;
577a5b79d62Sstigge@antcom.de 
578a5b79d62Sstigge@antcom.de 	if (max6639_info)
579a5b79d62Sstigge@antcom.de 		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
5800f33272bSNaresh Solanki 	data->rpm_range[0] = rpm_range;
5810f33272bSNaresh Solanki 	data->rpm_range[1] = rpm_range;
582a5b79d62Sstigge@antcom.de 
58345bf8305SNaresh Solanki 	for (i = 0; i < MAX6639_NUM_CHANNELS; i++) {
5842f2da1acSChris D Schimp 		/* Set Fan pulse per revolution */
5850f33272bSNaresh Solanki 		err = max6639_set_ppr(data, i, data->ppr[i]);
5862f2da1acSChris D Schimp 		if (err)
58745bf8305SNaresh Solanki 			return err;
5882f2da1acSChris D Schimp 
589a5b79d62Sstigge@antcom.de 		/* Fans config PWM, RPM */
59045bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i),
5910f33272bSNaresh Solanki 				   MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]);
592a5b79d62Sstigge@antcom.de 		if (err)
59345bf8305SNaresh Solanki 			return err;
594a5b79d62Sstigge@antcom.de 
595a5b79d62Sstigge@antcom.de 		/* Fans PWM polarity high by default */
5960f33272bSNaresh Solanki 		if (max6639_info) {
5970f33272bSNaresh Solanki 			if (max6639_info->pwm_polarity == 0)
59845bf8305SNaresh Solanki 				err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
599a5b79d62Sstigge@antcom.de 			else
60045bf8305SNaresh Solanki 				err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
6010f33272bSNaresh Solanki 		}
602a5b79d62Sstigge@antcom.de 		if (err)
60345bf8305SNaresh Solanki 			return err;
604a5b79d62Sstigge@antcom.de 
605177f3b92Sstigge@antcom.de 		/*
606177f3b92Sstigge@antcom.de 		 * /THERM full speed enable,
607177f3b92Sstigge@antcom.de 		 * PWM frequency 25kHz, see also GCONFIG below
608177f3b92Sstigge@antcom.de 		 */
60945bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i),
610177f3b92Sstigge@antcom.de 				   MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
611177f3b92Sstigge@antcom.de 		if (err)
61245bf8305SNaresh Solanki 			return err;
613177f3b92Sstigge@antcom.de 
614a5b79d62Sstigge@antcom.de 		/* Max. temp. 80C/90C/100C */
61545bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80);
616a5b79d62Sstigge@antcom.de 		if (err)
61745bf8305SNaresh Solanki 			return err;
61845bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90);
619a5b79d62Sstigge@antcom.de 		if (err)
62045bf8305SNaresh Solanki 			return err;
62145bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100);
622a5b79d62Sstigge@antcom.de 		if (err)
62345bf8305SNaresh Solanki 			return err;
624a5b79d62Sstigge@antcom.de 
625a5b79d62Sstigge@antcom.de 		/* PWM 120/120 (i.e. 100%) */
62645bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120);
627a5b79d62Sstigge@antcom.de 		if (err)
62845bf8305SNaresh Solanki 			return err;
629a5b79d62Sstigge@antcom.de 	}
630a5b79d62Sstigge@antcom.de 	/* Start monitoring */
63145bf8305SNaresh Solanki 	return regmap_write(data->regmap, MAX6639_REG_GCONFIG,
632177f3b92Sstigge@antcom.de 			    MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
633177f3b92Sstigge@antcom.de 			    MAX6639_GCONFIG_PWM_FREQ_HI);
63445bf8305SNaresh Solanki 
635a5b79d62Sstigge@antcom.de }
636a5b79d62Sstigge@antcom.de 
637a5b79d62Sstigge@antcom.de /* Return 0 if detection is successful, -ENODEV otherwise */
638a5b79d62Sstigge@antcom.de static int max6639_detect(struct i2c_client *client,
639a5b79d62Sstigge@antcom.de 			  struct i2c_board_info *info)
640a5b79d62Sstigge@antcom.de {
641a5b79d62Sstigge@antcom.de 	struct i2c_adapter *adapter = client->adapter;
642a5b79d62Sstigge@antcom.de 	int dev_id, manu_id;
643a5b79d62Sstigge@antcom.de 
644a5b79d62Sstigge@antcom.de 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
645a5b79d62Sstigge@antcom.de 		return -ENODEV;
646a5b79d62Sstigge@antcom.de 
647a5b79d62Sstigge@antcom.de 	/* Actual detection via device and manufacturer ID */
648a5b79d62Sstigge@antcom.de 	dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID);
649a5b79d62Sstigge@antcom.de 	manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID);
650a5b79d62Sstigge@antcom.de 	if (dev_id != 0x58 || manu_id != 0x4D)
651a5b79d62Sstigge@antcom.de 		return -ENODEV;
652a5b79d62Sstigge@antcom.de 
653f2f394dbSWolfram Sang 	strscpy(info->type, "max6639", I2C_NAME_SIZE);
654a5b79d62Sstigge@antcom.de 
655a5b79d62Sstigge@antcom.de 	return 0;
656a5b79d62Sstigge@antcom.de }
657a5b79d62Sstigge@antcom.de 
6584e2271eaSMarcello Sylvester Bauer static void max6639_regulator_disable(void *data)
6594e2271eaSMarcello Sylvester Bauer {
6604e2271eaSMarcello Sylvester Bauer 	regulator_disable(data);
6614e2271eaSMarcello Sylvester Bauer }
6624e2271eaSMarcello Sylvester Bauer 
66345bf8305SNaresh Solanki static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg)
66445bf8305SNaresh Solanki {
66545bf8305SNaresh Solanki 	switch (reg) {
66645bf8305SNaresh Solanki 	case MAX6639_REG_TEMP(0):
66745bf8305SNaresh Solanki 	case MAX6639_REG_TEMP_EXT(0):
66845bf8305SNaresh Solanki 	case MAX6639_REG_TEMP(1):
66945bf8305SNaresh Solanki 	case MAX6639_REG_TEMP_EXT(1):
67045bf8305SNaresh Solanki 	case MAX6639_REG_STATUS:
67145bf8305SNaresh Solanki 	case MAX6639_REG_FAN_CNT(0):
67245bf8305SNaresh Solanki 	case MAX6639_REG_FAN_CNT(1):
67345bf8305SNaresh Solanki 	case MAX6639_REG_TARGTDUTY(0):
67445bf8305SNaresh Solanki 	case MAX6639_REG_TARGTDUTY(1):
67545bf8305SNaresh Solanki 		return true;
67645bf8305SNaresh Solanki 	default:
67745bf8305SNaresh Solanki 		return false;
67845bf8305SNaresh Solanki 	}
67945bf8305SNaresh Solanki }
68045bf8305SNaresh Solanki 
68145bf8305SNaresh Solanki static const struct regmap_config max6639_regmap_config = {
68245bf8305SNaresh Solanki 	.reg_bits = 8,
68345bf8305SNaresh Solanki 	.val_bits = 8,
68445bf8305SNaresh Solanki 	.max_register = MAX6639_REG_DEVREV,
68545bf8305SNaresh Solanki 	.cache_type = REGCACHE_MAPLE,
68645bf8305SNaresh Solanki 	.volatile_reg = max6639_regmap_is_volatile,
68745bf8305SNaresh Solanki };
68845bf8305SNaresh Solanki 
68967487038SStephen Kitt static int max6639_probe(struct i2c_client *client)
690a5b79d62Sstigge@antcom.de {
691c1ea0a04SGuenter Roeck 	struct device *dev = &client->dev;
692a5b79d62Sstigge@antcom.de 	struct max6639_data *data;
6937981c584SGuenter Roeck 	struct device *hwmon_dev;
694a5b79d62Sstigge@antcom.de 	int err;
695a5b79d62Sstigge@antcom.de 
696c1ea0a04SGuenter Roeck 	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
697b07405fbSGuenter Roeck 	if (!data)
698b07405fbSGuenter Roeck 		return -ENOMEM;
699a5b79d62Sstigge@antcom.de 
70045bf8305SNaresh Solanki 	data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config);
70145bf8305SNaresh Solanki 	if (IS_ERR(data->regmap))
70245bf8305SNaresh Solanki 		return dev_err_probe(dev,
70345bf8305SNaresh Solanki 				     PTR_ERR(data->regmap),
70445bf8305SNaresh Solanki 				     "regmap initialization failed\n");
7054e2271eaSMarcello Sylvester Bauer 
7064e2271eaSMarcello Sylvester Bauer 	data->reg = devm_regulator_get_optional(dev, "fan");
7074e2271eaSMarcello Sylvester Bauer 	if (IS_ERR(data->reg)) {
7084e2271eaSMarcello Sylvester Bauer 		if (PTR_ERR(data->reg) != -ENODEV)
7094e2271eaSMarcello Sylvester Bauer 			return PTR_ERR(data->reg);
7104e2271eaSMarcello Sylvester Bauer 
7114e2271eaSMarcello Sylvester Bauer 		data->reg = NULL;
7124e2271eaSMarcello Sylvester Bauer 	} else {
7134e2271eaSMarcello Sylvester Bauer 		/* Spin up fans */
7144e2271eaSMarcello Sylvester Bauer 		err = regulator_enable(data->reg);
7154e2271eaSMarcello Sylvester Bauer 		if (err) {
7164e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to enable fan supply: %d\n", err);
7174e2271eaSMarcello Sylvester Bauer 			return err;
7184e2271eaSMarcello Sylvester Bauer 		}
7194e2271eaSMarcello Sylvester Bauer 		err = devm_add_action_or_reset(dev, max6639_regulator_disable,
7204e2271eaSMarcello Sylvester Bauer 					       data->reg);
7214e2271eaSMarcello Sylvester Bauer 		if (err) {
7224e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to register action: %d\n", err);
7234e2271eaSMarcello Sylvester Bauer 			return err;
7244e2271eaSMarcello Sylvester Bauer 		}
7254e2271eaSMarcello Sylvester Bauer 	}
7264e2271eaSMarcello Sylvester Bauer 
727*842b4d98SNaresh Solanki 	mutex_init(&data->update_lock);
728*842b4d98SNaresh Solanki 
729a5b79d62Sstigge@antcom.de 	/* Initialize the max6639 chip */
7307981c584SGuenter Roeck 	err = max6639_init_client(client, data);
731a5b79d62Sstigge@antcom.de 	if (err < 0)
732b07405fbSGuenter Roeck 		return err;
733a5b79d62Sstigge@antcom.de 
7340f33272bSNaresh Solanki 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
7350f33272bSNaresh Solanki 							 data, &max6639_chip_info,
7360f33272bSNaresh Solanki 							 NULL);
7370f33272bSNaresh Solanki 
7387981c584SGuenter Roeck 	return PTR_ERR_OR_ZERO(hwmon_dev);
739a5b79d62Sstigge@antcom.de }
740a5b79d62Sstigge@antcom.de 
74152f30f77SMark Brown static int max6639_suspend(struct device *dev)
742a5b79d62Sstigge@antcom.de {
7434e2271eaSMarcello Sylvester Bauer 	struct max6639_data *data = dev_get_drvdata(dev);
7444e2271eaSMarcello Sylvester Bauer 
7454e2271eaSMarcello Sylvester Bauer 	if (data->reg)
7464e2271eaSMarcello Sylvester Bauer 		regulator_disable(data->reg);
747a5b79d62Sstigge@antcom.de 
74845bf8305SNaresh Solanki 	return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
74945bf8305SNaresh Solanki 				 MAX6639_GCONFIG_STANDBY);
750a5b79d62Sstigge@antcom.de }
751a5b79d62Sstigge@antcom.de 
75252f30f77SMark Brown static int max6639_resume(struct device *dev)
753a5b79d62Sstigge@antcom.de {
7544e2271eaSMarcello Sylvester Bauer 	struct max6639_data *data = dev_get_drvdata(dev);
7554e2271eaSMarcello Sylvester Bauer 	int ret;
7564e2271eaSMarcello Sylvester Bauer 
7574e2271eaSMarcello Sylvester Bauer 	if (data->reg) {
7584e2271eaSMarcello Sylvester Bauer 		ret = regulator_enable(data->reg);
7594e2271eaSMarcello Sylvester Bauer 		if (ret) {
7604e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to enable fan supply: %d\n", ret);
7614e2271eaSMarcello Sylvester Bauer 			return ret;
7624e2271eaSMarcello Sylvester Bauer 		}
7634e2271eaSMarcello Sylvester Bauer 	}
7644e2271eaSMarcello Sylvester Bauer 
76545bf8305SNaresh Solanki 	return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
76645bf8305SNaresh Solanki 				 ~MAX6639_GCONFIG_STANDBY);
767a5b79d62Sstigge@antcom.de }
768a5b79d62Sstigge@antcom.de 
769a5b79d62Sstigge@antcom.de static const struct i2c_device_id max6639_id[] = {
770d8a66f36SUwe Kleine-König 	{"max6639"},
771a5b79d62Sstigge@antcom.de 	{ }
772a5b79d62Sstigge@antcom.de };
773a5b79d62Sstigge@antcom.de 
774a5b79d62Sstigge@antcom.de MODULE_DEVICE_TABLE(i2c, max6639_id);
775a5b79d62Sstigge@antcom.de 
77677563092SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
77752f30f77SMark Brown 
778f11e2738SNaresh Solanki static const struct of_device_id max6639_of_match[] = {
779f11e2738SNaresh Solanki 	{ .compatible = "maxim,max6639", },
780f11e2738SNaresh Solanki 	{ },
781f11e2738SNaresh Solanki };
782f11e2738SNaresh Solanki 
783a5b79d62Sstigge@antcom.de static struct i2c_driver max6639_driver = {
784a5b79d62Sstigge@antcom.de 	.class = I2C_CLASS_HWMON,
785a5b79d62Sstigge@antcom.de 	.driver = {
786a5b79d62Sstigge@antcom.de 		   .name = "max6639",
78777563092SJonathan Cameron 		   .pm = pm_sleep_ptr(&max6639_pm_ops),
788f11e2738SNaresh Solanki 		   .of_match_table = max6639_of_match,
789a5b79d62Sstigge@antcom.de 		   },
7901975d167SUwe Kleine-König 	.probe = max6639_probe,
791a5b79d62Sstigge@antcom.de 	.id_table = max6639_id,
792a5b79d62Sstigge@antcom.de 	.detect = max6639_detect,
793a5b79d62Sstigge@antcom.de 	.address_list = normal_i2c,
794a5b79d62Sstigge@antcom.de };
795a5b79d62Sstigge@antcom.de 
796f0967eeaSAxel Lin module_i2c_driver(max6639_driver);
797a5b79d62Sstigge@antcom.de 
798a5b79d62Sstigge@antcom.de MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
799a5b79d62Sstigge@antcom.de MODULE_DESCRIPTION("max6639 driver");
800a5b79d62Sstigge@antcom.de MODULE_LICENSE("GPL");
801