xref: /openbmc/linux/drivers/hwmon/pmbus/max31785.c (revision 00783d5ee2916278eae8283a7547a95c37506cc7)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24d420a6aSAndrew Jeffery /*
34d420a6aSAndrew Jeffery  * Copyright (C) 2017 IBM Corp.
44d420a6aSAndrew Jeffery  */
54d420a6aSAndrew Jeffery 
64d420a6aSAndrew Jeffery #include <linux/kernel.h>
74d420a6aSAndrew Jeffery #include <linux/module.h>
84d420a6aSAndrew Jeffery #include <linux/init.h>
94d420a6aSAndrew Jeffery #include <linux/err.h>
104d420a6aSAndrew Jeffery #include <linux/i2c.h>
114d420a6aSAndrew Jeffery #include "pmbus.h"
124d420a6aSAndrew Jeffery 
134d420a6aSAndrew Jeffery enum max31785_regs {
144d420a6aSAndrew Jeffery 	MFR_REVISION		= 0x9b,
15*00783d5eSAndrew Jeffery 	MFR_FAULT_RESPONSE	= 0xd9,
16*00783d5eSAndrew Jeffery 	MFR_TEMP_SENSOR_CONFIG	= 0xf0,
17cf583b42SAndrew Jeffery 	MFR_FAN_CONFIG		= 0xf1,
18*00783d5eSAndrew Jeffery 	MFR_FAN_FAULT_LIMIT	= 0xf5,
194d420a6aSAndrew Jeffery };
204d420a6aSAndrew Jeffery 
21cf583b42SAndrew Jeffery #define MAX31785			0x3030
22cf583b42SAndrew Jeffery #define MAX31785A			0x3040
23996dc09cSMatthew Barth #define MAX31785B			0x3061
24cf583b42SAndrew Jeffery 
25cf583b42SAndrew Jeffery #define MFR_FAN_CONFIG_DUAL_TACH	BIT(12)
26*00783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_TSFO		BIT(9)
27*00783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_TACHO		BIT(8)
28*00783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_HEALTH		BIT(4)
29*00783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_ROTOR_HI_LO	BIT(3)
30*00783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_ROTOR		BIT(2)
31*00783d5eSAndrew Jeffery 
32*00783d5eSAndrew Jeffery #define MFR_FAULT_RESPONSE_MONITOR	BIT(0)
33cf583b42SAndrew Jeffery 
344d420a6aSAndrew Jeffery #define MAX31785_NR_PAGES		23
35cf583b42SAndrew Jeffery #define MAX31785_NR_FAN_PAGES		6
36cf583b42SAndrew Jeffery 
37cf583b42SAndrew Jeffery static int max31785_read_byte_data(struct i2c_client *client, int page,
38cf583b42SAndrew Jeffery 				   int reg)
39cf583b42SAndrew Jeffery {
40cf583b42SAndrew Jeffery 	if (page < MAX31785_NR_PAGES)
41cf583b42SAndrew Jeffery 		return -ENODATA;
42cf583b42SAndrew Jeffery 
43cf583b42SAndrew Jeffery 	switch (reg) {
44cf583b42SAndrew Jeffery 	case PMBUS_VOUT_MODE:
45cf583b42SAndrew Jeffery 		return -ENOTSUPP;
46cf583b42SAndrew Jeffery 	case PMBUS_FAN_CONFIG_12:
47cf583b42SAndrew Jeffery 		return pmbus_read_byte_data(client, page - MAX31785_NR_PAGES,
48cf583b42SAndrew Jeffery 					    reg);
49cf583b42SAndrew Jeffery 	}
50cf583b42SAndrew Jeffery 
51cf583b42SAndrew Jeffery 	return -ENODATA;
52cf583b42SAndrew Jeffery }
53cf583b42SAndrew Jeffery 
54cf583b42SAndrew Jeffery static int max31785_write_byte(struct i2c_client *client, int page, u8 value)
55cf583b42SAndrew Jeffery {
56cf583b42SAndrew Jeffery 	if (page < MAX31785_NR_PAGES)
57cf583b42SAndrew Jeffery 		return -ENODATA;
58cf583b42SAndrew Jeffery 
59cf583b42SAndrew Jeffery 	return -ENOTSUPP;
60cf583b42SAndrew Jeffery }
61cf583b42SAndrew Jeffery 
62cf583b42SAndrew Jeffery static int max31785_read_long_data(struct i2c_client *client, int page,
63cf583b42SAndrew Jeffery 				   int reg, u32 *data)
64cf583b42SAndrew Jeffery {
65cf583b42SAndrew Jeffery 	unsigned char cmdbuf[1];
66cf583b42SAndrew Jeffery 	unsigned char rspbuf[4];
67cf583b42SAndrew Jeffery 	int rc;
68cf583b42SAndrew Jeffery 
69cf583b42SAndrew Jeffery 	struct i2c_msg msg[2] = {
70cf583b42SAndrew Jeffery 		{
71cf583b42SAndrew Jeffery 			.addr = client->addr,
72cf583b42SAndrew Jeffery 			.flags = 0,
73cf583b42SAndrew Jeffery 			.len = sizeof(cmdbuf),
74cf583b42SAndrew Jeffery 			.buf = cmdbuf,
75cf583b42SAndrew Jeffery 		},
76cf583b42SAndrew Jeffery 		{
77cf583b42SAndrew Jeffery 			.addr = client->addr,
78cf583b42SAndrew Jeffery 			.flags = I2C_M_RD,
79cf583b42SAndrew Jeffery 			.len = sizeof(rspbuf),
80cf583b42SAndrew Jeffery 			.buf = rspbuf,
81cf583b42SAndrew Jeffery 		},
82cf583b42SAndrew Jeffery 	};
83cf583b42SAndrew Jeffery 
84cf583b42SAndrew Jeffery 	cmdbuf[0] = reg;
85cf583b42SAndrew Jeffery 
8643f33b6eSGuenter Roeck 	rc = pmbus_set_page(client, page, 0xff);
87cf583b42SAndrew Jeffery 	if (rc < 0)
88cf583b42SAndrew Jeffery 		return rc;
89cf583b42SAndrew Jeffery 
90cf583b42SAndrew Jeffery 	rc = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
91cf583b42SAndrew Jeffery 	if (rc < 0)
92cf583b42SAndrew Jeffery 		return rc;
93cf583b42SAndrew Jeffery 
94cf583b42SAndrew Jeffery 	*data = (rspbuf[0] << (0 * 8)) | (rspbuf[1] << (1 * 8)) |
95cf583b42SAndrew Jeffery 		(rspbuf[2] << (2 * 8)) | (rspbuf[3] << (3 * 8));
96cf583b42SAndrew Jeffery 
97cf583b42SAndrew Jeffery 	return rc;
98cf583b42SAndrew Jeffery }
994d420a6aSAndrew Jeffery 
10056ad86b4SAndrew Jeffery static int max31785_get_pwm(struct i2c_client *client, int page)
10156ad86b4SAndrew Jeffery {
10256ad86b4SAndrew Jeffery 	int rv;
10356ad86b4SAndrew Jeffery 
10456ad86b4SAndrew Jeffery 	rv = pmbus_get_fan_rate_device(client, page, 0, percent);
10556ad86b4SAndrew Jeffery 	if (rv < 0)
10656ad86b4SAndrew Jeffery 		return rv;
10756ad86b4SAndrew Jeffery 	else if (rv >= 0x8000)
10856ad86b4SAndrew Jeffery 		return 0;
10956ad86b4SAndrew Jeffery 	else if (rv >= 0x2711)
11056ad86b4SAndrew Jeffery 		return 0x2710;
11156ad86b4SAndrew Jeffery 
11256ad86b4SAndrew Jeffery 	return rv;
11356ad86b4SAndrew Jeffery }
11456ad86b4SAndrew Jeffery 
11556ad86b4SAndrew Jeffery static int max31785_get_pwm_mode(struct i2c_client *client, int page)
11656ad86b4SAndrew Jeffery {
11756ad86b4SAndrew Jeffery 	int config;
11856ad86b4SAndrew Jeffery 	int command;
11956ad86b4SAndrew Jeffery 
12056ad86b4SAndrew Jeffery 	config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
12156ad86b4SAndrew Jeffery 	if (config < 0)
12256ad86b4SAndrew Jeffery 		return config;
12356ad86b4SAndrew Jeffery 
12443f33b6eSGuenter Roeck 	command = pmbus_read_word_data(client, page, 0xff, PMBUS_FAN_COMMAND_1);
12556ad86b4SAndrew Jeffery 	if (command < 0)
12656ad86b4SAndrew Jeffery 		return command;
12756ad86b4SAndrew Jeffery 
12856ad86b4SAndrew Jeffery 	if (config & PB_FAN_1_RPM)
12956ad86b4SAndrew Jeffery 		return (command >= 0x8000) ? 3 : 2;
13056ad86b4SAndrew Jeffery 
13156ad86b4SAndrew Jeffery 	if (command >= 0x8000)
13256ad86b4SAndrew Jeffery 		return 3;
13356ad86b4SAndrew Jeffery 	else if (command >= 0x2711)
13456ad86b4SAndrew Jeffery 		return 0;
13556ad86b4SAndrew Jeffery 
13656ad86b4SAndrew Jeffery 	return 1;
13756ad86b4SAndrew Jeffery }
13856ad86b4SAndrew Jeffery 
13956ad86b4SAndrew Jeffery static int max31785_read_word_data(struct i2c_client *client, int page,
14043f33b6eSGuenter Roeck 				   int phase, int reg)
14156ad86b4SAndrew Jeffery {
142cf583b42SAndrew Jeffery 	u32 val;
14356ad86b4SAndrew Jeffery 	int rv;
14456ad86b4SAndrew Jeffery 
14556ad86b4SAndrew Jeffery 	switch (reg) {
146cf583b42SAndrew Jeffery 	case PMBUS_READ_FAN_SPEED_1:
147cf583b42SAndrew Jeffery 		if (page < MAX31785_NR_PAGES)
148cf583b42SAndrew Jeffery 			return -ENODATA;
149cf583b42SAndrew Jeffery 
150cf583b42SAndrew Jeffery 		rv = max31785_read_long_data(client, page - MAX31785_NR_PAGES,
151cf583b42SAndrew Jeffery 					     reg, &val);
152cf583b42SAndrew Jeffery 		if (rv < 0)
153cf583b42SAndrew Jeffery 			return rv;
154cf583b42SAndrew Jeffery 
155cf583b42SAndrew Jeffery 		rv = (val >> 16) & 0xffff;
156cf583b42SAndrew Jeffery 		break;
157cf583b42SAndrew Jeffery 	case PMBUS_FAN_COMMAND_1:
158cf583b42SAndrew Jeffery 		/*
159cf583b42SAndrew Jeffery 		 * PMBUS_FAN_COMMAND_x is probed to judge whether or not to
160cf583b42SAndrew Jeffery 		 * expose fan control registers.
161cf583b42SAndrew Jeffery 		 *
162cf583b42SAndrew Jeffery 		 * Don't expose fan_target attribute for virtual pages.
163cf583b42SAndrew Jeffery 		 */
164cf583b42SAndrew Jeffery 		rv = (page >= MAX31785_NR_PAGES) ? -ENOTSUPP : -ENODATA;
165cf583b42SAndrew Jeffery 		break;
16656ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_1:
16756ad86b4SAndrew Jeffery 		rv = max31785_get_pwm(client, page);
16856ad86b4SAndrew Jeffery 		break;
16956ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_ENABLE_1:
17056ad86b4SAndrew Jeffery 		rv = max31785_get_pwm_mode(client, page);
17156ad86b4SAndrew Jeffery 		break;
17256ad86b4SAndrew Jeffery 	default:
17356ad86b4SAndrew Jeffery 		rv = -ENODATA;
17456ad86b4SAndrew Jeffery 		break;
17556ad86b4SAndrew Jeffery 	}
17656ad86b4SAndrew Jeffery 
17756ad86b4SAndrew Jeffery 	return rv;
17856ad86b4SAndrew Jeffery }
17956ad86b4SAndrew Jeffery 
18056ad86b4SAndrew Jeffery static inline u32 max31785_scale_pwm(u32 sensor_val)
18156ad86b4SAndrew Jeffery {
18256ad86b4SAndrew Jeffery 	/*
18356ad86b4SAndrew Jeffery 	 * The datasheet describes the accepted value range for manual PWM as
18456ad86b4SAndrew Jeffery 	 * [0, 0x2710], while the hwmon pwmX sysfs interface accepts values in
18556ad86b4SAndrew Jeffery 	 * [0, 255]. The MAX31785 uses DIRECT mode to scale the FAN_COMMAND
18656ad86b4SAndrew Jeffery 	 * registers and in PWM mode the coefficients are m=1, b=0, R=2. The
18756ad86b4SAndrew Jeffery 	 * important observation here is that 0x2710 == 10000 == 100 * 100.
18856ad86b4SAndrew Jeffery 	 *
18956ad86b4SAndrew Jeffery 	 * R=2 (== 10^2 == 100) accounts for scaling the value provided at the
19056ad86b4SAndrew Jeffery 	 * sysfs interface into the required hardware resolution, but it does
19156ad86b4SAndrew Jeffery 	 * not yet yield a value that we can write to the device (this initial
19256ad86b4SAndrew Jeffery 	 * scaling is handled by pmbus_data2reg()). Multiplying by 100 below
19356ad86b4SAndrew Jeffery 	 * translates the parameter value into the percentage units required by
19456ad86b4SAndrew Jeffery 	 * PMBus, and then we scale back by 255 as required by the hwmon pwmX
19556ad86b4SAndrew Jeffery 	 * interface to yield the percentage value at the appropriate
19656ad86b4SAndrew Jeffery 	 * resolution for hardware.
19756ad86b4SAndrew Jeffery 	 */
19856ad86b4SAndrew Jeffery 	return (sensor_val * 100) / 255;
19956ad86b4SAndrew Jeffery }
20056ad86b4SAndrew Jeffery 
20156ad86b4SAndrew Jeffery static int max31785_pwm_enable(struct i2c_client *client, int page,
20256ad86b4SAndrew Jeffery 				    u16 word)
20356ad86b4SAndrew Jeffery {
20456ad86b4SAndrew Jeffery 	int config = 0;
20556ad86b4SAndrew Jeffery 	int rate;
20656ad86b4SAndrew Jeffery 
20756ad86b4SAndrew Jeffery 	switch (word) {
20856ad86b4SAndrew Jeffery 	case 0:
20956ad86b4SAndrew Jeffery 		rate = 0x7fff;
21056ad86b4SAndrew Jeffery 		break;
21156ad86b4SAndrew Jeffery 	case 1:
21256ad86b4SAndrew Jeffery 		rate = pmbus_get_fan_rate_cached(client, page, 0, percent);
21356ad86b4SAndrew Jeffery 		if (rate < 0)
21456ad86b4SAndrew Jeffery 			return rate;
21556ad86b4SAndrew Jeffery 		rate = max31785_scale_pwm(rate);
21656ad86b4SAndrew Jeffery 		break;
21756ad86b4SAndrew Jeffery 	case 2:
21856ad86b4SAndrew Jeffery 		config = PB_FAN_1_RPM;
21956ad86b4SAndrew Jeffery 		rate = pmbus_get_fan_rate_cached(client, page, 0, rpm);
22056ad86b4SAndrew Jeffery 		if (rate < 0)
22156ad86b4SAndrew Jeffery 			return rate;
22256ad86b4SAndrew Jeffery 		break;
22356ad86b4SAndrew Jeffery 	case 3:
22456ad86b4SAndrew Jeffery 		rate = 0xffff;
22556ad86b4SAndrew Jeffery 		break;
22656ad86b4SAndrew Jeffery 	default:
22756ad86b4SAndrew Jeffery 		return -EINVAL;
22856ad86b4SAndrew Jeffery 	}
22956ad86b4SAndrew Jeffery 
23056ad86b4SAndrew Jeffery 	return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate);
23156ad86b4SAndrew Jeffery }
23256ad86b4SAndrew Jeffery 
23356ad86b4SAndrew Jeffery static int max31785_write_word_data(struct i2c_client *client, int page,
23456ad86b4SAndrew Jeffery 				    int reg, u16 word)
23556ad86b4SAndrew Jeffery {
23656ad86b4SAndrew Jeffery 	switch (reg) {
23756ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_1:
23856ad86b4SAndrew Jeffery 		return pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM,
23956ad86b4SAndrew Jeffery 					max31785_scale_pwm(word));
24056ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_ENABLE_1:
24156ad86b4SAndrew Jeffery 		return max31785_pwm_enable(client, page, word);
24256ad86b4SAndrew Jeffery 	default:
24356ad86b4SAndrew Jeffery 		break;
24456ad86b4SAndrew Jeffery 	}
24556ad86b4SAndrew Jeffery 
24656ad86b4SAndrew Jeffery 	return -ENODATA;
24756ad86b4SAndrew Jeffery }
24856ad86b4SAndrew Jeffery 
249*00783d5eSAndrew Jeffery /*
250*00783d5eSAndrew Jeffery  * Returns negative error codes if an unrecoverable problem is detected, 0 if a
251*00783d5eSAndrew Jeffery  * recoverable problem is detected, or a positive value on success.
252*00783d5eSAndrew Jeffery  */
253*00783d5eSAndrew Jeffery static int max31785_of_fan_config(struct i2c_client *client,
254*00783d5eSAndrew Jeffery 				  struct pmbus_driver_info *info,
255*00783d5eSAndrew Jeffery 				  struct device_node *child)
256*00783d5eSAndrew Jeffery {
257*00783d5eSAndrew Jeffery 	int mfr_cfg = 0, mfr_fault_resp = 0, pb_cfg;
258*00783d5eSAndrew Jeffery 	struct device *dev = &client->dev;
259*00783d5eSAndrew Jeffery 	char *lock_polarity = NULL;
260*00783d5eSAndrew Jeffery 	const char *sval;
261*00783d5eSAndrew Jeffery 	u32 page;
262*00783d5eSAndrew Jeffery 	u32 uval;
263*00783d5eSAndrew Jeffery 	int ret;
264*00783d5eSAndrew Jeffery 
265*00783d5eSAndrew Jeffery 	if (!of_device_is_compatible(child, "pmbus-fan"))
266*00783d5eSAndrew Jeffery 		return 0;
267*00783d5eSAndrew Jeffery 
268*00783d5eSAndrew Jeffery 	ret = of_property_read_u32(child, "reg", &page);
269*00783d5eSAndrew Jeffery 	if (ret < 0) {
270*00783d5eSAndrew Jeffery 		dev_err(&client->dev, "Missing valid reg property\n");
271*00783d5eSAndrew Jeffery 		return ret;
272*00783d5eSAndrew Jeffery 	}
273*00783d5eSAndrew Jeffery 
274*00783d5eSAndrew Jeffery 	if (!(info->func[page] & PMBUS_HAVE_FAN12)) {
275*00783d5eSAndrew Jeffery 		dev_err(dev, "Page %d does not have fan capabilities\n", page);
276*00783d5eSAndrew Jeffery 		return -ENXIO;
277*00783d5eSAndrew Jeffery 	}
278*00783d5eSAndrew Jeffery 
279*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
280*00783d5eSAndrew Jeffery 	if (ret < 0)
281*00783d5eSAndrew Jeffery 		return ret;
282*00783d5eSAndrew Jeffery 
283*00783d5eSAndrew Jeffery 	pb_cfg = i2c_smbus_read_byte_data(client, PMBUS_FAN_CONFIG_12);
284*00783d5eSAndrew Jeffery 	if (pb_cfg < 0)
285*00783d5eSAndrew Jeffery 		return pb_cfg;
286*00783d5eSAndrew Jeffery 
287*00783d5eSAndrew Jeffery 	if (of_property_read_bool(child->parent, "use-stored-presence")) {
288*00783d5eSAndrew Jeffery 		if (!(pb_cfg & PB_FAN_1_INSTALLED))
289*00783d5eSAndrew Jeffery 			dev_info(dev, "Fan %d is configured but not installed\n",
290*00783d5eSAndrew Jeffery 				 page);
291*00783d5eSAndrew Jeffery 	} else {
292*00783d5eSAndrew Jeffery 		pb_cfg |= PB_FAN_1_INSTALLED;
293*00783d5eSAndrew Jeffery 	}
294*00783d5eSAndrew Jeffery 
295*00783d5eSAndrew Jeffery 	ret = of_property_read_string(child, "maxim,fan-rotor-input", &sval);
296*00783d5eSAndrew Jeffery 	if (ret < 0) {
297*00783d5eSAndrew Jeffery 		dev_err(dev, "Missing valid maxim,fan-rotor-input property for fan %d\n",
298*00783d5eSAndrew Jeffery 				page);
299*00783d5eSAndrew Jeffery 		return ret;
300*00783d5eSAndrew Jeffery 	}
301*00783d5eSAndrew Jeffery 
302*00783d5eSAndrew Jeffery 	if (strcmp("tach", sval) && strcmp("lock", sval)) {
303*00783d5eSAndrew Jeffery 		dev_err(dev, "maxim,fan-rotor-input has invalid value for fan %d: %s\n",
304*00783d5eSAndrew Jeffery 				page, sval);
305*00783d5eSAndrew Jeffery 		return -EINVAL;
306*00783d5eSAndrew Jeffery 	} else if (!strcmp("lock", sval)) {
307*00783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_ROTOR;
308*00783d5eSAndrew Jeffery 
309*00783d5eSAndrew Jeffery 		ret = i2c_smbus_write_word_data(client, MFR_FAN_FAULT_LIMIT, 1);
310*00783d5eSAndrew Jeffery 		if (ret < 0)
311*00783d5eSAndrew Jeffery 			return ret;
312*00783d5eSAndrew Jeffery 
313*00783d5eSAndrew Jeffery 		ret = of_property_read_string(child, "maxim,fan-lock-polarity",
314*00783d5eSAndrew Jeffery 					      &sval);
315*00783d5eSAndrew Jeffery 		if (ret < 0) {
316*00783d5eSAndrew Jeffery 			dev_err(dev, "Missing valid maxim,fan-lock-polarity property for fan %d\n",
317*00783d5eSAndrew Jeffery 					page);
318*00783d5eSAndrew Jeffery 			return ret;
319*00783d5eSAndrew Jeffery 		}
320*00783d5eSAndrew Jeffery 
321*00783d5eSAndrew Jeffery 		if (strcmp("low", sval) && strcmp("high", sval)) {
322*00783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-lock-polarity has invalid value for fan %d: %s\n",
323*00783d5eSAndrew Jeffery 					page, lock_polarity);
324*00783d5eSAndrew Jeffery 			return -EINVAL;
325*00783d5eSAndrew Jeffery 		} else if (!strcmp("high", sval))
326*00783d5eSAndrew Jeffery 			mfr_cfg |= MFR_FAN_CONFIG_ROTOR_HI_LO;
327*00783d5eSAndrew Jeffery 	}
328*00783d5eSAndrew Jeffery 
329*00783d5eSAndrew Jeffery 	if (!of_property_read_string(child, "fan-mode", &sval)) {
330*00783d5eSAndrew Jeffery 		if (!strcmp("rpm", sval))
331*00783d5eSAndrew Jeffery 			pb_cfg |= PB_FAN_1_RPM;
332*00783d5eSAndrew Jeffery 		else if (!strcmp("pwm", sval))
333*00783d5eSAndrew Jeffery 			pb_cfg &= ~PB_FAN_1_RPM;
334*00783d5eSAndrew Jeffery 		else {
335*00783d5eSAndrew Jeffery 			dev_err(dev, "fan-mode has invalid value for fan %d: %s\n",
336*00783d5eSAndrew Jeffery 					page, sval);
337*00783d5eSAndrew Jeffery 			return -EINVAL;
338*00783d5eSAndrew Jeffery 		}
339*00783d5eSAndrew Jeffery 	}
340*00783d5eSAndrew Jeffery 
341*00783d5eSAndrew Jeffery 	ret = of_property_read_u32(child, "tach-pulses", &uval);
342*00783d5eSAndrew Jeffery 	if (ret < 0) {
343*00783d5eSAndrew Jeffery 		pb_cfg &= ~PB_FAN_1_PULSE_MASK;
344*00783d5eSAndrew Jeffery 	} else if (uval && (uval - 1) < 4) {
345*00783d5eSAndrew Jeffery 		pb_cfg = ((pb_cfg & ~PB_FAN_1_PULSE_MASK) | ((uval - 1) << 4));
346*00783d5eSAndrew Jeffery 	} else {
347*00783d5eSAndrew Jeffery 		dev_err(dev, "tach-pulses has invalid value for fan %d: %u\n",
348*00783d5eSAndrew Jeffery 				page, uval);
349*00783d5eSAndrew Jeffery 		return -EINVAL;
350*00783d5eSAndrew Jeffery 	}
351*00783d5eSAndrew Jeffery 
352*00783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-health"))
353*00783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_HEALTH;
354*00783d5eSAndrew Jeffery 
355*00783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-no-watchdog") ||
356*00783d5eSAndrew Jeffery 		of_property_read_bool(child, "maxim,tmp-no-fault-ramp"))
357*00783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_TSFO;
358*00783d5eSAndrew Jeffery 
359*00783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-dual-tach"))
360*00783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_DUAL_TACH;
361*00783d5eSAndrew Jeffery 
362*00783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-no-fault-ramp"))
363*00783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_TACHO;
364*00783d5eSAndrew Jeffery 
365*00783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,fan-startup", &uval)) {
366*00783d5eSAndrew Jeffery 		uval /= 2;
367*00783d5eSAndrew Jeffery 		if (uval < 5) {
368*00783d5eSAndrew Jeffery 			mfr_cfg |= uval;
369*00783d5eSAndrew Jeffery 		} else {
370*00783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-startup has invalid value for fan %d: %u\n",
371*00783d5eSAndrew Jeffery 					page, uval);
372*00783d5eSAndrew Jeffery 			return -EINVAL;
373*00783d5eSAndrew Jeffery 		}
374*00783d5eSAndrew Jeffery 	}
375*00783d5eSAndrew Jeffery 
376*00783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,fan-ramp", &uval)) {
377*00783d5eSAndrew Jeffery 		if (uval < 8) {
378*00783d5eSAndrew Jeffery 			mfr_cfg |= uval << 5;
379*00783d5eSAndrew Jeffery 		} else {
380*00783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-ramp has invalid value for fan %d: %u\n",
381*00783d5eSAndrew Jeffery 					page, uval);
382*00783d5eSAndrew Jeffery 			return -EINVAL;
383*00783d5eSAndrew Jeffery 		}
384*00783d5eSAndrew Jeffery 	}
385*00783d5eSAndrew Jeffery 
386*00783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,tmp-hysteresis", &uval)) {
387*00783d5eSAndrew Jeffery 		uval /= 2;
388*00783d5eSAndrew Jeffery 		uval -= 1;
389*00783d5eSAndrew Jeffery 		if (uval < 4) {
390*00783d5eSAndrew Jeffery 			mfr_cfg |= uval << 10;
391*00783d5eSAndrew Jeffery 		} else {
392*00783d5eSAndrew Jeffery 			dev_err(dev, "maxim,tmp-hysteresis has invalid value for fan %d, %u\n",
393*00783d5eSAndrew Jeffery 					page, uval);
394*00783d5eSAndrew Jeffery 			return -EINVAL;
395*00783d5eSAndrew Jeffery 		}
396*00783d5eSAndrew Jeffery 	}
397*00783d5eSAndrew Jeffery 
398*00783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,fan-pwm-freq", &uval)) {
399*00783d5eSAndrew Jeffery 		u16 val;
400*00783d5eSAndrew Jeffery 
401*00783d5eSAndrew Jeffery 		if (uval == 30) {
402*00783d5eSAndrew Jeffery 			val = 0;
403*00783d5eSAndrew Jeffery 		} else if (uval == 50) {
404*00783d5eSAndrew Jeffery 			val = 1;
405*00783d5eSAndrew Jeffery 		} else if (uval == 100) {
406*00783d5eSAndrew Jeffery 			val = 2;
407*00783d5eSAndrew Jeffery 		} else if (uval == 150) {
408*00783d5eSAndrew Jeffery 			val = 3;
409*00783d5eSAndrew Jeffery 		} else if (uval == 25000) {
410*00783d5eSAndrew Jeffery 			val = 7;
411*00783d5eSAndrew Jeffery 		} else {
412*00783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-pwm-freq has invalid value for fan %d: %u\n",
413*00783d5eSAndrew Jeffery 					page, uval);
414*00783d5eSAndrew Jeffery 			return -EINVAL;
415*00783d5eSAndrew Jeffery 		}
416*00783d5eSAndrew Jeffery 
417*00783d5eSAndrew Jeffery 		mfr_cfg |= val << 13;
418*00783d5eSAndrew Jeffery 	}
419*00783d5eSAndrew Jeffery 
420*00783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-fault-pin-mon"))
421*00783d5eSAndrew Jeffery 		mfr_fault_resp |= MFR_FAULT_RESPONSE_MONITOR;
422*00783d5eSAndrew Jeffery 
423*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_byte_data(client, PMBUS_FAN_CONFIG_12,
424*00783d5eSAndrew Jeffery 					pb_cfg & ~PB_FAN_1_INSTALLED);
425*00783d5eSAndrew Jeffery 	if (ret < 0)
426*00783d5eSAndrew Jeffery 		return ret;
427*00783d5eSAndrew Jeffery 
428*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_word_data(client, MFR_FAN_CONFIG, mfr_cfg);
429*00783d5eSAndrew Jeffery 	if (ret < 0)
430*00783d5eSAndrew Jeffery 		return ret;
431*00783d5eSAndrew Jeffery 
432*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_byte_data(client, MFR_FAULT_RESPONSE,
433*00783d5eSAndrew Jeffery 					mfr_fault_resp);
434*00783d5eSAndrew Jeffery 	if (ret < 0)
435*00783d5eSAndrew Jeffery 		return ret;
436*00783d5eSAndrew Jeffery 
437*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_byte_data(client, PMBUS_FAN_CONFIG_12, pb_cfg);
438*00783d5eSAndrew Jeffery 	if (ret < 0)
439*00783d5eSAndrew Jeffery 		return ret;
440*00783d5eSAndrew Jeffery 
441*00783d5eSAndrew Jeffery 	/*
442*00783d5eSAndrew Jeffery 	 * Fans are on pages 0 - 5. If the page property of a fan node is
443*00783d5eSAndrew Jeffery 	 * greater than 5 we will have errored in checks above out above.
444*00783d5eSAndrew Jeffery 	 * Therefore we don't need to cope with values up to 31, and the int
445*00783d5eSAndrew Jeffery 	 * return type is enough.
446*00783d5eSAndrew Jeffery 	 *
447*00783d5eSAndrew Jeffery 	 * The bit mask return value is used to populate a bitfield of fans
448*00783d5eSAndrew Jeffery 	 * who are both configured in the devicetree _and_ reported as
449*00783d5eSAndrew Jeffery 	 * installed by the hardware. Any fans that are not configured in the
450*00783d5eSAndrew Jeffery 	 * devicetree but are reported as installed by the hardware will have
451*00783d5eSAndrew Jeffery 	 * their hardware configuration updated to unset the installed bit.
452*00783d5eSAndrew Jeffery 	 */
453*00783d5eSAndrew Jeffery 	return BIT(page);
454*00783d5eSAndrew Jeffery }
455*00783d5eSAndrew Jeffery 
456*00783d5eSAndrew Jeffery static int max31785_of_tmp_config(struct i2c_client *client,
457*00783d5eSAndrew Jeffery 				  struct pmbus_driver_info *info,
458*00783d5eSAndrew Jeffery 				  struct device_node *child)
459*00783d5eSAndrew Jeffery {
460*00783d5eSAndrew Jeffery 	struct device *dev = &client->dev;
461*00783d5eSAndrew Jeffery 	struct device_node *np;
462*00783d5eSAndrew Jeffery 	u16 mfr_tmp_cfg = 0;
463*00783d5eSAndrew Jeffery 	u32 page;
464*00783d5eSAndrew Jeffery 	u32 uval;
465*00783d5eSAndrew Jeffery 	int ret;
466*00783d5eSAndrew Jeffery 	int i;
467*00783d5eSAndrew Jeffery 
468*00783d5eSAndrew Jeffery 	if (!of_device_is_compatible(child, "pmbus-temperature"))
469*00783d5eSAndrew Jeffery 		return 0;
470*00783d5eSAndrew Jeffery 
471*00783d5eSAndrew Jeffery 	ret = of_property_read_u32(child, "reg", &page);
472*00783d5eSAndrew Jeffery 	if (ret < 0) {
473*00783d5eSAndrew Jeffery 		dev_err(&client->dev, "Missing valid reg property\n");
474*00783d5eSAndrew Jeffery 		return ret;
475*00783d5eSAndrew Jeffery 	}
476*00783d5eSAndrew Jeffery 
477*00783d5eSAndrew Jeffery 	if (!(info->func[page] & PMBUS_HAVE_TEMP)) {
478*00783d5eSAndrew Jeffery 		dev_err(dev, "Page %d does not have temp capabilities\n", page);
479*00783d5eSAndrew Jeffery 		return -ENXIO;
480*00783d5eSAndrew Jeffery 	}
481*00783d5eSAndrew Jeffery 
482*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
483*00783d5eSAndrew Jeffery 	if (ret < 0)
484*00783d5eSAndrew Jeffery 		return ret;
485*00783d5eSAndrew Jeffery 
486*00783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,tmp-offset", &uval)) {
487*00783d5eSAndrew Jeffery 		if (uval < 32)
488*00783d5eSAndrew Jeffery 			mfr_tmp_cfg |= uval << 10;
489*00783d5eSAndrew Jeffery 	}
490*00783d5eSAndrew Jeffery 
491*00783d5eSAndrew Jeffery 	i = 0;
492*00783d5eSAndrew Jeffery 	while ((np = of_parse_phandle(child, "maxim,tmp-fans", i))) {
493*00783d5eSAndrew Jeffery 		if (of_property_read_u32(np, "reg", &uval)) {
494*00783d5eSAndrew Jeffery 			dev_err(&client->dev, "Failed to read fan reg property for phandle index %d\n",
495*00783d5eSAndrew Jeffery 					i);
496*00783d5eSAndrew Jeffery 		} else {
497*00783d5eSAndrew Jeffery 			if (uval < 6)
498*00783d5eSAndrew Jeffery 				mfr_tmp_cfg |= BIT(uval);
499*00783d5eSAndrew Jeffery 			else
500*00783d5eSAndrew Jeffery 				dev_warn(&client->dev, "Invalid fan page: %d\n",
501*00783d5eSAndrew Jeffery 						uval);
502*00783d5eSAndrew Jeffery 		}
503*00783d5eSAndrew Jeffery 		i++;
504*00783d5eSAndrew Jeffery 	}
505*00783d5eSAndrew Jeffery 
506*00783d5eSAndrew Jeffery 	ret = i2c_smbus_write_word_data(client, MFR_TEMP_SENSOR_CONFIG,
507*00783d5eSAndrew Jeffery 					mfr_tmp_cfg);
508*00783d5eSAndrew Jeffery 	if (ret < 0)
509*00783d5eSAndrew Jeffery 		return ret;
510*00783d5eSAndrew Jeffery 
511*00783d5eSAndrew Jeffery 	return 0;
512*00783d5eSAndrew Jeffery }
513*00783d5eSAndrew Jeffery 
5144d420a6aSAndrew Jeffery #define MAX31785_FAN_FUNCS \
51556ad86b4SAndrew Jeffery 	(PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_PWM12)
5164d420a6aSAndrew Jeffery 
5174d420a6aSAndrew Jeffery #define MAX31785_TEMP_FUNCS \
5184d420a6aSAndrew Jeffery 	(PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
5194d420a6aSAndrew Jeffery 
5204d420a6aSAndrew Jeffery #define MAX31785_VOUT_FUNCS \
5214d420a6aSAndrew Jeffery 	(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
5224d420a6aSAndrew Jeffery 
5234d420a6aSAndrew Jeffery static const struct pmbus_driver_info max31785_info = {
5244d420a6aSAndrew Jeffery 	.pages = MAX31785_NR_PAGES,
5254d420a6aSAndrew Jeffery 
52656ad86b4SAndrew Jeffery 	.write_word_data = max31785_write_word_data,
527cf583b42SAndrew Jeffery 	.read_byte_data = max31785_read_byte_data,
52856ad86b4SAndrew Jeffery 	.read_word_data = max31785_read_word_data,
529cf583b42SAndrew Jeffery 	.write_byte = max31785_write_byte,
53056ad86b4SAndrew Jeffery 
5314d420a6aSAndrew Jeffery 	/* RPM */
5324d420a6aSAndrew Jeffery 	.format[PSC_FAN] = direct,
5334d420a6aSAndrew Jeffery 	.m[PSC_FAN] = 1,
5344d420a6aSAndrew Jeffery 	.b[PSC_FAN] = 0,
5354d420a6aSAndrew Jeffery 	.R[PSC_FAN] = 0,
53656ad86b4SAndrew Jeffery 	/* PWM */
53756ad86b4SAndrew Jeffery 	.format[PSC_PWM] = direct,
53856ad86b4SAndrew Jeffery 	.m[PSC_PWM] = 1,
53956ad86b4SAndrew Jeffery 	.b[PSC_PWM] = 0,
54056ad86b4SAndrew Jeffery 	.R[PSC_PWM] = 2,
5414d420a6aSAndrew Jeffery 	.func[0] = MAX31785_FAN_FUNCS,
5424d420a6aSAndrew Jeffery 	.func[1] = MAX31785_FAN_FUNCS,
5434d420a6aSAndrew Jeffery 	.func[2] = MAX31785_FAN_FUNCS,
5444d420a6aSAndrew Jeffery 	.func[3] = MAX31785_FAN_FUNCS,
5454d420a6aSAndrew Jeffery 	.func[4] = MAX31785_FAN_FUNCS,
5464d420a6aSAndrew Jeffery 	.func[5] = MAX31785_FAN_FUNCS,
5474d420a6aSAndrew Jeffery 
5484d420a6aSAndrew Jeffery 	.format[PSC_TEMPERATURE] = direct,
5494d420a6aSAndrew Jeffery 	.m[PSC_TEMPERATURE] = 1,
5504d420a6aSAndrew Jeffery 	.b[PSC_TEMPERATURE] = 0,
5514d420a6aSAndrew Jeffery 	.R[PSC_TEMPERATURE] = 2,
5524d420a6aSAndrew Jeffery 	.func[6]  = MAX31785_TEMP_FUNCS,
5534d420a6aSAndrew Jeffery 	.func[7]  = MAX31785_TEMP_FUNCS,
5544d420a6aSAndrew Jeffery 	.func[8]  = MAX31785_TEMP_FUNCS,
5554d420a6aSAndrew Jeffery 	.func[9]  = MAX31785_TEMP_FUNCS,
5564d420a6aSAndrew Jeffery 	.func[10] = MAX31785_TEMP_FUNCS,
5574d420a6aSAndrew Jeffery 	.func[11] = MAX31785_TEMP_FUNCS,
5584d420a6aSAndrew Jeffery 	.func[12] = MAX31785_TEMP_FUNCS,
5594d420a6aSAndrew Jeffery 	.func[13] = MAX31785_TEMP_FUNCS,
5604d420a6aSAndrew Jeffery 	.func[14] = MAX31785_TEMP_FUNCS,
5614d420a6aSAndrew Jeffery 	.func[15] = MAX31785_TEMP_FUNCS,
5624d420a6aSAndrew Jeffery 	.func[16] = MAX31785_TEMP_FUNCS,
5634d420a6aSAndrew Jeffery 
5644d420a6aSAndrew Jeffery 	.format[PSC_VOLTAGE_OUT] = direct,
5654d420a6aSAndrew Jeffery 	.m[PSC_VOLTAGE_OUT] = 1,
5664d420a6aSAndrew Jeffery 	.b[PSC_VOLTAGE_OUT] = 0,
5674d420a6aSAndrew Jeffery 	.R[PSC_VOLTAGE_OUT] = 0,
5684d420a6aSAndrew Jeffery 	.func[17] = MAX31785_VOUT_FUNCS,
5694d420a6aSAndrew Jeffery 	.func[18] = MAX31785_VOUT_FUNCS,
5704d420a6aSAndrew Jeffery 	.func[19] = MAX31785_VOUT_FUNCS,
5714d420a6aSAndrew Jeffery 	.func[20] = MAX31785_VOUT_FUNCS,
5724d420a6aSAndrew Jeffery 	.func[21] = MAX31785_VOUT_FUNCS,
5734d420a6aSAndrew Jeffery 	.func[22] = MAX31785_VOUT_FUNCS,
5744d420a6aSAndrew Jeffery };
5754d420a6aSAndrew Jeffery 
576cf583b42SAndrew Jeffery static int max31785_configure_dual_tach(struct i2c_client *client,
577cf583b42SAndrew Jeffery 					struct pmbus_driver_info *info)
578cf583b42SAndrew Jeffery {
579cf583b42SAndrew Jeffery 	int ret;
580cf583b42SAndrew Jeffery 	int i;
581cf583b42SAndrew Jeffery 
582cf583b42SAndrew Jeffery 	for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) {
583cf583b42SAndrew Jeffery 		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
584cf583b42SAndrew Jeffery 		if (ret < 0)
585cf583b42SAndrew Jeffery 			return ret;
586cf583b42SAndrew Jeffery 
587cf583b42SAndrew Jeffery 		ret = i2c_smbus_read_word_data(client, MFR_FAN_CONFIG);
588cf583b42SAndrew Jeffery 		if (ret < 0)
589cf583b42SAndrew Jeffery 			return ret;
590cf583b42SAndrew Jeffery 
591cf583b42SAndrew Jeffery 		if (ret & MFR_FAN_CONFIG_DUAL_TACH) {
592cf583b42SAndrew Jeffery 			int virtual = MAX31785_NR_PAGES + i;
593cf583b42SAndrew Jeffery 
594cf583b42SAndrew Jeffery 			info->pages = virtual + 1;
595cf583b42SAndrew Jeffery 			info->func[virtual] |= PMBUS_HAVE_FAN12;
596cf583b42SAndrew Jeffery 			info->func[virtual] |= PMBUS_PAGE_VIRTUAL;
597cf583b42SAndrew Jeffery 		}
598cf583b42SAndrew Jeffery 	}
599cf583b42SAndrew Jeffery 
600cf583b42SAndrew Jeffery 	return 0;
601cf583b42SAndrew Jeffery }
602cf583b42SAndrew Jeffery 
603dd431939SStephen Kitt static int max31785_probe(struct i2c_client *client)
6044d420a6aSAndrew Jeffery {
6054d420a6aSAndrew Jeffery 	struct device *dev = &client->dev;
606*00783d5eSAndrew Jeffery 	struct device_node *child;
6074d420a6aSAndrew Jeffery 	struct pmbus_driver_info *info;
608cf583b42SAndrew Jeffery 	bool dual_tach = false;
609996dc09cSMatthew Barth 	int ret;
610*00783d5eSAndrew Jeffery 	u32 fans;
611*00783d5eSAndrew Jeffery 	int i;
6124d420a6aSAndrew Jeffery 
613cf583b42SAndrew Jeffery 	if (!i2c_check_functionality(client->adapter,
614cf583b42SAndrew Jeffery 				     I2C_FUNC_SMBUS_BYTE_DATA |
615cf583b42SAndrew Jeffery 				     I2C_FUNC_SMBUS_WORD_DATA))
616cf583b42SAndrew Jeffery 		return -ENODEV;
617cf583b42SAndrew Jeffery 
6184d420a6aSAndrew Jeffery 	info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
6194d420a6aSAndrew Jeffery 	if (!info)
6204d420a6aSAndrew Jeffery 		return -ENOMEM;
6214d420a6aSAndrew Jeffery 
6224d420a6aSAndrew Jeffery 	*info = max31785_info;
6234d420a6aSAndrew Jeffery 
6244d420a6aSAndrew Jeffery 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
6254d420a6aSAndrew Jeffery 	if (ret < 0)
6264d420a6aSAndrew Jeffery 		return ret;
6274d420a6aSAndrew Jeffery 
628cf583b42SAndrew Jeffery 	ret = i2c_smbus_read_word_data(client, MFR_REVISION);
629cf583b42SAndrew Jeffery 	if (ret < 0)
630cf583b42SAndrew Jeffery 		return ret;
631cf583b42SAndrew Jeffery 
632996dc09cSMatthew Barth 	if (ret == MAX31785A || ret == MAX31785B) {
633cf583b42SAndrew Jeffery 		dual_tach = true;
634cf583b42SAndrew Jeffery 	} else if (ret == MAX31785) {
635996dc09cSMatthew Barth 		if (!strcmp("max31785a", client->name) ||
636996dc09cSMatthew Barth 		    !strcmp("max31785b", client->name))
637996dc09cSMatthew Barth 			dev_warn(dev, "Expected max31785a/b, found max31785: cannot provide secondary tachometer readings\n");
638cf583b42SAndrew Jeffery 	} else {
639996dc09cSMatthew Barth 		dev_err(dev, "Unrecognized MAX31785 revision: %x\n", ret);
640cf583b42SAndrew Jeffery 		return -ENODEV;
641cf583b42SAndrew Jeffery 	}
642cf583b42SAndrew Jeffery 
643*00783d5eSAndrew Jeffery 	fans = 0;
644*00783d5eSAndrew Jeffery 	for_each_child_of_node(dev->of_node, child) {
645*00783d5eSAndrew Jeffery 		ret = max31785_of_fan_config(client, info, child);
646*00783d5eSAndrew Jeffery 		if (ret < 0) {
647*00783d5eSAndrew Jeffery 			of_node_put(child);
648*00783d5eSAndrew Jeffery 			return ret;
649*00783d5eSAndrew Jeffery 		}
650*00783d5eSAndrew Jeffery 
651*00783d5eSAndrew Jeffery 		if (ret)
652*00783d5eSAndrew Jeffery 			fans |= ret;
653*00783d5eSAndrew Jeffery 
654*00783d5eSAndrew Jeffery 		ret = max31785_of_tmp_config(client, info, child);
655*00783d5eSAndrew Jeffery 		if (ret < 0) {
656*00783d5eSAndrew Jeffery 			of_node_put(child);
657*00783d5eSAndrew Jeffery 			return ret;
658*00783d5eSAndrew Jeffery 		}
659*00783d5eSAndrew Jeffery 	}
660*00783d5eSAndrew Jeffery 
661*00783d5eSAndrew Jeffery 	for (i = 0; i < MAX31785_NR_PAGES; i++) {
662*00783d5eSAndrew Jeffery 		bool have_fan = !!(info->func[i] & PMBUS_HAVE_FAN12);
663*00783d5eSAndrew Jeffery 		bool fan_configured = !!(fans & BIT(i));
664*00783d5eSAndrew Jeffery 
665*00783d5eSAndrew Jeffery 		if (!have_fan || fan_configured)
666*00783d5eSAndrew Jeffery 			continue;
667*00783d5eSAndrew Jeffery 
668*00783d5eSAndrew Jeffery 		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
669*00783d5eSAndrew Jeffery 		if (ret < 0)
670*00783d5eSAndrew Jeffery 			return ret;
671*00783d5eSAndrew Jeffery 
672*00783d5eSAndrew Jeffery 		ret = i2c_smbus_read_byte_data(client, PMBUS_FAN_CONFIG_12);
673*00783d5eSAndrew Jeffery 		if (ret < 0)
674*00783d5eSAndrew Jeffery 			return ret;
675*00783d5eSAndrew Jeffery 
676*00783d5eSAndrew Jeffery 		ret &= ~PB_FAN_1_INSTALLED;
677*00783d5eSAndrew Jeffery 		ret = i2c_smbus_write_word_data(client, PMBUS_FAN_CONFIG_12,
678*00783d5eSAndrew Jeffery 						ret);
679*00783d5eSAndrew Jeffery 		if (ret < 0)
680*00783d5eSAndrew Jeffery 			return ret;
681*00783d5eSAndrew Jeffery 	}
682*00783d5eSAndrew Jeffery 
683cf583b42SAndrew Jeffery 	if (dual_tach) {
684cf583b42SAndrew Jeffery 		ret = max31785_configure_dual_tach(client, info);
685cf583b42SAndrew Jeffery 		if (ret < 0)
686cf583b42SAndrew Jeffery 			return ret;
687cf583b42SAndrew Jeffery 	}
688cf583b42SAndrew Jeffery 
689dd431939SStephen Kitt 	return pmbus_do_probe(client, info);
6904d420a6aSAndrew Jeffery }
6914d420a6aSAndrew Jeffery 
6924d420a6aSAndrew Jeffery static const struct i2c_device_id max31785_id[] = {
6934d420a6aSAndrew Jeffery 	{ "max31785", 0 },
6944d420a6aSAndrew Jeffery 	{ "max31785a", 0 },
695996dc09cSMatthew Barth 	{ "max31785b", 0 },
6964d420a6aSAndrew Jeffery 	{ },
6974d420a6aSAndrew Jeffery };
6984d420a6aSAndrew Jeffery 
6994d420a6aSAndrew Jeffery MODULE_DEVICE_TABLE(i2c, max31785_id);
7004d420a6aSAndrew Jeffery 
70198b16a09SJavier Martinez Canillas static const struct of_device_id max31785_of_match[] = {
70298b16a09SJavier Martinez Canillas 	{ .compatible = "maxim,max31785" },
70398b16a09SJavier Martinez Canillas 	{ .compatible = "maxim,max31785a" },
704996dc09cSMatthew Barth 	{ .compatible = "maxim,max31785b" },
70598b16a09SJavier Martinez Canillas 	{ },
70698b16a09SJavier Martinez Canillas };
70798b16a09SJavier Martinez Canillas 
70898b16a09SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, max31785_of_match);
70998b16a09SJavier Martinez Canillas 
7104d420a6aSAndrew Jeffery static struct i2c_driver max31785_driver = {
7114d420a6aSAndrew Jeffery 	.driver = {
7124d420a6aSAndrew Jeffery 		.name = "max31785",
71398b16a09SJavier Martinez Canillas 		.of_match_table = max31785_of_match,
7144d420a6aSAndrew Jeffery 	},
7151975d167SUwe Kleine-König 	.probe = max31785_probe,
7164d420a6aSAndrew Jeffery 	.id_table = max31785_id,
7174d420a6aSAndrew Jeffery };
7184d420a6aSAndrew Jeffery 
7194d420a6aSAndrew Jeffery module_i2c_driver(max31785_driver);
7204d420a6aSAndrew Jeffery 
7214d420a6aSAndrew Jeffery MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
7224d420a6aSAndrew Jeffery MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
7234d420a6aSAndrew Jeffery MODULE_LICENSE("GPL");
724b94ca77eSGuenter Roeck MODULE_IMPORT_NS(PMBUS);
725