xref: /openbmc/linux/drivers/hwmon/pmbus/max31785.c (revision a529fa1b6a2f935510073988cf68588a24cce261)
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,
1500783d5eSAndrew Jeffery 	MFR_FAULT_RESPONSE	= 0xd9,
1600783d5eSAndrew Jeffery 	MFR_TEMP_SENSOR_CONFIG	= 0xf0,
17cf583b42SAndrew Jeffery 	MFR_FAN_CONFIG		= 0xf1,
1800783d5eSAndrew 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)
2600783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_TSFO		BIT(9)
2700783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_TACHO		BIT(8)
2800783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_HEALTH		BIT(4)
2900783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_ROTOR_HI_LO	BIT(3)
3000783d5eSAndrew Jeffery #define MFR_FAN_CONFIG_ROTOR		BIT(2)
3100783d5eSAndrew Jeffery 
3200783d5eSAndrew 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 
37*a529fa1bSAndrew Jeffery /*
38*a529fa1bSAndrew Jeffery  * MAX31785 dragons ahead
39*a529fa1bSAndrew Jeffery  *
40*a529fa1bSAndrew Jeffery  * We see weird issues where some transfers fail. There doesn't appear to be
41*a529fa1bSAndrew Jeffery  * any pattern to the problem, so below we wrap all the read/write calls with a
42*a529fa1bSAndrew Jeffery  * retry. The device provides no indication of this besides NACK'ing master
43*a529fa1bSAndrew Jeffery  * Txs; no bits are set in STATUS_BYTE to suggest anything has gone wrong.
44*a529fa1bSAndrew Jeffery  */
45*a529fa1bSAndrew Jeffery 
46*a529fa1bSAndrew Jeffery #define max31785_retry(_func, ...) ({					\
47*a529fa1bSAndrew Jeffery 	/* All relevant functions return int, sue me */			\
48*a529fa1bSAndrew Jeffery 	int _ret = _func(__VA_ARGS__);					\
49*a529fa1bSAndrew Jeffery 	if (_ret == -EIO)						\
50*a529fa1bSAndrew Jeffery 		_ret = _func(__VA_ARGS__);				\
51*a529fa1bSAndrew Jeffery 	_ret;								\
52*a529fa1bSAndrew Jeffery })
53*a529fa1bSAndrew Jeffery 
max31785_i2c_smbus_read_byte_data(struct i2c_client * client,int command)54*a529fa1bSAndrew Jeffery static int max31785_i2c_smbus_read_byte_data(struct i2c_client *client,
55*a529fa1bSAndrew Jeffery 					      int command)
56*a529fa1bSAndrew Jeffery {
57*a529fa1bSAndrew Jeffery 	return max31785_retry(i2c_smbus_read_byte_data, client, command);
58*a529fa1bSAndrew Jeffery }
59*a529fa1bSAndrew Jeffery 
60*a529fa1bSAndrew Jeffery 
max31785_i2c_smbus_write_byte_data(struct i2c_client * client,int command,u16 data)61*a529fa1bSAndrew Jeffery static int max31785_i2c_smbus_write_byte_data(struct i2c_client *client,
62*a529fa1bSAndrew Jeffery 					      int command, u16 data)
63*a529fa1bSAndrew Jeffery {
64*a529fa1bSAndrew Jeffery 	return max31785_retry(i2c_smbus_write_byte_data, client, command, data);
65*a529fa1bSAndrew Jeffery }
66*a529fa1bSAndrew Jeffery 
max31785_i2c_smbus_read_word_data(struct i2c_client * client,int command)67*a529fa1bSAndrew Jeffery static int max31785_i2c_smbus_read_word_data(struct i2c_client *client,
68*a529fa1bSAndrew Jeffery 					     int command)
69*a529fa1bSAndrew Jeffery {
70*a529fa1bSAndrew Jeffery 	return max31785_retry(i2c_smbus_read_word_data, client, command);
71*a529fa1bSAndrew Jeffery }
72*a529fa1bSAndrew Jeffery 
max31785_i2c_smbus_write_word_data(struct i2c_client * client,int command,u16 data)73*a529fa1bSAndrew Jeffery static int max31785_i2c_smbus_write_word_data(struct i2c_client *client,
74*a529fa1bSAndrew Jeffery 					      int command, u16 data)
75*a529fa1bSAndrew Jeffery {
76*a529fa1bSAndrew Jeffery 	return max31785_retry(i2c_smbus_write_word_data, client, command, data);
77*a529fa1bSAndrew Jeffery }
78*a529fa1bSAndrew Jeffery 
max31785_pmbus_write_byte(struct i2c_client * client,int page,u8 value)79*a529fa1bSAndrew Jeffery static int max31785_pmbus_write_byte(struct i2c_client *client, int page,
80*a529fa1bSAndrew Jeffery 				     u8 value)
81*a529fa1bSAndrew Jeffery {
82*a529fa1bSAndrew Jeffery 	return max31785_retry(pmbus_write_byte, client, page, value);
83*a529fa1bSAndrew Jeffery }
84*a529fa1bSAndrew Jeffery 
max31785_pmbus_read_byte_data(struct i2c_client * client,int page,int command)85*a529fa1bSAndrew Jeffery static int max31785_pmbus_read_byte_data(struct i2c_client *client, int page,
86*a529fa1bSAndrew Jeffery 					  int command)
87*a529fa1bSAndrew Jeffery {
88*a529fa1bSAndrew Jeffery 	return max31785_retry(pmbus_read_byte_data, client, page, command);
89*a529fa1bSAndrew Jeffery }
90*a529fa1bSAndrew Jeffery 
max31785_pmbus_write_byte_data(struct i2c_client * client,int page,int command,u16 data)91*a529fa1bSAndrew Jeffery static int max31785_pmbus_write_byte_data(struct i2c_client *client, int page,
92*a529fa1bSAndrew Jeffery 					  int command, u16 data)
93*a529fa1bSAndrew Jeffery {
94*a529fa1bSAndrew Jeffery 	return max31785_retry(pmbus_write_byte_data, client, page, command,
95*a529fa1bSAndrew Jeffery 			      data);
96*a529fa1bSAndrew Jeffery }
97*a529fa1bSAndrew Jeffery 
max31785_pmbus_read_word_data(struct i2c_client * client,int page,int phase,int command)98*a529fa1bSAndrew Jeffery static int max31785_pmbus_read_word_data(struct i2c_client *client, int page,
99*a529fa1bSAndrew Jeffery 					 int phase, int command)
100*a529fa1bSAndrew Jeffery {
101*a529fa1bSAndrew Jeffery 	return max31785_retry(pmbus_read_word_data, client, page, phase, command);
102*a529fa1bSAndrew Jeffery }
103*a529fa1bSAndrew Jeffery 
max31785_pmbus_write_word_data(struct i2c_client * client,int page,int command,u16 data)104*a529fa1bSAndrew Jeffery static int max31785_pmbus_write_word_data(struct i2c_client *client, int page,
105*a529fa1bSAndrew Jeffery 					  int command, u16 data)
106*a529fa1bSAndrew Jeffery {
107*a529fa1bSAndrew Jeffery 	return max31785_retry(pmbus_write_word_data, client, page, command,
108*a529fa1bSAndrew Jeffery 			      data);
109*a529fa1bSAndrew Jeffery }
110*a529fa1bSAndrew Jeffery 
max31785_read_byte_data(struct i2c_client * client,int page,int reg)111cf583b42SAndrew Jeffery static int max31785_read_byte_data(struct i2c_client *client, int page,
112cf583b42SAndrew Jeffery 				   int reg)
113cf583b42SAndrew Jeffery {
114cf583b42SAndrew Jeffery 	switch (reg) {
115cf583b42SAndrew Jeffery 	case PMBUS_VOUT_MODE:
116*a529fa1bSAndrew Jeffery 		if (page >= MAX31785_NR_PAGES)
117cf583b42SAndrew Jeffery 			return -ENOTSUPP;
118*a529fa1bSAndrew Jeffery 		break;
119cf583b42SAndrew Jeffery 	case PMBUS_FAN_CONFIG_12:
120*a529fa1bSAndrew Jeffery 		if (page >= MAX31785_NR_PAGES)
121*a529fa1bSAndrew Jeffery 			return max31785_pmbus_read_byte_data(client,
122*a529fa1bSAndrew Jeffery 					page - MAX31785_NR_PAGES,
123cf583b42SAndrew Jeffery 					reg);
124*a529fa1bSAndrew Jeffery 		break;
125cf583b42SAndrew Jeffery 	}
126cf583b42SAndrew Jeffery 
127*a529fa1bSAndrew Jeffery 	return max31785_pmbus_read_byte_data(client, page, reg);
128cf583b42SAndrew Jeffery }
129cf583b42SAndrew Jeffery 
max31785_write_byte(struct i2c_client * client,int page,u8 value)130cf583b42SAndrew Jeffery static int max31785_write_byte(struct i2c_client *client, int page, u8 value)
131cf583b42SAndrew Jeffery {
132*a529fa1bSAndrew Jeffery 	if (page >= MAX31785_NR_PAGES)
133cf583b42SAndrew Jeffery 		return -ENOTSUPP;
134*a529fa1bSAndrew Jeffery 
135*a529fa1bSAndrew Jeffery 	return max31785_pmbus_write_byte(client, page, value);
136cf583b42SAndrew Jeffery }
137cf583b42SAndrew Jeffery 
max31785_read_long_data(struct i2c_client * client,int page,int reg,u32 * data)138cf583b42SAndrew Jeffery static int max31785_read_long_data(struct i2c_client *client, int page,
139cf583b42SAndrew Jeffery 				   int reg, u32 *data)
140cf583b42SAndrew Jeffery {
141cf583b42SAndrew Jeffery 	unsigned char cmdbuf[1];
142cf583b42SAndrew Jeffery 	unsigned char rspbuf[4];
143cf583b42SAndrew Jeffery 	int rc;
144cf583b42SAndrew Jeffery 
145cf583b42SAndrew Jeffery 	struct i2c_msg msg[2] = {
146cf583b42SAndrew Jeffery 		{
147cf583b42SAndrew Jeffery 			.addr = client->addr,
148cf583b42SAndrew Jeffery 			.flags = 0,
149cf583b42SAndrew Jeffery 			.len = sizeof(cmdbuf),
150cf583b42SAndrew Jeffery 			.buf = cmdbuf,
151cf583b42SAndrew Jeffery 		},
152cf583b42SAndrew Jeffery 		{
153cf583b42SAndrew Jeffery 			.addr = client->addr,
154cf583b42SAndrew Jeffery 			.flags = I2C_M_RD,
155cf583b42SAndrew Jeffery 			.len = sizeof(rspbuf),
156cf583b42SAndrew Jeffery 			.buf = rspbuf,
157cf583b42SAndrew Jeffery 		},
158cf583b42SAndrew Jeffery 	};
159cf583b42SAndrew Jeffery 
160cf583b42SAndrew Jeffery 	cmdbuf[0] = reg;
161cf583b42SAndrew Jeffery 
16243f33b6eSGuenter Roeck 	rc = pmbus_set_page(client, page, 0xff);
163cf583b42SAndrew Jeffery 	if (rc < 0)
164cf583b42SAndrew Jeffery 		return rc;
165cf583b42SAndrew Jeffery 
166cf583b42SAndrew Jeffery 	rc = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
167cf583b42SAndrew Jeffery 	if (rc < 0)
168cf583b42SAndrew Jeffery 		return rc;
169cf583b42SAndrew Jeffery 
170cf583b42SAndrew Jeffery 	*data = (rspbuf[0] << (0 * 8)) | (rspbuf[1] << (1 * 8)) |
171cf583b42SAndrew Jeffery 		(rspbuf[2] << (2 * 8)) | (rspbuf[3] << (3 * 8));
172cf583b42SAndrew Jeffery 
173cf583b42SAndrew Jeffery 	return rc;
174cf583b42SAndrew Jeffery }
1754d420a6aSAndrew Jeffery 
max31785_get_pwm(struct i2c_client * client,int page)17656ad86b4SAndrew Jeffery static int max31785_get_pwm(struct i2c_client *client, int page)
17756ad86b4SAndrew Jeffery {
17856ad86b4SAndrew Jeffery 	int rv;
17956ad86b4SAndrew Jeffery 
18056ad86b4SAndrew Jeffery 	rv = pmbus_get_fan_rate_device(client, page, 0, percent);
18156ad86b4SAndrew Jeffery 	if (rv < 0)
18256ad86b4SAndrew Jeffery 		return rv;
18356ad86b4SAndrew Jeffery 	else if (rv >= 0x8000)
18456ad86b4SAndrew Jeffery 		return 0;
18556ad86b4SAndrew Jeffery 	else if (rv >= 0x2711)
18656ad86b4SAndrew Jeffery 		return 0x2710;
18756ad86b4SAndrew Jeffery 
18856ad86b4SAndrew Jeffery 	return rv;
18956ad86b4SAndrew Jeffery }
19056ad86b4SAndrew Jeffery 
max31785_get_pwm_mode(struct i2c_client * client,int page)19156ad86b4SAndrew Jeffery static int max31785_get_pwm_mode(struct i2c_client *client, int page)
19256ad86b4SAndrew Jeffery {
19356ad86b4SAndrew Jeffery 	int config;
19456ad86b4SAndrew Jeffery 	int command;
19556ad86b4SAndrew Jeffery 
196*a529fa1bSAndrew Jeffery 	config = max31785_pmbus_read_byte_data(client, page,
197*a529fa1bSAndrew Jeffery 					       PMBUS_FAN_CONFIG_12);
19856ad86b4SAndrew Jeffery 	if (config < 0)
19956ad86b4SAndrew Jeffery 		return config;
20056ad86b4SAndrew Jeffery 
201*a529fa1bSAndrew Jeffery 	command = max31785_pmbus_read_word_data(client, page, 0xff,
202*a529fa1bSAndrew Jeffery 						PMBUS_FAN_COMMAND_1);
20356ad86b4SAndrew Jeffery 	if (command < 0)
20456ad86b4SAndrew Jeffery 		return command;
20556ad86b4SAndrew Jeffery 
20656ad86b4SAndrew Jeffery 	if (config & PB_FAN_1_RPM)
20756ad86b4SAndrew Jeffery 		return (command >= 0x8000) ? 3 : 2;
20856ad86b4SAndrew Jeffery 
20956ad86b4SAndrew Jeffery 	if (command >= 0x8000)
21056ad86b4SAndrew Jeffery 		return 3;
21156ad86b4SAndrew Jeffery 	else if (command >= 0x2711)
21256ad86b4SAndrew Jeffery 		return 0;
21356ad86b4SAndrew Jeffery 
21456ad86b4SAndrew Jeffery 	return 1;
21556ad86b4SAndrew Jeffery }
21656ad86b4SAndrew Jeffery 
max31785_read_word_data(struct i2c_client * client,int page,int phase,int reg)21756ad86b4SAndrew Jeffery static int max31785_read_word_data(struct i2c_client *client, int page,
21843f33b6eSGuenter Roeck 				   int phase, int reg)
21956ad86b4SAndrew Jeffery {
220cf583b42SAndrew Jeffery 	u32 val;
22156ad86b4SAndrew Jeffery 	int rv;
22256ad86b4SAndrew Jeffery 
22356ad86b4SAndrew Jeffery 	switch (reg) {
224cf583b42SAndrew Jeffery 	case PMBUS_READ_FAN_SPEED_1:
225cf583b42SAndrew Jeffery 		if (page < MAX31785_NR_PAGES)
226*a529fa1bSAndrew Jeffery 			return max31785_pmbus_read_word_data(client, page, 0xff, reg);
227cf583b42SAndrew Jeffery 
228cf583b42SAndrew Jeffery 		rv = max31785_read_long_data(client, page - MAX31785_NR_PAGES,
229cf583b42SAndrew Jeffery 					     reg, &val);
230cf583b42SAndrew Jeffery 		if (rv < 0)
231cf583b42SAndrew Jeffery 			return rv;
232cf583b42SAndrew Jeffery 
233*a529fa1bSAndrew Jeffery 		return (val >> 16) & 0xffff;
234cf583b42SAndrew Jeffery 	case PMBUS_FAN_COMMAND_1:
235cf583b42SAndrew Jeffery 		/*
236cf583b42SAndrew Jeffery 		 * PMBUS_FAN_COMMAND_x is probed to judge whether or not to
237cf583b42SAndrew Jeffery 		 * expose fan control registers.
238cf583b42SAndrew Jeffery 		 *
239cf583b42SAndrew Jeffery 		 * Don't expose fan_target attribute for virtual pages.
240cf583b42SAndrew Jeffery 		 */
241*a529fa1bSAndrew Jeffery 		if (page >= MAX31785_NR_PAGES)
242*a529fa1bSAndrew Jeffery 			return -ENOTSUPP;
243cf583b42SAndrew Jeffery 		break;
244*a529fa1bSAndrew Jeffery 	case PMBUS_VIRT_FAN_TARGET_1:
245*a529fa1bSAndrew Jeffery 		if (page >= MAX31785_NR_PAGES)
246*a529fa1bSAndrew Jeffery 			return -ENOTSUPP;
247*a529fa1bSAndrew Jeffery 
248*a529fa1bSAndrew Jeffery 		return -ENODATA;
24956ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_1:
250*a529fa1bSAndrew Jeffery 		return max31785_get_pwm(client, page);
25156ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_ENABLE_1:
252*a529fa1bSAndrew Jeffery 		return max31785_get_pwm_mode(client, page);
25356ad86b4SAndrew Jeffery 	default:
254*a529fa1bSAndrew Jeffery 		if (page >= MAX31785_NR_PAGES)
255*a529fa1bSAndrew Jeffery 			return -ENXIO;
25656ad86b4SAndrew Jeffery 		break;
25756ad86b4SAndrew Jeffery 	}
25856ad86b4SAndrew Jeffery 
259*a529fa1bSAndrew Jeffery 	if (reg >= PMBUS_VIRT_BASE)
260*a529fa1bSAndrew Jeffery 		return -ENXIO;
261*a529fa1bSAndrew Jeffery 
262*a529fa1bSAndrew Jeffery 	return max31785_pmbus_read_word_data(client, page, 0xff, reg);
26356ad86b4SAndrew Jeffery }
26456ad86b4SAndrew Jeffery 
max31785_scale_pwm(u32 sensor_val)26556ad86b4SAndrew Jeffery static inline u32 max31785_scale_pwm(u32 sensor_val)
26656ad86b4SAndrew Jeffery {
26756ad86b4SAndrew Jeffery 	/*
26856ad86b4SAndrew Jeffery 	 * The datasheet describes the accepted value range for manual PWM as
26956ad86b4SAndrew Jeffery 	 * [0, 0x2710], while the hwmon pwmX sysfs interface accepts values in
27056ad86b4SAndrew Jeffery 	 * [0, 255]. The MAX31785 uses DIRECT mode to scale the FAN_COMMAND
27156ad86b4SAndrew Jeffery 	 * registers and in PWM mode the coefficients are m=1, b=0, R=2. The
27256ad86b4SAndrew Jeffery 	 * important observation here is that 0x2710 == 10000 == 100 * 100.
27356ad86b4SAndrew Jeffery 	 *
27456ad86b4SAndrew Jeffery 	 * R=2 (== 10^2 == 100) accounts for scaling the value provided at the
27556ad86b4SAndrew Jeffery 	 * sysfs interface into the required hardware resolution, but it does
27656ad86b4SAndrew Jeffery 	 * not yet yield a value that we can write to the device (this initial
27756ad86b4SAndrew Jeffery 	 * scaling is handled by pmbus_data2reg()). Multiplying by 100 below
27856ad86b4SAndrew Jeffery 	 * translates the parameter value into the percentage units required by
27956ad86b4SAndrew Jeffery 	 * PMBus, and then we scale back by 255 as required by the hwmon pwmX
28056ad86b4SAndrew Jeffery 	 * interface to yield the percentage value at the appropriate
28156ad86b4SAndrew Jeffery 	 * resolution for hardware.
28256ad86b4SAndrew Jeffery 	 */
28356ad86b4SAndrew Jeffery 	return (sensor_val * 100) / 255;
28456ad86b4SAndrew Jeffery }
28556ad86b4SAndrew Jeffery 
max31785_update_fan(struct i2c_client * client,int page,u8 config,u8 mask,u16 command)286*a529fa1bSAndrew Jeffery static int max31785_update_fan(struct i2c_client *client, int page,
287*a529fa1bSAndrew Jeffery 			       u8 config, u8 mask, u16 command)
288*a529fa1bSAndrew Jeffery {
289*a529fa1bSAndrew Jeffery 	int from, rv;
290*a529fa1bSAndrew Jeffery 	u8 to;
291*a529fa1bSAndrew Jeffery 
292*a529fa1bSAndrew Jeffery 	from = max31785_pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
293*a529fa1bSAndrew Jeffery 	if (from < 0)
294*a529fa1bSAndrew Jeffery 		return from;
295*a529fa1bSAndrew Jeffery 
296*a529fa1bSAndrew Jeffery 	to = (from & ~mask) | (config & mask);
297*a529fa1bSAndrew Jeffery 
298*a529fa1bSAndrew Jeffery 	if (to != from) {
299*a529fa1bSAndrew Jeffery 		rv = max31785_pmbus_write_byte_data(client, page,
300*a529fa1bSAndrew Jeffery 						    PMBUS_FAN_CONFIG_12, to);
301*a529fa1bSAndrew Jeffery 		if (rv < 0)
302*a529fa1bSAndrew Jeffery 			return rv;
303*a529fa1bSAndrew Jeffery 	}
304*a529fa1bSAndrew Jeffery 
305*a529fa1bSAndrew Jeffery 	rv = max31785_pmbus_write_word_data(client, page, PMBUS_FAN_COMMAND_1,
306*a529fa1bSAndrew Jeffery 					    command);
307*a529fa1bSAndrew Jeffery 
308*a529fa1bSAndrew Jeffery 	return rv;
309*a529fa1bSAndrew Jeffery }
310*a529fa1bSAndrew Jeffery 
max31785_pwm_enable(struct i2c_client * client,int page,u16 word)31156ad86b4SAndrew Jeffery static int max31785_pwm_enable(struct i2c_client *client, int page,
31256ad86b4SAndrew Jeffery 				    u16 word)
31356ad86b4SAndrew Jeffery {
31456ad86b4SAndrew Jeffery 	int config = 0;
31556ad86b4SAndrew Jeffery 	int rate;
31656ad86b4SAndrew Jeffery 
31756ad86b4SAndrew Jeffery 	switch (word) {
31856ad86b4SAndrew Jeffery 	case 0:
31956ad86b4SAndrew Jeffery 		rate = 0x7fff;
32056ad86b4SAndrew Jeffery 		break;
32156ad86b4SAndrew Jeffery 	case 1:
32256ad86b4SAndrew Jeffery 		rate = pmbus_get_fan_rate_cached(client, page, 0, percent);
32356ad86b4SAndrew Jeffery 		if (rate < 0)
32456ad86b4SAndrew Jeffery 			return rate;
32556ad86b4SAndrew Jeffery 		rate = max31785_scale_pwm(rate);
32656ad86b4SAndrew Jeffery 		break;
32756ad86b4SAndrew Jeffery 	case 2:
32856ad86b4SAndrew Jeffery 		config = PB_FAN_1_RPM;
32956ad86b4SAndrew Jeffery 		rate = pmbus_get_fan_rate_cached(client, page, 0, rpm);
33056ad86b4SAndrew Jeffery 		if (rate < 0)
33156ad86b4SAndrew Jeffery 			return rate;
33256ad86b4SAndrew Jeffery 		break;
33356ad86b4SAndrew Jeffery 	case 3:
33456ad86b4SAndrew Jeffery 		rate = 0xffff;
33556ad86b4SAndrew Jeffery 		break;
33656ad86b4SAndrew Jeffery 	default:
33756ad86b4SAndrew Jeffery 		return -EINVAL;
33856ad86b4SAndrew Jeffery 	}
33956ad86b4SAndrew Jeffery 
340*a529fa1bSAndrew Jeffery 	return max31785_update_fan(client, page, config, PB_FAN_1_RPM, rate);
34156ad86b4SAndrew Jeffery }
34256ad86b4SAndrew Jeffery 
max31785_write_word_data(struct i2c_client * client,int page,int reg,u16 word)34356ad86b4SAndrew Jeffery static int max31785_write_word_data(struct i2c_client *client, int page,
34456ad86b4SAndrew Jeffery 				    int reg, u16 word)
34556ad86b4SAndrew Jeffery {
34656ad86b4SAndrew Jeffery 	switch (reg) {
347*a529fa1bSAndrew Jeffery 	case PMBUS_VIRT_FAN_TARGET_1:
348*a529fa1bSAndrew Jeffery 		return max31785_update_fan(client, page, PB_FAN_1_RPM,
349*a529fa1bSAndrew Jeffery 					   PB_FAN_1_RPM, word);
35056ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_1:
351*a529fa1bSAndrew Jeffery 		return max31785_update_fan(client, page, 0, PB_FAN_1_RPM,
35256ad86b4SAndrew Jeffery 					max31785_scale_pwm(word));
35356ad86b4SAndrew Jeffery 	case PMBUS_VIRT_PWM_ENABLE_1:
35456ad86b4SAndrew Jeffery 		return max31785_pwm_enable(client, page, word);
35556ad86b4SAndrew Jeffery 	default:
35656ad86b4SAndrew Jeffery 		break;
35756ad86b4SAndrew Jeffery 	}
35856ad86b4SAndrew Jeffery 
359*a529fa1bSAndrew Jeffery 	if (reg < PMBUS_VIRT_BASE)
360*a529fa1bSAndrew Jeffery 		return max31785_pmbus_write_word_data(client, page, reg, word);
361*a529fa1bSAndrew Jeffery 
362*a529fa1bSAndrew Jeffery 	return -ENXIO;
36356ad86b4SAndrew Jeffery }
36456ad86b4SAndrew Jeffery 
36500783d5eSAndrew Jeffery /*
36600783d5eSAndrew Jeffery  * Returns negative error codes if an unrecoverable problem is detected, 0 if a
36700783d5eSAndrew Jeffery  * recoverable problem is detected, or a positive value on success.
36800783d5eSAndrew Jeffery  */
max31785_of_fan_config(struct i2c_client * client,struct pmbus_driver_info * info,struct device_node * child)36900783d5eSAndrew Jeffery static int max31785_of_fan_config(struct i2c_client *client,
37000783d5eSAndrew Jeffery 				  struct pmbus_driver_info *info,
37100783d5eSAndrew Jeffery 				  struct device_node *child)
37200783d5eSAndrew Jeffery {
37300783d5eSAndrew Jeffery 	int mfr_cfg = 0, mfr_fault_resp = 0, pb_cfg;
37400783d5eSAndrew Jeffery 	struct device *dev = &client->dev;
37500783d5eSAndrew Jeffery 	char *lock_polarity = NULL;
37600783d5eSAndrew Jeffery 	const char *sval;
37700783d5eSAndrew Jeffery 	u32 page;
37800783d5eSAndrew Jeffery 	u32 uval;
37900783d5eSAndrew Jeffery 	int ret;
38000783d5eSAndrew Jeffery 
38100783d5eSAndrew Jeffery 	if (!of_device_is_compatible(child, "pmbus-fan"))
38200783d5eSAndrew Jeffery 		return 0;
38300783d5eSAndrew Jeffery 
38400783d5eSAndrew Jeffery 	ret = of_property_read_u32(child, "reg", &page);
38500783d5eSAndrew Jeffery 	if (ret < 0) {
38600783d5eSAndrew Jeffery 		dev_err(&client->dev, "Missing valid reg property\n");
38700783d5eSAndrew Jeffery 		return ret;
38800783d5eSAndrew Jeffery 	}
38900783d5eSAndrew Jeffery 
39000783d5eSAndrew Jeffery 	if (!(info->func[page] & PMBUS_HAVE_FAN12)) {
39100783d5eSAndrew Jeffery 		dev_err(dev, "Page %d does not have fan capabilities\n", page);
39200783d5eSAndrew Jeffery 		return -ENXIO;
39300783d5eSAndrew Jeffery 	}
39400783d5eSAndrew Jeffery 
395*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
39600783d5eSAndrew Jeffery 	if (ret < 0)
39700783d5eSAndrew Jeffery 		return ret;
39800783d5eSAndrew Jeffery 
399*a529fa1bSAndrew Jeffery 	pb_cfg = max31785_i2c_smbus_read_byte_data(client, PMBUS_FAN_CONFIG_12);
40000783d5eSAndrew Jeffery 	if (pb_cfg < 0)
40100783d5eSAndrew Jeffery 		return pb_cfg;
40200783d5eSAndrew Jeffery 
40300783d5eSAndrew Jeffery 	if (of_property_read_bool(child->parent, "use-stored-presence")) {
40400783d5eSAndrew Jeffery 		if (!(pb_cfg & PB_FAN_1_INSTALLED))
40500783d5eSAndrew Jeffery 			dev_info(dev, "Fan %d is configured but not installed\n",
40600783d5eSAndrew Jeffery 				 page);
40700783d5eSAndrew Jeffery 	} else {
40800783d5eSAndrew Jeffery 		pb_cfg |= PB_FAN_1_INSTALLED;
40900783d5eSAndrew Jeffery 	}
41000783d5eSAndrew Jeffery 
41100783d5eSAndrew Jeffery 	ret = of_property_read_string(child, "maxim,fan-rotor-input", &sval);
41200783d5eSAndrew Jeffery 	if (ret < 0) {
41300783d5eSAndrew Jeffery 		dev_err(dev, "Missing valid maxim,fan-rotor-input property for fan %d\n",
41400783d5eSAndrew Jeffery 				page);
41500783d5eSAndrew Jeffery 		return ret;
41600783d5eSAndrew Jeffery 	}
41700783d5eSAndrew Jeffery 
41800783d5eSAndrew Jeffery 	if (strcmp("tach", sval) && strcmp("lock", sval)) {
41900783d5eSAndrew Jeffery 		dev_err(dev, "maxim,fan-rotor-input has invalid value for fan %d: %s\n",
42000783d5eSAndrew Jeffery 				page, sval);
42100783d5eSAndrew Jeffery 		return -EINVAL;
42200783d5eSAndrew Jeffery 	} else if (!strcmp("lock", sval)) {
42300783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_ROTOR;
42400783d5eSAndrew Jeffery 
425*a529fa1bSAndrew Jeffery 		ret = max31785_i2c_smbus_write_word_data(client,
426*a529fa1bSAndrew Jeffery 							 MFR_FAN_FAULT_LIMIT,
427*a529fa1bSAndrew Jeffery 							 1);
42800783d5eSAndrew Jeffery 		if (ret < 0)
42900783d5eSAndrew Jeffery 			return ret;
43000783d5eSAndrew Jeffery 
43100783d5eSAndrew Jeffery 		ret = of_property_read_string(child, "maxim,fan-lock-polarity",
43200783d5eSAndrew Jeffery 					      &sval);
43300783d5eSAndrew Jeffery 		if (ret < 0) {
43400783d5eSAndrew Jeffery 			dev_err(dev, "Missing valid maxim,fan-lock-polarity property for fan %d\n",
43500783d5eSAndrew Jeffery 					page);
43600783d5eSAndrew Jeffery 			return ret;
43700783d5eSAndrew Jeffery 		}
43800783d5eSAndrew Jeffery 
43900783d5eSAndrew Jeffery 		if (strcmp("low", sval) && strcmp("high", sval)) {
44000783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-lock-polarity has invalid value for fan %d: %s\n",
44100783d5eSAndrew Jeffery 					page, lock_polarity);
44200783d5eSAndrew Jeffery 			return -EINVAL;
44300783d5eSAndrew Jeffery 		} else if (!strcmp("high", sval))
44400783d5eSAndrew Jeffery 			mfr_cfg |= MFR_FAN_CONFIG_ROTOR_HI_LO;
44500783d5eSAndrew Jeffery 	}
44600783d5eSAndrew Jeffery 
44700783d5eSAndrew Jeffery 	if (!of_property_read_string(child, "fan-mode", &sval)) {
44800783d5eSAndrew Jeffery 		if (!strcmp("rpm", sval))
44900783d5eSAndrew Jeffery 			pb_cfg |= PB_FAN_1_RPM;
45000783d5eSAndrew Jeffery 		else if (!strcmp("pwm", sval))
45100783d5eSAndrew Jeffery 			pb_cfg &= ~PB_FAN_1_RPM;
45200783d5eSAndrew Jeffery 		else {
45300783d5eSAndrew Jeffery 			dev_err(dev, "fan-mode has invalid value for fan %d: %s\n",
45400783d5eSAndrew Jeffery 					page, sval);
45500783d5eSAndrew Jeffery 			return -EINVAL;
45600783d5eSAndrew Jeffery 		}
45700783d5eSAndrew Jeffery 	}
45800783d5eSAndrew Jeffery 
45900783d5eSAndrew Jeffery 	ret = of_property_read_u32(child, "tach-pulses", &uval);
46000783d5eSAndrew Jeffery 	if (ret < 0) {
46100783d5eSAndrew Jeffery 		pb_cfg &= ~PB_FAN_1_PULSE_MASK;
46200783d5eSAndrew Jeffery 	} else if (uval && (uval - 1) < 4) {
46300783d5eSAndrew Jeffery 		pb_cfg = ((pb_cfg & ~PB_FAN_1_PULSE_MASK) | ((uval - 1) << 4));
46400783d5eSAndrew Jeffery 	} else {
46500783d5eSAndrew Jeffery 		dev_err(dev, "tach-pulses has invalid value for fan %d: %u\n",
46600783d5eSAndrew Jeffery 				page, uval);
46700783d5eSAndrew Jeffery 		return -EINVAL;
46800783d5eSAndrew Jeffery 	}
46900783d5eSAndrew Jeffery 
47000783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-health"))
47100783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_HEALTH;
47200783d5eSAndrew Jeffery 
47300783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-no-watchdog") ||
47400783d5eSAndrew Jeffery 		of_property_read_bool(child, "maxim,tmp-no-fault-ramp"))
47500783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_TSFO;
47600783d5eSAndrew Jeffery 
47700783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-dual-tach"))
47800783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_DUAL_TACH;
47900783d5eSAndrew Jeffery 
48000783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-no-fault-ramp"))
48100783d5eSAndrew Jeffery 		mfr_cfg |= MFR_FAN_CONFIG_TACHO;
48200783d5eSAndrew Jeffery 
48300783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,fan-startup", &uval)) {
48400783d5eSAndrew Jeffery 		uval /= 2;
48500783d5eSAndrew Jeffery 		if (uval < 5) {
48600783d5eSAndrew Jeffery 			mfr_cfg |= uval;
48700783d5eSAndrew Jeffery 		} else {
48800783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-startup has invalid value for fan %d: %u\n",
48900783d5eSAndrew Jeffery 					page, uval);
49000783d5eSAndrew Jeffery 			return -EINVAL;
49100783d5eSAndrew Jeffery 		}
49200783d5eSAndrew Jeffery 	}
49300783d5eSAndrew Jeffery 
49400783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,fan-ramp", &uval)) {
49500783d5eSAndrew Jeffery 		if (uval < 8) {
49600783d5eSAndrew Jeffery 			mfr_cfg |= uval << 5;
49700783d5eSAndrew Jeffery 		} else {
49800783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-ramp has invalid value for fan %d: %u\n",
49900783d5eSAndrew Jeffery 					page, uval);
50000783d5eSAndrew Jeffery 			return -EINVAL;
50100783d5eSAndrew Jeffery 		}
50200783d5eSAndrew Jeffery 	}
50300783d5eSAndrew Jeffery 
50400783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,tmp-hysteresis", &uval)) {
50500783d5eSAndrew Jeffery 		uval /= 2;
50600783d5eSAndrew Jeffery 		uval -= 1;
50700783d5eSAndrew Jeffery 		if (uval < 4) {
50800783d5eSAndrew Jeffery 			mfr_cfg |= uval << 10;
50900783d5eSAndrew Jeffery 		} else {
51000783d5eSAndrew Jeffery 			dev_err(dev, "maxim,tmp-hysteresis has invalid value for fan %d, %u\n",
51100783d5eSAndrew Jeffery 					page, uval);
51200783d5eSAndrew Jeffery 			return -EINVAL;
51300783d5eSAndrew Jeffery 		}
51400783d5eSAndrew Jeffery 	}
51500783d5eSAndrew Jeffery 
51600783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,fan-pwm-freq", &uval)) {
51700783d5eSAndrew Jeffery 		u16 val;
51800783d5eSAndrew Jeffery 
51900783d5eSAndrew Jeffery 		if (uval == 30) {
52000783d5eSAndrew Jeffery 			val = 0;
52100783d5eSAndrew Jeffery 		} else if (uval == 50) {
52200783d5eSAndrew Jeffery 			val = 1;
52300783d5eSAndrew Jeffery 		} else if (uval == 100) {
52400783d5eSAndrew Jeffery 			val = 2;
52500783d5eSAndrew Jeffery 		} else if (uval == 150) {
52600783d5eSAndrew Jeffery 			val = 3;
52700783d5eSAndrew Jeffery 		} else if (uval == 25000) {
52800783d5eSAndrew Jeffery 			val = 7;
52900783d5eSAndrew Jeffery 		} else {
53000783d5eSAndrew Jeffery 			dev_err(dev, "maxim,fan-pwm-freq has invalid value for fan %d: %u\n",
53100783d5eSAndrew Jeffery 					page, uval);
53200783d5eSAndrew Jeffery 			return -EINVAL;
53300783d5eSAndrew Jeffery 		}
53400783d5eSAndrew Jeffery 
53500783d5eSAndrew Jeffery 		mfr_cfg |= val << 13;
53600783d5eSAndrew Jeffery 	}
53700783d5eSAndrew Jeffery 
53800783d5eSAndrew Jeffery 	if (of_property_read_bool(child, "maxim,fan-fault-pin-mon"))
53900783d5eSAndrew Jeffery 		mfr_fault_resp |= MFR_FAULT_RESPONSE_MONITOR;
54000783d5eSAndrew Jeffery 
541*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_FAN_CONFIG_12,
54200783d5eSAndrew Jeffery 					pb_cfg & ~PB_FAN_1_INSTALLED);
54300783d5eSAndrew Jeffery 	if (ret < 0)
54400783d5eSAndrew Jeffery 		return ret;
54500783d5eSAndrew Jeffery 
546*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_word_data(client, MFR_FAN_CONFIG,
547*a529fa1bSAndrew Jeffery 						 mfr_cfg);
54800783d5eSAndrew Jeffery 	if (ret < 0)
54900783d5eSAndrew Jeffery 		return ret;
55000783d5eSAndrew Jeffery 
551*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_byte_data(client, MFR_FAULT_RESPONSE,
55200783d5eSAndrew Jeffery 						 mfr_fault_resp);
55300783d5eSAndrew Jeffery 	if (ret < 0)
55400783d5eSAndrew Jeffery 		return ret;
55500783d5eSAndrew Jeffery 
556*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_FAN_CONFIG_12,
557*a529fa1bSAndrew Jeffery 						 pb_cfg);
55800783d5eSAndrew Jeffery 	if (ret < 0)
55900783d5eSAndrew Jeffery 		return ret;
56000783d5eSAndrew Jeffery 
56100783d5eSAndrew Jeffery 	/*
56200783d5eSAndrew Jeffery 	 * Fans are on pages 0 - 5. If the page property of a fan node is
56300783d5eSAndrew Jeffery 	 * greater than 5 we will have errored in checks above out above.
56400783d5eSAndrew Jeffery 	 * Therefore we don't need to cope with values up to 31, and the int
56500783d5eSAndrew Jeffery 	 * return type is enough.
56600783d5eSAndrew Jeffery 	 *
56700783d5eSAndrew Jeffery 	 * The bit mask return value is used to populate a bitfield of fans
56800783d5eSAndrew Jeffery 	 * who are both configured in the devicetree _and_ reported as
56900783d5eSAndrew Jeffery 	 * installed by the hardware. Any fans that are not configured in the
57000783d5eSAndrew Jeffery 	 * devicetree but are reported as installed by the hardware will have
57100783d5eSAndrew Jeffery 	 * their hardware configuration updated to unset the installed bit.
57200783d5eSAndrew Jeffery 	 */
57300783d5eSAndrew Jeffery 	return BIT(page);
57400783d5eSAndrew Jeffery }
57500783d5eSAndrew Jeffery 
max31785_of_tmp_config(struct i2c_client * client,struct pmbus_driver_info * info,struct device_node * child)57600783d5eSAndrew Jeffery static int max31785_of_tmp_config(struct i2c_client *client,
57700783d5eSAndrew Jeffery 				  struct pmbus_driver_info *info,
57800783d5eSAndrew Jeffery 				  struct device_node *child)
57900783d5eSAndrew Jeffery {
58000783d5eSAndrew Jeffery 	struct device *dev = &client->dev;
58100783d5eSAndrew Jeffery 	struct device_node *np;
58200783d5eSAndrew Jeffery 	u16 mfr_tmp_cfg = 0;
58300783d5eSAndrew Jeffery 	u32 page;
58400783d5eSAndrew Jeffery 	u32 uval;
58500783d5eSAndrew Jeffery 	int ret;
58600783d5eSAndrew Jeffery 	int i;
58700783d5eSAndrew Jeffery 
58800783d5eSAndrew Jeffery 	if (!of_device_is_compatible(child, "pmbus-temperature"))
58900783d5eSAndrew Jeffery 		return 0;
59000783d5eSAndrew Jeffery 
59100783d5eSAndrew Jeffery 	ret = of_property_read_u32(child, "reg", &page);
59200783d5eSAndrew Jeffery 	if (ret < 0) {
59300783d5eSAndrew Jeffery 		dev_err(&client->dev, "Missing valid reg property\n");
59400783d5eSAndrew Jeffery 		return ret;
59500783d5eSAndrew Jeffery 	}
59600783d5eSAndrew Jeffery 
59700783d5eSAndrew Jeffery 	if (!(info->func[page] & PMBUS_HAVE_TEMP)) {
59800783d5eSAndrew Jeffery 		dev_err(dev, "Page %d does not have temp capabilities\n", page);
59900783d5eSAndrew Jeffery 		return -ENXIO;
60000783d5eSAndrew Jeffery 	}
60100783d5eSAndrew Jeffery 
602*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
60300783d5eSAndrew Jeffery 	if (ret < 0)
60400783d5eSAndrew Jeffery 		return ret;
60500783d5eSAndrew Jeffery 
60600783d5eSAndrew Jeffery 	if (!of_property_read_u32(child, "maxim,tmp-offset", &uval)) {
60700783d5eSAndrew Jeffery 		if (uval < 32)
60800783d5eSAndrew Jeffery 			mfr_tmp_cfg |= uval << 10;
60900783d5eSAndrew Jeffery 	}
61000783d5eSAndrew Jeffery 
61100783d5eSAndrew Jeffery 	i = 0;
61200783d5eSAndrew Jeffery 	while ((np = of_parse_phandle(child, "maxim,tmp-fans", i))) {
61300783d5eSAndrew Jeffery 		if (of_property_read_u32(np, "reg", &uval)) {
61400783d5eSAndrew Jeffery 			dev_err(&client->dev, "Failed to read fan reg property for phandle index %d\n",
61500783d5eSAndrew Jeffery 					i);
61600783d5eSAndrew Jeffery 		} else {
61700783d5eSAndrew Jeffery 			if (uval < 6)
61800783d5eSAndrew Jeffery 				mfr_tmp_cfg |= BIT(uval);
61900783d5eSAndrew Jeffery 			else
62000783d5eSAndrew Jeffery 				dev_warn(&client->dev, "Invalid fan page: %d\n",
62100783d5eSAndrew Jeffery 						uval);
62200783d5eSAndrew Jeffery 		}
62300783d5eSAndrew Jeffery 		i++;
62400783d5eSAndrew Jeffery 	}
62500783d5eSAndrew Jeffery 
626*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_word_data(client, MFR_TEMP_SENSOR_CONFIG,
62700783d5eSAndrew Jeffery 					mfr_tmp_cfg);
62800783d5eSAndrew Jeffery 	if (ret < 0)
62900783d5eSAndrew Jeffery 		return ret;
63000783d5eSAndrew Jeffery 
63100783d5eSAndrew Jeffery 	return 0;
63200783d5eSAndrew Jeffery }
63300783d5eSAndrew Jeffery 
6344d420a6aSAndrew Jeffery #define MAX31785_FAN_FUNCS \
63556ad86b4SAndrew Jeffery 	(PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_PWM12)
6364d420a6aSAndrew Jeffery 
6374d420a6aSAndrew Jeffery #define MAX31785_TEMP_FUNCS \
6384d420a6aSAndrew Jeffery 	(PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
6394d420a6aSAndrew Jeffery 
6404d420a6aSAndrew Jeffery #define MAX31785_VOUT_FUNCS \
6414d420a6aSAndrew Jeffery 	(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
6424d420a6aSAndrew Jeffery 
6434d420a6aSAndrew Jeffery static const struct pmbus_driver_info max31785_info = {
6444d420a6aSAndrew Jeffery 	.pages = MAX31785_NR_PAGES,
6454d420a6aSAndrew Jeffery 
64656ad86b4SAndrew Jeffery 	.write_word_data = max31785_write_word_data,
647cf583b42SAndrew Jeffery 	.read_byte_data = max31785_read_byte_data,
64856ad86b4SAndrew Jeffery 	.read_word_data = max31785_read_word_data,
649cf583b42SAndrew Jeffery 	.write_byte = max31785_write_byte,
65056ad86b4SAndrew Jeffery 
6514d420a6aSAndrew Jeffery 	/* RPM */
6524d420a6aSAndrew Jeffery 	.format[PSC_FAN] = direct,
6534d420a6aSAndrew Jeffery 	.m[PSC_FAN] = 1,
6544d420a6aSAndrew Jeffery 	.b[PSC_FAN] = 0,
6554d420a6aSAndrew Jeffery 	.R[PSC_FAN] = 0,
65656ad86b4SAndrew Jeffery 	/* PWM */
65756ad86b4SAndrew Jeffery 	.format[PSC_PWM] = direct,
65856ad86b4SAndrew Jeffery 	.m[PSC_PWM] = 1,
65956ad86b4SAndrew Jeffery 	.b[PSC_PWM] = 0,
66056ad86b4SAndrew Jeffery 	.R[PSC_PWM] = 2,
6614d420a6aSAndrew Jeffery 	.func[0] = MAX31785_FAN_FUNCS,
6624d420a6aSAndrew Jeffery 	.func[1] = MAX31785_FAN_FUNCS,
6634d420a6aSAndrew Jeffery 	.func[2] = MAX31785_FAN_FUNCS,
6644d420a6aSAndrew Jeffery 	.func[3] = MAX31785_FAN_FUNCS,
6654d420a6aSAndrew Jeffery 	.func[4] = MAX31785_FAN_FUNCS,
6664d420a6aSAndrew Jeffery 	.func[5] = MAX31785_FAN_FUNCS,
6674d420a6aSAndrew Jeffery 
6684d420a6aSAndrew Jeffery 	.format[PSC_TEMPERATURE] = direct,
6694d420a6aSAndrew Jeffery 	.m[PSC_TEMPERATURE] = 1,
6704d420a6aSAndrew Jeffery 	.b[PSC_TEMPERATURE] = 0,
6714d420a6aSAndrew Jeffery 	.R[PSC_TEMPERATURE] = 2,
6724d420a6aSAndrew Jeffery 	.func[6]  = MAX31785_TEMP_FUNCS,
6734d420a6aSAndrew Jeffery 	.func[7]  = MAX31785_TEMP_FUNCS,
6744d420a6aSAndrew Jeffery 	.func[8]  = MAX31785_TEMP_FUNCS,
6754d420a6aSAndrew Jeffery 	.func[9]  = MAX31785_TEMP_FUNCS,
6764d420a6aSAndrew Jeffery 	.func[10] = MAX31785_TEMP_FUNCS,
6774d420a6aSAndrew Jeffery 	.func[11] = MAX31785_TEMP_FUNCS,
6784d420a6aSAndrew Jeffery 	.func[12] = MAX31785_TEMP_FUNCS,
6794d420a6aSAndrew Jeffery 	.func[13] = MAX31785_TEMP_FUNCS,
6804d420a6aSAndrew Jeffery 	.func[14] = MAX31785_TEMP_FUNCS,
6814d420a6aSAndrew Jeffery 	.func[15] = MAX31785_TEMP_FUNCS,
6824d420a6aSAndrew Jeffery 	.func[16] = MAX31785_TEMP_FUNCS,
6834d420a6aSAndrew Jeffery 
6844d420a6aSAndrew Jeffery 	.format[PSC_VOLTAGE_OUT] = direct,
6854d420a6aSAndrew Jeffery 	.m[PSC_VOLTAGE_OUT] = 1,
6864d420a6aSAndrew Jeffery 	.b[PSC_VOLTAGE_OUT] = 0,
6874d420a6aSAndrew Jeffery 	.R[PSC_VOLTAGE_OUT] = 0,
6884d420a6aSAndrew Jeffery 	.func[17] = MAX31785_VOUT_FUNCS,
6894d420a6aSAndrew Jeffery 	.func[18] = MAX31785_VOUT_FUNCS,
6904d420a6aSAndrew Jeffery 	.func[19] = MAX31785_VOUT_FUNCS,
6914d420a6aSAndrew Jeffery 	.func[20] = MAX31785_VOUT_FUNCS,
6924d420a6aSAndrew Jeffery 	.func[21] = MAX31785_VOUT_FUNCS,
6934d420a6aSAndrew Jeffery 	.func[22] = MAX31785_VOUT_FUNCS,
6944d420a6aSAndrew Jeffery };
6954d420a6aSAndrew Jeffery 
max31785_configure_dual_tach(struct i2c_client * client,struct pmbus_driver_info * info)696cf583b42SAndrew Jeffery static int max31785_configure_dual_tach(struct i2c_client *client,
697cf583b42SAndrew Jeffery 					struct pmbus_driver_info *info)
698cf583b42SAndrew Jeffery {
699cf583b42SAndrew Jeffery 	int ret;
700cf583b42SAndrew Jeffery 	int i;
701cf583b42SAndrew Jeffery 
702cf583b42SAndrew Jeffery 	for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) {
703*a529fa1bSAndrew Jeffery 		ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
704cf583b42SAndrew Jeffery 		if (ret < 0)
705cf583b42SAndrew Jeffery 			return ret;
706cf583b42SAndrew Jeffery 
707*a529fa1bSAndrew Jeffery 		ret = max31785_i2c_smbus_read_word_data(client, MFR_FAN_CONFIG);
708cf583b42SAndrew Jeffery 		if (ret < 0)
709cf583b42SAndrew Jeffery 			return ret;
710cf583b42SAndrew Jeffery 
711cf583b42SAndrew Jeffery 		if (ret & MFR_FAN_CONFIG_DUAL_TACH) {
712cf583b42SAndrew Jeffery 			int virtual = MAX31785_NR_PAGES + i;
713cf583b42SAndrew Jeffery 
714cf583b42SAndrew Jeffery 			info->pages = virtual + 1;
715cf583b42SAndrew Jeffery 			info->func[virtual] |= PMBUS_HAVE_FAN12;
716cf583b42SAndrew Jeffery 			info->func[virtual] |= PMBUS_PAGE_VIRTUAL;
717cf583b42SAndrew Jeffery 		}
718cf583b42SAndrew Jeffery 	}
719cf583b42SAndrew Jeffery 
720cf583b42SAndrew Jeffery 	return 0;
721cf583b42SAndrew Jeffery }
722cf583b42SAndrew Jeffery 
max31785_probe(struct i2c_client * client)723dd431939SStephen Kitt static int max31785_probe(struct i2c_client *client)
7244d420a6aSAndrew Jeffery {
7254d420a6aSAndrew Jeffery 	struct device *dev = &client->dev;
72600783d5eSAndrew Jeffery 	struct device_node *child;
7274d420a6aSAndrew Jeffery 	struct pmbus_driver_info *info;
728cf583b42SAndrew Jeffery 	bool dual_tach = false;
729996dc09cSMatthew Barth 	int ret;
73000783d5eSAndrew Jeffery 	u32 fans;
73100783d5eSAndrew Jeffery 	int i;
7324d420a6aSAndrew Jeffery 
733cf583b42SAndrew Jeffery 	if (!i2c_check_functionality(client->adapter,
734cf583b42SAndrew Jeffery 				     I2C_FUNC_SMBUS_BYTE_DATA |
735cf583b42SAndrew Jeffery 				     I2C_FUNC_SMBUS_WORD_DATA))
736cf583b42SAndrew Jeffery 		return -ENODEV;
737cf583b42SAndrew Jeffery 
7384d420a6aSAndrew Jeffery 	info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
7394d420a6aSAndrew Jeffery 	if (!info)
7404d420a6aSAndrew Jeffery 		return -ENOMEM;
7414d420a6aSAndrew Jeffery 
7424d420a6aSAndrew Jeffery 	*info = max31785_info;
7434d420a6aSAndrew Jeffery 
744*a529fa1bSAndrew Jeffery 	ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
7454d420a6aSAndrew Jeffery 	if (ret < 0)
7464d420a6aSAndrew Jeffery 		return ret;
7474d420a6aSAndrew Jeffery 
748cf583b42SAndrew Jeffery 	ret = i2c_smbus_read_word_data(client, MFR_REVISION);
749cf583b42SAndrew Jeffery 	if (ret < 0)
750cf583b42SAndrew Jeffery 		return ret;
751cf583b42SAndrew Jeffery 
752996dc09cSMatthew Barth 	if (ret == MAX31785A || ret == MAX31785B) {
753cf583b42SAndrew Jeffery 		dual_tach = true;
754cf583b42SAndrew Jeffery 	} else if (ret == MAX31785) {
755996dc09cSMatthew Barth 		if (!strcmp("max31785a", client->name) ||
756996dc09cSMatthew Barth 		    !strcmp("max31785b", client->name))
757996dc09cSMatthew Barth 			dev_warn(dev, "Expected max31785a/b, found max31785: cannot provide secondary tachometer readings\n");
758cf583b42SAndrew Jeffery 	} else {
759996dc09cSMatthew Barth 		dev_err(dev, "Unrecognized MAX31785 revision: %x\n", ret);
760cf583b42SAndrew Jeffery 		return -ENODEV;
761cf583b42SAndrew Jeffery 	}
762cf583b42SAndrew Jeffery 
76300783d5eSAndrew Jeffery 	fans = 0;
76400783d5eSAndrew Jeffery 	for_each_child_of_node(dev->of_node, child) {
76500783d5eSAndrew Jeffery 		ret = max31785_of_fan_config(client, info, child);
76600783d5eSAndrew Jeffery 		if (ret < 0) {
76700783d5eSAndrew Jeffery 			of_node_put(child);
76800783d5eSAndrew Jeffery 			return ret;
76900783d5eSAndrew Jeffery 		}
77000783d5eSAndrew Jeffery 
77100783d5eSAndrew Jeffery 		if (ret)
77200783d5eSAndrew Jeffery 			fans |= ret;
77300783d5eSAndrew Jeffery 
77400783d5eSAndrew Jeffery 		ret = max31785_of_tmp_config(client, info, child);
77500783d5eSAndrew Jeffery 		if (ret < 0) {
77600783d5eSAndrew Jeffery 			of_node_put(child);
77700783d5eSAndrew Jeffery 			return ret;
77800783d5eSAndrew Jeffery 		}
77900783d5eSAndrew Jeffery 	}
78000783d5eSAndrew Jeffery 
78100783d5eSAndrew Jeffery 	for (i = 0; i < MAX31785_NR_PAGES; i++) {
78200783d5eSAndrew Jeffery 		bool have_fan = !!(info->func[i] & PMBUS_HAVE_FAN12);
78300783d5eSAndrew Jeffery 		bool fan_configured = !!(fans & BIT(i));
78400783d5eSAndrew Jeffery 
78500783d5eSAndrew Jeffery 		if (!have_fan || fan_configured)
78600783d5eSAndrew Jeffery 			continue;
78700783d5eSAndrew Jeffery 
788*a529fa1bSAndrew Jeffery 		ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE,
789*a529fa1bSAndrew Jeffery 							 i);
79000783d5eSAndrew Jeffery 		if (ret < 0)
79100783d5eSAndrew Jeffery 			return ret;
79200783d5eSAndrew Jeffery 
793*a529fa1bSAndrew Jeffery 		ret = max31785_i2c_smbus_read_byte_data(client,
794*a529fa1bSAndrew Jeffery 							PMBUS_FAN_CONFIG_12);
79500783d5eSAndrew Jeffery 		if (ret < 0)
79600783d5eSAndrew Jeffery 			return ret;
79700783d5eSAndrew Jeffery 
79800783d5eSAndrew Jeffery 		ret &= ~PB_FAN_1_INSTALLED;
799*a529fa1bSAndrew Jeffery 		ret = max31785_i2c_smbus_write_word_data(client,
800*a529fa1bSAndrew Jeffery 							 PMBUS_FAN_CONFIG_12,
80100783d5eSAndrew Jeffery 							 ret);
80200783d5eSAndrew Jeffery 		if (ret < 0)
80300783d5eSAndrew Jeffery 			return ret;
80400783d5eSAndrew Jeffery 	}
80500783d5eSAndrew Jeffery 
806cf583b42SAndrew Jeffery 	if (dual_tach) {
807cf583b42SAndrew Jeffery 		ret = max31785_configure_dual_tach(client, info);
808cf583b42SAndrew Jeffery 		if (ret < 0)
809cf583b42SAndrew Jeffery 			return ret;
810cf583b42SAndrew Jeffery 	}
811cf583b42SAndrew Jeffery 
812dd431939SStephen Kitt 	return pmbus_do_probe(client, info);
8134d420a6aSAndrew Jeffery }
8144d420a6aSAndrew Jeffery 
8154d420a6aSAndrew Jeffery static const struct i2c_device_id max31785_id[] = {
8164d420a6aSAndrew Jeffery 	{ "max31785", 0 },
8174d420a6aSAndrew Jeffery 	{ "max31785a", 0 },
818996dc09cSMatthew Barth 	{ "max31785b", 0 },
8194d420a6aSAndrew Jeffery 	{ },
8204d420a6aSAndrew Jeffery };
8214d420a6aSAndrew Jeffery 
8224d420a6aSAndrew Jeffery MODULE_DEVICE_TABLE(i2c, max31785_id);
8234d420a6aSAndrew Jeffery 
82498b16a09SJavier Martinez Canillas static const struct of_device_id max31785_of_match[] = {
82598b16a09SJavier Martinez Canillas 	{ .compatible = "maxim,max31785" },
82698b16a09SJavier Martinez Canillas 	{ .compatible = "maxim,max31785a" },
827996dc09cSMatthew Barth 	{ .compatible = "maxim,max31785b" },
82898b16a09SJavier Martinez Canillas 	{ },
82998b16a09SJavier Martinez Canillas };
83098b16a09SJavier Martinez Canillas 
83198b16a09SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, max31785_of_match);
83298b16a09SJavier Martinez Canillas 
8334d420a6aSAndrew Jeffery static struct i2c_driver max31785_driver = {
8344d420a6aSAndrew Jeffery 	.driver = {
8354d420a6aSAndrew Jeffery 		.name = "max31785",
83698b16a09SJavier Martinez Canillas 		.of_match_table = max31785_of_match,
8374d420a6aSAndrew Jeffery 	},
8381975d167SUwe Kleine-König 	.probe = max31785_probe,
8394d420a6aSAndrew Jeffery 	.id_table = max31785_id,
8404d420a6aSAndrew Jeffery };
8414d420a6aSAndrew Jeffery 
8424d420a6aSAndrew Jeffery module_i2c_driver(max31785_driver);
8434d420a6aSAndrew Jeffery 
8444d420a6aSAndrew Jeffery MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
8454d420a6aSAndrew Jeffery MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
8464d420a6aSAndrew Jeffery MODULE_LICENSE("GPL");
847b94ca77eSGuenter Roeck MODULE_IMPORT_NS(PMBUS);
848