xref: /linux/drivers/hwmon/max6639.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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;
79842b4d98SNaresh 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 
max6639_temp_read_input(struct device * dev,int channel,long * temp)890f33272bSNaresh Solanki static int max6639_temp_read_input(struct device *dev, int channel, long *temp)
90a5b79d62Sstigge@antcom.de {
91*21a93a9eSGuenter Roeck 	u32 regs[2] = { MAX6639_REG_TEMP_EXT(channel), MAX6639_REG_TEMP(channel) };
9245bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
93*21a93a9eSGuenter Roeck 	u8 regvals[2];
9445bf8305SNaresh Solanki 	int res;
95a5b79d62Sstigge@antcom.de 
96*21a93a9eSGuenter Roeck 	res = regmap_multi_reg_read(data->regmap, regs, regvals, 2);
9745bf8305SNaresh Solanki 	if (res < 0)
9845bf8305SNaresh Solanki 		return res;
99a5b79d62Sstigge@antcom.de 
100*21a93a9eSGuenter Roeck 	*temp = ((regvals[0] >> 5) | (regvals[1] << 3)) * 125;
10145bf8305SNaresh Solanki 
1020f33272bSNaresh Solanki 	return 0;
103a5b79d62Sstigge@antcom.de }
104a5b79d62Sstigge@antcom.de 
max6639_temp_read_fault(struct device * dev,int channel,long * fault)1050f33272bSNaresh Solanki static int max6639_temp_read_fault(struct device *dev, int channel, long *fault)
106a5b79d62Sstigge@antcom.de {
10745bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
10845bf8305SNaresh Solanki 	unsigned int val;
10945bf8305SNaresh Solanki 	int res;
110a5b79d62Sstigge@antcom.de 
1110f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(channel), &val);
11245bf8305SNaresh Solanki 	if (res < 0)
11345bf8305SNaresh Solanki 		return res;
11445bf8305SNaresh Solanki 
1150f33272bSNaresh Solanki 	*fault = val & 1;
1160f33272bSNaresh Solanki 
1170f33272bSNaresh Solanki 	return 0;
118a5b79d62Sstigge@antcom.de }
119a5b79d62Sstigge@antcom.de 
max6639_temp_read_max(struct device * dev,int channel,long * max)1200f33272bSNaresh Solanki static int max6639_temp_read_max(struct device *dev, int channel, long *max)
121a5b79d62Sstigge@antcom.de {
1227981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
12345bf8305SNaresh Solanki 	unsigned int val;
12445bf8305SNaresh Solanki 	int res;
125a5b79d62Sstigge@antcom.de 
1260f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(channel), &val);
12745bf8305SNaresh Solanki 	if (res < 0)
12845bf8305SNaresh Solanki 		return res;
12945bf8305SNaresh Solanki 
1300f33272bSNaresh Solanki 	*max = (long)val * 1000;
1310f33272bSNaresh Solanki 
1320f33272bSNaresh Solanki 	return 0;
133a5b79d62Sstigge@antcom.de }
134a5b79d62Sstigge@antcom.de 
max6639_temp_read_crit(struct device * dev,int channel,long * crit)1350f33272bSNaresh Solanki static int max6639_temp_read_crit(struct device *dev, int channel, long *crit)
136a5b79d62Sstigge@antcom.de {
1377981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
13845bf8305SNaresh Solanki 	unsigned int val;
13945bf8305SNaresh Solanki 	int res;
140a5b79d62Sstigge@antcom.de 
1410f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), &val);
14245bf8305SNaresh Solanki 	if (res < 0)
14345bf8305SNaresh Solanki 		return res;
14445bf8305SNaresh Solanki 
1450f33272bSNaresh Solanki 	*crit = (long)val * 1000;
1460f33272bSNaresh Solanki 
1470f33272bSNaresh Solanki 	return 0;
148a5b79d62Sstigge@antcom.de }
149a5b79d62Sstigge@antcom.de 
max6639_temp_read_emergency(struct device * dev,int channel,long * emerg)1500f33272bSNaresh Solanki static int max6639_temp_read_emergency(struct device *dev, int channel, long *emerg)
151a5b79d62Sstigge@antcom.de {
1527981c584SGuenter Roeck 	struct max6639_data *data = dev_get_drvdata(dev);
15345bf8305SNaresh Solanki 	unsigned int val;
15445bf8305SNaresh Solanki 	int res;
155a5b79d62Sstigge@antcom.de 
1560f33272bSNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(channel), &val);
15745bf8305SNaresh Solanki 	if (res < 0)
15845bf8305SNaresh Solanki 		return res;
15945bf8305SNaresh Solanki 
1600f33272bSNaresh Solanki 	*emerg = (long)val * 1000;
1610f33272bSNaresh Solanki 
1620f33272bSNaresh Solanki 	return 0;
163a5b79d62Sstigge@antcom.de }
164a5b79d62Sstigge@antcom.de 
max6639_get_status(struct device * dev,unsigned int * status)1650f33272bSNaresh Solanki static int max6639_get_status(struct device *dev, unsigned int *status)
166a5b79d62Sstigge@antcom.de {
16745bf8305SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
16845bf8305SNaresh Solanki 	unsigned int val;
16945bf8305SNaresh Solanki 	int res;
170a5b79d62Sstigge@antcom.de 
17145bf8305SNaresh Solanki 	res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val);
17245bf8305SNaresh Solanki 	if (res < 0)
17345bf8305SNaresh Solanki 		return res;
174a5b79d62Sstigge@antcom.de 
1750f33272bSNaresh Solanki 	*status = val;
1760f33272bSNaresh Solanki 
1770f33272bSNaresh Solanki 	return 0;
178a5b79d62Sstigge@antcom.de }
179a5b79d62Sstigge@antcom.de 
max6639_temp_set_max(struct max6639_data * data,int channel,long val)1800f33272bSNaresh Solanki static int max6639_temp_set_max(struct max6639_data *data, int channel, long val)
1810f33272bSNaresh Solanki {
1820f33272bSNaresh Solanki 	int res;
183a5b79d62Sstigge@antcom.de 
1840f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel),
1850f33272bSNaresh Solanki 			   TEMP_LIMIT_TO_REG(val));
1860f33272bSNaresh Solanki 	return res;
1870f33272bSNaresh Solanki }
188a5b79d62Sstigge@antcom.de 
max6639_temp_set_crit(struct max6639_data * data,int channel,long val)1890f33272bSNaresh Solanki static int max6639_temp_set_crit(struct max6639_data *data, int channel, long val)
1900f33272bSNaresh Solanki {
1910f33272bSNaresh Solanki 	int res;
1920f33272bSNaresh Solanki 
1930f33272bSNaresh Solanki 	res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
1940f33272bSNaresh Solanki 
1950f33272bSNaresh Solanki 	return res;
1960f33272bSNaresh Solanki }
1970f33272bSNaresh Solanki 
max6639_temp_set_emergency(struct max6639_data * data,int channel,long val)1980f33272bSNaresh Solanki static int max6639_temp_set_emergency(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_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
2030f33272bSNaresh Solanki 
2040f33272bSNaresh Solanki 	return res;
2050f33272bSNaresh Solanki }
2060f33272bSNaresh Solanki 
max6639_read_fan(struct device * dev,u32 attr,int channel,long * fan_val)2070f33272bSNaresh Solanki static int max6639_read_fan(struct device *dev, u32 attr, int channel,
2080f33272bSNaresh Solanki 			    long *fan_val)
2090f33272bSNaresh Solanki {
2100f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
2110f33272bSNaresh Solanki 	unsigned int val;
2120f33272bSNaresh Solanki 	int res;
2130f33272bSNaresh Solanki 
2140f33272bSNaresh Solanki 	switch (attr) {
2150f33272bSNaresh Solanki 	case hwmon_fan_input:
2160f33272bSNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val);
2170f33272bSNaresh Solanki 		if (res < 0)
2180f33272bSNaresh Solanki 			return res;
2190f33272bSNaresh Solanki 		*fan_val = FAN_FROM_REG(val, data->rpm_range[channel]);
2200f33272bSNaresh Solanki 		return 0;
2210f33272bSNaresh Solanki 	case hwmon_fan_fault:
2220f33272bSNaresh Solanki 		res = max6639_get_status(dev, &val);
2230f33272bSNaresh Solanki 		if (res < 0)
2240f33272bSNaresh Solanki 			return res;
2250f33272bSNaresh Solanki 		*fan_val = !!(val & BIT(1 - channel));
2260f33272bSNaresh Solanki 		return 0;
227842b4d98SNaresh Solanki 	case hwmon_fan_pulses:
228842b4d98SNaresh Solanki 		*fan_val = data->ppr[channel];
229842b4d98SNaresh Solanki 		return 0;
2300f33272bSNaresh Solanki 	default:
2310f33272bSNaresh Solanki 		return -EOPNOTSUPP;
2320f33272bSNaresh Solanki 	}
2330f33272bSNaresh Solanki }
2340f33272bSNaresh Solanki 
max6639_set_ppr(struct max6639_data * data,int channel,u8 ppr)2350f33272bSNaresh Solanki static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr)
2360f33272bSNaresh Solanki {
2370f33272bSNaresh Solanki 	/* Decrement the PPR value and shift left by 6 to match the register format */
2380f33272bSNaresh Solanki 	return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6);
2390f33272bSNaresh Solanki }
2400f33272bSNaresh Solanki 
max6639_write_fan(struct device * dev,u32 attr,int channel,long val)241842b4d98SNaresh Solanki static int max6639_write_fan(struct device *dev, u32 attr, int channel,
242842b4d98SNaresh Solanki 			     long val)
243842b4d98SNaresh Solanki {
244842b4d98SNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
245842b4d98SNaresh Solanki 	int err;
246842b4d98SNaresh Solanki 
247842b4d98SNaresh Solanki 	switch (attr) {
248842b4d98SNaresh Solanki 	case hwmon_fan_pulses:
249842b4d98SNaresh Solanki 		if (val <= 0 || val > 4)
250842b4d98SNaresh Solanki 			return -EINVAL;
251842b4d98SNaresh Solanki 
252842b4d98SNaresh Solanki 		mutex_lock(&data->update_lock);
253842b4d98SNaresh Solanki 		/* Set Fan pulse per revolution */
254842b4d98SNaresh Solanki 		err = max6639_set_ppr(data, channel, val);
255842b4d98SNaresh Solanki 		if (err < 0) {
256842b4d98SNaresh Solanki 			mutex_unlock(&data->update_lock);
257842b4d98SNaresh Solanki 			return err;
258842b4d98SNaresh Solanki 		}
259842b4d98SNaresh Solanki 		data->ppr[channel] = val;
260842b4d98SNaresh Solanki 
261842b4d98SNaresh Solanki 		mutex_unlock(&data->update_lock);
262842b4d98SNaresh Solanki 		return 0;
263842b4d98SNaresh Solanki 	default:
264842b4d98SNaresh Solanki 		return -EOPNOTSUPP;
265842b4d98SNaresh Solanki 	}
266842b4d98SNaresh Solanki }
267842b4d98SNaresh Solanki 
max6639_fan_is_visible(const void * _data,u32 attr,int channel)2680f33272bSNaresh Solanki static umode_t max6639_fan_is_visible(const void *_data, u32 attr, int channel)
2690f33272bSNaresh Solanki {
2700f33272bSNaresh Solanki 	switch (attr) {
2710f33272bSNaresh Solanki 	case hwmon_fan_input:
2720f33272bSNaresh Solanki 	case hwmon_fan_fault:
2730f33272bSNaresh Solanki 		return 0444;
2740f33272bSNaresh Solanki 	case hwmon_fan_pulses:
2750f33272bSNaresh Solanki 		return 0644;
2760f33272bSNaresh Solanki 	default:
2770f33272bSNaresh Solanki 		return 0;
2780f33272bSNaresh Solanki 	}
2790f33272bSNaresh Solanki }
2800f33272bSNaresh Solanki 
max6639_read_pwm(struct device * dev,u32 attr,int channel,long * pwm_val)2810f33272bSNaresh Solanki static int max6639_read_pwm(struct device *dev, u32 attr, int channel,
2820f33272bSNaresh Solanki 			    long *pwm_val)
2830f33272bSNaresh Solanki {
284*21a93a9eSGuenter Roeck 	u32 regs[2] = { MAX6639_REG_FAN_CONFIG3(channel), MAX6639_REG_GCONFIG };
2850f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
2860f33272bSNaresh Solanki 	unsigned int val;
287*21a93a9eSGuenter Roeck 	u8 regvals[2];
2880f33272bSNaresh Solanki 	int res;
289842b4d98SNaresh Solanki 	u8 i;
2900f33272bSNaresh Solanki 
2910f33272bSNaresh Solanki 	switch (attr) {
2920f33272bSNaresh Solanki 	case hwmon_pwm_input:
2930f33272bSNaresh Solanki 		res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(channel), &val);
2940f33272bSNaresh Solanki 		if (res < 0)
2950f33272bSNaresh Solanki 			return res;
2960f33272bSNaresh Solanki 		*pwm_val = val * 255 / 120;
2970f33272bSNaresh Solanki 		return 0;
298842b4d98SNaresh Solanki 	case hwmon_pwm_freq:
299*21a93a9eSGuenter Roeck 		res = regmap_multi_reg_read(data->regmap, regs, regvals, 2);
300*21a93a9eSGuenter Roeck 		if (res < 0)
301842b4d98SNaresh Solanki 			return res;
302*21a93a9eSGuenter Roeck 		i = regvals[0] & MAX6639_FAN_CONFIG3_FREQ_MASK;
303*21a93a9eSGuenter Roeck 		if (regvals[1] & MAX6639_GCONFIG_PWM_FREQ_HI)
304842b4d98SNaresh Solanki 			i |= 0x4;
305842b4d98SNaresh Solanki 		*pwm_val = freq_table[i];
306842b4d98SNaresh Solanki 		return 0;
3070f33272bSNaresh Solanki 	default:
3080f33272bSNaresh Solanki 		return -EOPNOTSUPP;
3090f33272bSNaresh Solanki 	}
3100f33272bSNaresh Solanki }
3110f33272bSNaresh Solanki 
max6639_write_pwm(struct device * dev,u32 attr,int channel,long val)3120f33272bSNaresh Solanki static int max6639_write_pwm(struct device *dev, u32 attr, int channel,
3130f33272bSNaresh Solanki 			     long val)
3140f33272bSNaresh Solanki {
3150f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
3160f33272bSNaresh Solanki 	int err;
317842b4d98SNaresh Solanki 	u8 i;
3180f33272bSNaresh Solanki 
3190f33272bSNaresh Solanki 	switch (attr) {
3200f33272bSNaresh Solanki 	case hwmon_pwm_input:
3210f33272bSNaresh Solanki 		if (val < 0 || val > 255)
3220f33272bSNaresh Solanki 			return -EINVAL;
3230f33272bSNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel),
3240f33272bSNaresh Solanki 				   val * 120 / 255);
3250f33272bSNaresh Solanki 		return err;
326842b4d98SNaresh Solanki 	case hwmon_pwm_freq:
327842b4d98SNaresh Solanki 		val = clamp_val(val, 0, 25000);
328842b4d98SNaresh Solanki 
329842b4d98SNaresh Solanki 		i = find_closest(val, freq_table, ARRAY_SIZE(freq_table));
330842b4d98SNaresh Solanki 
331842b4d98SNaresh Solanki 		mutex_lock(&data->update_lock);
332842b4d98SNaresh Solanki 		err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel),
333842b4d98SNaresh Solanki 					 MAX6639_FAN_CONFIG3_FREQ_MASK, i);
334842b4d98SNaresh Solanki 		if (err < 0) {
335842b4d98SNaresh Solanki 			mutex_unlock(&data->update_lock);
336842b4d98SNaresh Solanki 			return err;
337842b4d98SNaresh Solanki 		}
338842b4d98SNaresh Solanki 
339842b4d98SNaresh Solanki 		if (i >> 2)
340842b4d98SNaresh Solanki 			err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG,
341842b4d98SNaresh Solanki 					      MAX6639_GCONFIG_PWM_FREQ_HI);
342842b4d98SNaresh Solanki 		else
343842b4d98SNaresh Solanki 			err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG,
344842b4d98SNaresh Solanki 						MAX6639_GCONFIG_PWM_FREQ_HI);
345842b4d98SNaresh Solanki 
346842b4d98SNaresh Solanki 		mutex_unlock(&data->update_lock);
347842b4d98SNaresh Solanki 		return err;
3480f33272bSNaresh Solanki 	default:
3490f33272bSNaresh Solanki 		return -EOPNOTSUPP;
3500f33272bSNaresh Solanki 	}
3510f33272bSNaresh Solanki }
3520f33272bSNaresh Solanki 
max6639_pwm_is_visible(const void * _data,u32 attr,int channel)3530f33272bSNaresh Solanki static umode_t max6639_pwm_is_visible(const void *_data, u32 attr, int channel)
3540f33272bSNaresh Solanki {
3550f33272bSNaresh Solanki 	switch (attr) {
3560f33272bSNaresh Solanki 	case hwmon_pwm_input:
357842b4d98SNaresh Solanki 	case hwmon_pwm_freq:
3580f33272bSNaresh Solanki 		return 0644;
3590f33272bSNaresh Solanki 	default:
3600f33272bSNaresh Solanki 		return 0;
3610f33272bSNaresh Solanki 	}
3620f33272bSNaresh Solanki }
3630f33272bSNaresh Solanki 
max6639_read_temp(struct device * dev,u32 attr,int channel,long * val)3640f33272bSNaresh Solanki static int max6639_read_temp(struct device *dev, u32 attr, int channel,
3650f33272bSNaresh Solanki 			     long *val)
3660f33272bSNaresh Solanki {
3670f33272bSNaresh Solanki 	unsigned int status;
3680f33272bSNaresh Solanki 	int res;
3690f33272bSNaresh Solanki 
3700f33272bSNaresh Solanki 	switch (attr) {
3710f33272bSNaresh Solanki 	case hwmon_temp_input:
3720f33272bSNaresh Solanki 		res = max6639_temp_read_input(dev, channel, val);
3730f33272bSNaresh Solanki 		return res;
3740f33272bSNaresh Solanki 	case hwmon_temp_fault:
3750f33272bSNaresh Solanki 		res = max6639_temp_read_fault(dev, channel, val);
3760f33272bSNaresh Solanki 		return res;
3770f33272bSNaresh Solanki 	case hwmon_temp_max:
3780f33272bSNaresh Solanki 		res = max6639_temp_read_max(dev, channel, val);
3790f33272bSNaresh Solanki 		return res;
3800f33272bSNaresh Solanki 	case hwmon_temp_crit:
3810f33272bSNaresh Solanki 		res = max6639_temp_read_crit(dev, channel, val);
3820f33272bSNaresh Solanki 		return res;
3830f33272bSNaresh Solanki 	case hwmon_temp_emergency:
3840f33272bSNaresh Solanki 		res = max6639_temp_read_emergency(dev, channel, val);
3850f33272bSNaresh Solanki 		return res;
3860f33272bSNaresh Solanki 	case hwmon_temp_max_alarm:
3870f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
3880f33272bSNaresh Solanki 		if (res < 0)
3890f33272bSNaresh Solanki 			return res;
3900f33272bSNaresh Solanki 		*val = !!(status & BIT(3 - channel));
3910f33272bSNaresh Solanki 		return 0;
3920f33272bSNaresh Solanki 	case hwmon_temp_crit_alarm:
3930f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
3940f33272bSNaresh Solanki 		if (res < 0)
3950f33272bSNaresh Solanki 			return res;
3960f33272bSNaresh Solanki 		*val = !!(status & BIT(7 - channel));
3970f33272bSNaresh Solanki 		return 0;
3980f33272bSNaresh Solanki 	case hwmon_temp_emergency_alarm:
3990f33272bSNaresh Solanki 		res = max6639_get_status(dev, &status);
4000f33272bSNaresh Solanki 		if (res < 0)
4010f33272bSNaresh Solanki 			return res;
4020f33272bSNaresh Solanki 		*val = !!(status & BIT(5 - channel));
4030f33272bSNaresh Solanki 		return 0;
4040f33272bSNaresh Solanki 	default:
4050f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4060f33272bSNaresh Solanki 	}
4070f33272bSNaresh Solanki }
4080f33272bSNaresh Solanki 
max6639_write_temp(struct device * dev,u32 attr,int channel,long val)4090f33272bSNaresh Solanki static int max6639_write_temp(struct device *dev, u32 attr, int channel,
4100f33272bSNaresh Solanki 			      long val)
4110f33272bSNaresh Solanki {
4120f33272bSNaresh Solanki 	struct max6639_data *data = dev_get_drvdata(dev);
4130f33272bSNaresh Solanki 
4140f33272bSNaresh Solanki 	switch (attr) {
4150f33272bSNaresh Solanki 	case hwmon_temp_max:
4160f33272bSNaresh Solanki 		return max6639_temp_set_max(data, channel, val);
4170f33272bSNaresh Solanki 	case hwmon_temp_crit:
4180f33272bSNaresh Solanki 		return max6639_temp_set_crit(data, channel, val);
4190f33272bSNaresh Solanki 	case hwmon_temp_emergency:
4200f33272bSNaresh Solanki 		return max6639_temp_set_emergency(data, channel, val);
4210f33272bSNaresh Solanki 	default:
4220f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4230f33272bSNaresh Solanki 	}
4240f33272bSNaresh Solanki }
4250f33272bSNaresh Solanki 
max6639_temp_is_visible(const void * _data,u32 attr,int channel)4260f33272bSNaresh Solanki static umode_t max6639_temp_is_visible(const void *_data, u32 attr, int channel)
4270f33272bSNaresh Solanki {
4280f33272bSNaresh Solanki 	switch (attr) {
4290f33272bSNaresh Solanki 	case hwmon_temp_input:
4300f33272bSNaresh Solanki 	case hwmon_temp_fault:
4310f33272bSNaresh Solanki 	case hwmon_temp_max_alarm:
4320f33272bSNaresh Solanki 	case hwmon_temp_crit_alarm:
4330f33272bSNaresh Solanki 	case hwmon_temp_emergency_alarm:
4340f33272bSNaresh Solanki 		return 0444;
4350f33272bSNaresh Solanki 	case hwmon_temp_max:
4360f33272bSNaresh Solanki 	case hwmon_temp_crit:
4370f33272bSNaresh Solanki 	case hwmon_temp_emergency:
4380f33272bSNaresh Solanki 		return 0644;
4390f33272bSNaresh Solanki 	default:
4400f33272bSNaresh Solanki 		return 0;
4410f33272bSNaresh Solanki 	}
4420f33272bSNaresh Solanki }
4430f33272bSNaresh Solanki 
max6639_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)4440f33272bSNaresh Solanki static int max6639_read(struct device *dev, enum hwmon_sensor_types type,
4450f33272bSNaresh Solanki 			u32 attr, int channel, long *val)
4460f33272bSNaresh Solanki {
4470f33272bSNaresh Solanki 	switch (type) {
4480f33272bSNaresh Solanki 	case hwmon_fan:
4490f33272bSNaresh Solanki 		return max6639_read_fan(dev, attr, channel, val);
4500f33272bSNaresh Solanki 	case hwmon_pwm:
4510f33272bSNaresh Solanki 		return max6639_read_pwm(dev, attr, channel, val);
4520f33272bSNaresh Solanki 	case hwmon_temp:
4530f33272bSNaresh Solanki 		return max6639_read_temp(dev, attr, channel, val);
4540f33272bSNaresh Solanki 	default:
4550f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4560f33272bSNaresh Solanki 	}
4570f33272bSNaresh Solanki }
4580f33272bSNaresh Solanki 
max6639_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)4590f33272bSNaresh Solanki static int max6639_write(struct device *dev, enum hwmon_sensor_types type,
4600f33272bSNaresh Solanki 			 u32 attr, int channel, long val)
4610f33272bSNaresh Solanki {
4620f33272bSNaresh Solanki 	switch (type) {
463842b4d98SNaresh Solanki 	case hwmon_fan:
464842b4d98SNaresh Solanki 		return max6639_write_fan(dev, attr, channel, val);
4650f33272bSNaresh Solanki 	case hwmon_pwm:
4660f33272bSNaresh Solanki 		return max6639_write_pwm(dev, attr, channel, val);
4670f33272bSNaresh Solanki 	case hwmon_temp:
4680f33272bSNaresh Solanki 		return max6639_write_temp(dev, attr, channel, val);
4690f33272bSNaresh Solanki 	default:
4700f33272bSNaresh Solanki 		return -EOPNOTSUPP;
4710f33272bSNaresh Solanki 	}
4720f33272bSNaresh Solanki }
4730f33272bSNaresh Solanki 
max6639_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)4740f33272bSNaresh Solanki static umode_t max6639_is_visible(const void *data,
4750f33272bSNaresh Solanki 				  enum hwmon_sensor_types type,
4760f33272bSNaresh Solanki 				  u32 attr, int channel)
4770f33272bSNaresh Solanki {
4780f33272bSNaresh Solanki 	switch (type) {
4790f33272bSNaresh Solanki 	case hwmon_fan:
4800f33272bSNaresh Solanki 		return max6639_fan_is_visible(data, attr, channel);
4810f33272bSNaresh Solanki 	case hwmon_pwm:
4820f33272bSNaresh Solanki 		return max6639_pwm_is_visible(data, attr, channel);
4830f33272bSNaresh Solanki 	case hwmon_temp:
4840f33272bSNaresh Solanki 		return max6639_temp_is_visible(data, attr, channel);
4850f33272bSNaresh Solanki 	default:
4860f33272bSNaresh Solanki 		return 0;
4870f33272bSNaresh Solanki 	}
4880f33272bSNaresh Solanki }
4890f33272bSNaresh Solanki 
4900f33272bSNaresh Solanki static const struct hwmon_channel_info * const max6639_info[] = {
4910f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(fan,
492842b4d98SNaresh Solanki 			   HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES,
493842b4d98SNaresh Solanki 			   HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_PULSES),
4940f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(pwm,
495842b4d98SNaresh Solanki 			   HWMON_PWM_INPUT | HWMON_PWM_FREQ,
496842b4d98SNaresh Solanki 			   HWMON_PWM_INPUT | HWMON_PWM_FREQ),
4970f33272bSNaresh Solanki 	HWMON_CHANNEL_INFO(temp,
4980f33272bSNaresh Solanki 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM |
4990f33272bSNaresh Solanki 			   HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY |
5000f33272bSNaresh Solanki 			   HWMON_T_EMERGENCY_ALARM,
5010f33272bSNaresh Solanki 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_MAX | HWMON_T_MAX_ALARM |
5020f33272bSNaresh Solanki 			   HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY |
5030f33272bSNaresh Solanki 			   HWMON_T_EMERGENCY_ALARM),
504a5b79d62Sstigge@antcom.de 	NULL
505a5b79d62Sstigge@antcom.de };
5060f33272bSNaresh Solanki 
5070f33272bSNaresh Solanki static const struct hwmon_ops max6639_hwmon_ops = {
5080f33272bSNaresh Solanki 	.is_visible = max6639_is_visible,
5090f33272bSNaresh Solanki 	.read = max6639_read,
5100f33272bSNaresh Solanki 	.write = max6639_write,
5110f33272bSNaresh Solanki };
5120f33272bSNaresh Solanki 
5130f33272bSNaresh Solanki static const struct hwmon_chip_info max6639_chip_info = {
5140f33272bSNaresh Solanki 	.ops = &max6639_hwmon_ops,
5150f33272bSNaresh Solanki 	.info = max6639_info,
5160f33272bSNaresh Solanki };
517a5b79d62Sstigge@antcom.de 
518a5b79d62Sstigge@antcom.de /*
519a5b79d62Sstigge@antcom.de  *  returns respective index in rpm_ranges table
520a5b79d62Sstigge@antcom.de  *  1 by default on invalid range
521a5b79d62Sstigge@antcom.de  */
rpm_range_to_reg(int range)522a5b79d62Sstigge@antcom.de static int rpm_range_to_reg(int range)
523a5b79d62Sstigge@antcom.de {
524a5b79d62Sstigge@antcom.de 	int i;
525a5b79d62Sstigge@antcom.de 
526a5b79d62Sstigge@antcom.de 	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
527a5b79d62Sstigge@antcom.de 		if (rpm_ranges[i] == range)
528a5b79d62Sstigge@antcom.de 			return i;
529a5b79d62Sstigge@antcom.de 	}
530a5b79d62Sstigge@antcom.de 
531a5b79d62Sstigge@antcom.de 	return 1; /* default: 4000 RPM */
532a5b79d62Sstigge@antcom.de }
533a5b79d62Sstigge@antcom.de 
max6639_init_client(struct i2c_client * client,struct max6639_data * data)5347981c584SGuenter Roeck static int max6639_init_client(struct i2c_client *client,
5357981c584SGuenter Roeck 			       struct max6639_data *data)
536a5b79d62Sstigge@antcom.de {
537a5b79d62Sstigge@antcom.de 	struct max6639_platform_data *max6639_info =
538a8b3a3a5SJingoo Han 		dev_get_platdata(&client->dev);
5392f2da1acSChris D Schimp 	int i;
540a5b79d62Sstigge@antcom.de 	int rpm_range = 1; /* default: 4000 RPM */
54145bf8305SNaresh Solanki 	int err, ppr;
542a5b79d62Sstigge@antcom.de 
543177f3b92Sstigge@antcom.de 	/* Reset chip to default values, see below for GCONFIG setup */
54445bf8305SNaresh Solanki 	err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR);
545a5b79d62Sstigge@antcom.de 	if (err)
54645bf8305SNaresh Solanki 		return err;
547a5b79d62Sstigge@antcom.de 
548a5b79d62Sstigge@antcom.de 	/* Fans pulse per revolution is 2 by default */
549a5b79d62Sstigge@antcom.de 	if (max6639_info && max6639_info->ppr > 0 &&
550a5b79d62Sstigge@antcom.de 			max6639_info->ppr < 5)
55145bf8305SNaresh Solanki 		ppr = max6639_info->ppr;
552a5b79d62Sstigge@antcom.de 	else
55345bf8305SNaresh Solanki 		ppr = 2;
5540f33272bSNaresh Solanki 
5550f33272bSNaresh Solanki 	data->ppr[0] = ppr;
5560f33272bSNaresh Solanki 	data->ppr[1] = ppr;
557a5b79d62Sstigge@antcom.de 
558a5b79d62Sstigge@antcom.de 	if (max6639_info)
559a5b79d62Sstigge@antcom.de 		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
5600f33272bSNaresh Solanki 	data->rpm_range[0] = rpm_range;
5610f33272bSNaresh Solanki 	data->rpm_range[1] = rpm_range;
562a5b79d62Sstigge@antcom.de 
56345bf8305SNaresh Solanki 	for (i = 0; i < MAX6639_NUM_CHANNELS; i++) {
5642f2da1acSChris D Schimp 		/* Set Fan pulse per revolution */
5650f33272bSNaresh Solanki 		err = max6639_set_ppr(data, i, data->ppr[i]);
5662f2da1acSChris D Schimp 		if (err)
56745bf8305SNaresh Solanki 			return err;
5682f2da1acSChris D Schimp 
569a5b79d62Sstigge@antcom.de 		/* Fans config PWM, RPM */
57045bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i),
5710f33272bSNaresh Solanki 				   MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]);
572a5b79d62Sstigge@antcom.de 		if (err)
57345bf8305SNaresh Solanki 			return err;
574a5b79d62Sstigge@antcom.de 
575a5b79d62Sstigge@antcom.de 		/* Fans PWM polarity high by default */
5760f33272bSNaresh Solanki 		if (max6639_info) {
5770f33272bSNaresh Solanki 			if (max6639_info->pwm_polarity == 0)
57845bf8305SNaresh Solanki 				err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
579a5b79d62Sstigge@antcom.de 			else
58045bf8305SNaresh Solanki 				err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
5810f33272bSNaresh Solanki 		}
582a5b79d62Sstigge@antcom.de 		if (err)
58345bf8305SNaresh Solanki 			return err;
584a5b79d62Sstigge@antcom.de 
585177f3b92Sstigge@antcom.de 		/*
586177f3b92Sstigge@antcom.de 		 * /THERM full speed enable,
587177f3b92Sstigge@antcom.de 		 * PWM frequency 25kHz, see also GCONFIG below
588177f3b92Sstigge@antcom.de 		 */
58945bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i),
590177f3b92Sstigge@antcom.de 				   MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
591177f3b92Sstigge@antcom.de 		if (err)
59245bf8305SNaresh Solanki 			return err;
593177f3b92Sstigge@antcom.de 
594a5b79d62Sstigge@antcom.de 		/* Max. temp. 80C/90C/100C */
59545bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80);
596a5b79d62Sstigge@antcom.de 		if (err)
59745bf8305SNaresh Solanki 			return err;
59845bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90);
599a5b79d62Sstigge@antcom.de 		if (err)
60045bf8305SNaresh Solanki 			return err;
60145bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100);
602a5b79d62Sstigge@antcom.de 		if (err)
60345bf8305SNaresh Solanki 			return err;
604a5b79d62Sstigge@antcom.de 
605a5b79d62Sstigge@antcom.de 		/* PWM 120/120 (i.e. 100%) */
60645bf8305SNaresh Solanki 		err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120);
607a5b79d62Sstigge@antcom.de 		if (err)
60845bf8305SNaresh Solanki 			return err;
609a5b79d62Sstigge@antcom.de 	}
610a5b79d62Sstigge@antcom.de 	/* Start monitoring */
61145bf8305SNaresh Solanki 	return regmap_write(data->regmap, MAX6639_REG_GCONFIG,
612177f3b92Sstigge@antcom.de 			    MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
613177f3b92Sstigge@antcom.de 			    MAX6639_GCONFIG_PWM_FREQ_HI);
61445bf8305SNaresh Solanki 
615a5b79d62Sstigge@antcom.de }
616a5b79d62Sstigge@antcom.de 
617a5b79d62Sstigge@antcom.de /* Return 0 if detection is successful, -ENODEV otherwise */
max6639_detect(struct i2c_client * client,struct i2c_board_info * info)618a5b79d62Sstigge@antcom.de static int max6639_detect(struct i2c_client *client,
619a5b79d62Sstigge@antcom.de 			  struct i2c_board_info *info)
620a5b79d62Sstigge@antcom.de {
621a5b79d62Sstigge@antcom.de 	struct i2c_adapter *adapter = client->adapter;
622a5b79d62Sstigge@antcom.de 	int dev_id, manu_id;
623a5b79d62Sstigge@antcom.de 
624a5b79d62Sstigge@antcom.de 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
625a5b79d62Sstigge@antcom.de 		return -ENODEV;
626a5b79d62Sstigge@antcom.de 
627a5b79d62Sstigge@antcom.de 	/* Actual detection via device and manufacturer ID */
628a5b79d62Sstigge@antcom.de 	dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID);
629a5b79d62Sstigge@antcom.de 	manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID);
630a5b79d62Sstigge@antcom.de 	if (dev_id != 0x58 || manu_id != 0x4D)
631a5b79d62Sstigge@antcom.de 		return -ENODEV;
632a5b79d62Sstigge@antcom.de 
633f2f394dbSWolfram Sang 	strscpy(info->type, "max6639", I2C_NAME_SIZE);
634a5b79d62Sstigge@antcom.de 
635a5b79d62Sstigge@antcom.de 	return 0;
636a5b79d62Sstigge@antcom.de }
637a5b79d62Sstigge@antcom.de 
max6639_regulator_disable(void * data)6384e2271eaSMarcello Sylvester Bauer static void max6639_regulator_disable(void *data)
6394e2271eaSMarcello Sylvester Bauer {
6404e2271eaSMarcello Sylvester Bauer 	regulator_disable(data);
6414e2271eaSMarcello Sylvester Bauer }
6424e2271eaSMarcello Sylvester Bauer 
max6639_regmap_is_volatile(struct device * dev,unsigned int reg)64345bf8305SNaresh Solanki static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg)
64445bf8305SNaresh Solanki {
64545bf8305SNaresh Solanki 	switch (reg) {
64645bf8305SNaresh Solanki 	case MAX6639_REG_TEMP(0):
64745bf8305SNaresh Solanki 	case MAX6639_REG_TEMP_EXT(0):
64845bf8305SNaresh Solanki 	case MAX6639_REG_TEMP(1):
64945bf8305SNaresh Solanki 	case MAX6639_REG_TEMP_EXT(1):
65045bf8305SNaresh Solanki 	case MAX6639_REG_STATUS:
65145bf8305SNaresh Solanki 	case MAX6639_REG_FAN_CNT(0):
65245bf8305SNaresh Solanki 	case MAX6639_REG_FAN_CNT(1):
65345bf8305SNaresh Solanki 	case MAX6639_REG_TARGTDUTY(0):
65445bf8305SNaresh Solanki 	case MAX6639_REG_TARGTDUTY(1):
65545bf8305SNaresh Solanki 		return true;
65645bf8305SNaresh Solanki 	default:
65745bf8305SNaresh Solanki 		return false;
65845bf8305SNaresh Solanki 	}
65945bf8305SNaresh Solanki }
66045bf8305SNaresh Solanki 
66145bf8305SNaresh Solanki static const struct regmap_config max6639_regmap_config = {
66245bf8305SNaresh Solanki 	.reg_bits = 8,
66345bf8305SNaresh Solanki 	.val_bits = 8,
66445bf8305SNaresh Solanki 	.max_register = MAX6639_REG_DEVREV,
66545bf8305SNaresh Solanki 	.cache_type = REGCACHE_MAPLE,
66645bf8305SNaresh Solanki 	.volatile_reg = max6639_regmap_is_volatile,
66745bf8305SNaresh Solanki };
66845bf8305SNaresh Solanki 
max6639_probe(struct i2c_client * client)66967487038SStephen Kitt static int max6639_probe(struct i2c_client *client)
670a5b79d62Sstigge@antcom.de {
671c1ea0a04SGuenter Roeck 	struct device *dev = &client->dev;
672a5b79d62Sstigge@antcom.de 	struct max6639_data *data;
6737981c584SGuenter Roeck 	struct device *hwmon_dev;
674a5b79d62Sstigge@antcom.de 	int err;
675a5b79d62Sstigge@antcom.de 
676c1ea0a04SGuenter Roeck 	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
677b07405fbSGuenter Roeck 	if (!data)
678b07405fbSGuenter Roeck 		return -ENOMEM;
679a5b79d62Sstigge@antcom.de 
68045bf8305SNaresh Solanki 	data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config);
68145bf8305SNaresh Solanki 	if (IS_ERR(data->regmap))
68245bf8305SNaresh Solanki 		return dev_err_probe(dev,
68345bf8305SNaresh Solanki 				     PTR_ERR(data->regmap),
68445bf8305SNaresh Solanki 				     "regmap initialization failed\n");
6854e2271eaSMarcello Sylvester Bauer 
6864e2271eaSMarcello Sylvester Bauer 	data->reg = devm_regulator_get_optional(dev, "fan");
6874e2271eaSMarcello Sylvester Bauer 	if (IS_ERR(data->reg)) {
6884e2271eaSMarcello Sylvester Bauer 		if (PTR_ERR(data->reg) != -ENODEV)
6894e2271eaSMarcello Sylvester Bauer 			return PTR_ERR(data->reg);
6904e2271eaSMarcello Sylvester Bauer 
6914e2271eaSMarcello Sylvester Bauer 		data->reg = NULL;
6924e2271eaSMarcello Sylvester Bauer 	} else {
6934e2271eaSMarcello Sylvester Bauer 		/* Spin up fans */
6944e2271eaSMarcello Sylvester Bauer 		err = regulator_enable(data->reg);
6954e2271eaSMarcello Sylvester Bauer 		if (err) {
6964e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to enable fan supply: %d\n", err);
6974e2271eaSMarcello Sylvester Bauer 			return err;
6984e2271eaSMarcello Sylvester Bauer 		}
6994e2271eaSMarcello Sylvester Bauer 		err = devm_add_action_or_reset(dev, max6639_regulator_disable,
7004e2271eaSMarcello Sylvester Bauer 					       data->reg);
7014e2271eaSMarcello Sylvester Bauer 		if (err) {
7024e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to register action: %d\n", err);
7034e2271eaSMarcello Sylvester Bauer 			return err;
7044e2271eaSMarcello Sylvester Bauer 		}
7054e2271eaSMarcello Sylvester Bauer 	}
7064e2271eaSMarcello Sylvester Bauer 
707842b4d98SNaresh Solanki 	mutex_init(&data->update_lock);
708842b4d98SNaresh Solanki 
709a5b79d62Sstigge@antcom.de 	/* Initialize the max6639 chip */
7107981c584SGuenter Roeck 	err = max6639_init_client(client, data);
711a5b79d62Sstigge@antcom.de 	if (err < 0)
712b07405fbSGuenter Roeck 		return err;
713a5b79d62Sstigge@antcom.de 
7140f33272bSNaresh Solanki 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
7150f33272bSNaresh Solanki 							 data, &max6639_chip_info,
7160f33272bSNaresh Solanki 							 NULL);
7170f33272bSNaresh Solanki 
7187981c584SGuenter Roeck 	return PTR_ERR_OR_ZERO(hwmon_dev);
719a5b79d62Sstigge@antcom.de }
720a5b79d62Sstigge@antcom.de 
max6639_suspend(struct device * dev)72152f30f77SMark Brown static int max6639_suspend(struct device *dev)
722a5b79d62Sstigge@antcom.de {
7234e2271eaSMarcello Sylvester Bauer 	struct max6639_data *data = dev_get_drvdata(dev);
7244e2271eaSMarcello Sylvester Bauer 
7254e2271eaSMarcello Sylvester Bauer 	if (data->reg)
7264e2271eaSMarcello Sylvester Bauer 		regulator_disable(data->reg);
727a5b79d62Sstigge@antcom.de 
72845bf8305SNaresh Solanki 	return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
72945bf8305SNaresh Solanki 				 MAX6639_GCONFIG_STANDBY);
730a5b79d62Sstigge@antcom.de }
731a5b79d62Sstigge@antcom.de 
max6639_resume(struct device * dev)73252f30f77SMark Brown static int max6639_resume(struct device *dev)
733a5b79d62Sstigge@antcom.de {
7344e2271eaSMarcello Sylvester Bauer 	struct max6639_data *data = dev_get_drvdata(dev);
7354e2271eaSMarcello Sylvester Bauer 	int ret;
7364e2271eaSMarcello Sylvester Bauer 
7374e2271eaSMarcello Sylvester Bauer 	if (data->reg) {
7384e2271eaSMarcello Sylvester Bauer 		ret = regulator_enable(data->reg);
7394e2271eaSMarcello Sylvester Bauer 		if (ret) {
7404e2271eaSMarcello Sylvester Bauer 			dev_err(dev, "Failed to enable fan supply: %d\n", ret);
7414e2271eaSMarcello Sylvester Bauer 			return ret;
7424e2271eaSMarcello Sylvester Bauer 		}
7434e2271eaSMarcello Sylvester Bauer 	}
7444e2271eaSMarcello Sylvester Bauer 
74545bf8305SNaresh Solanki 	return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
74645bf8305SNaresh Solanki 				 ~MAX6639_GCONFIG_STANDBY);
747a5b79d62Sstigge@antcom.de }
748a5b79d62Sstigge@antcom.de 
749a5b79d62Sstigge@antcom.de static const struct i2c_device_id max6639_id[] = {
750d8a66f36SUwe Kleine-König 	{"max6639"},
751a5b79d62Sstigge@antcom.de 	{ }
752a5b79d62Sstigge@antcom.de };
753a5b79d62Sstigge@antcom.de 
754a5b79d62Sstigge@antcom.de MODULE_DEVICE_TABLE(i2c, max6639_id);
755a5b79d62Sstigge@antcom.de 
75677563092SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
75752f30f77SMark Brown 
758f11e2738SNaresh Solanki static const struct of_device_id max6639_of_match[] = {
759f11e2738SNaresh Solanki 	{ .compatible = "maxim,max6639", },
760f11e2738SNaresh Solanki 	{ },
761f11e2738SNaresh Solanki };
762f11e2738SNaresh Solanki 
763a5b79d62Sstigge@antcom.de static struct i2c_driver max6639_driver = {
764a5b79d62Sstigge@antcom.de 	.class = I2C_CLASS_HWMON,
765a5b79d62Sstigge@antcom.de 	.driver = {
766a5b79d62Sstigge@antcom.de 		   .name = "max6639",
76777563092SJonathan Cameron 		   .pm = pm_sleep_ptr(&max6639_pm_ops),
768f11e2738SNaresh Solanki 		   .of_match_table = max6639_of_match,
769a5b79d62Sstigge@antcom.de 		   },
7701975d167SUwe Kleine-König 	.probe = max6639_probe,
771a5b79d62Sstigge@antcom.de 	.id_table = max6639_id,
772a5b79d62Sstigge@antcom.de 	.detect = max6639_detect,
773a5b79d62Sstigge@antcom.de 	.address_list = normal_i2c,
774a5b79d62Sstigge@antcom.de };
775a5b79d62Sstigge@antcom.de 
776f0967eeaSAxel Lin module_i2c_driver(max6639_driver);
777a5b79d62Sstigge@antcom.de 
778a5b79d62Sstigge@antcom.de MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
779a5b79d62Sstigge@antcom.de MODULE_DESCRIPTION("max6639 driver");
780a5b79d62Sstigge@antcom.de MODULE_LICENSE("GPL");
781