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