Skip to content

Commit cf583b4

Browse files
amboargroeck
authored andcommitted
hwmon: (pmbus/max31785) Add dual tachometer support
The dual tachometer feature is implemented in hardware with a TACHSEL input to indicate the rotor under measurement, and exposed on the device by extending the READ_FAN_SPEED_1 word with two extra bytes*. The need to read the non-standard four-byte response leads to a cut-down implementation of i2c_smbus_xfer_emulated() included in the driver. Further, to expose the second rotor tachometer value to userspace the values are exposed through virtual pages. We re-route accesses to FAN_CONFIG_1_2 and READ_FAN_SPEED_1 on pages 23-28 (not defined by the hardware) to the same registers on pages 0-5, and with the latter command we extract the value from the second word of the four-byte response. * The documentation recommends the slower rotor be associated with TACHSEL=0, which corresponds to the first word of the response. The TACHSEL=0 measurement is used by the controller's closed-loop fan management to judge target fan rate. Signed-off-by: Andrew Jeffery <[email protected]> Signed-off-by: Guenter Roeck <[email protected]>
1 parent 464df6f commit cf583b4

File tree

2 files changed

+152
-3
lines changed

2 files changed

+152
-3
lines changed

Documentation/hwmon/max31785

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ management with temperature and remote voltage sensing. Various fan control
1717
features are provided, including PWM frequency control, temperature hysteresis,
1818
dual tachometer measurements, and fan health monitoring.
1919

20-
For dual rotor fan configuration, the MAX31785 exposes the slowest rotor of the
21-
two in the fan[1-4]_input attributes.
20+
For dual-rotor configurations the MAX31785A exposes the second rotor tachometer
21+
readings in attributes fan[5-8]_input. By contrast the MAX31785 only exposes
22+
the slowest rotor measurement, and does so in the fan[1-4]_input attributes.
2223

2324
Usage Notes
2425
-----------
@@ -31,7 +32,8 @@ Sysfs attributes
3132

3233
fan[1-4]_alarm Fan alarm.
3334
fan[1-4]_fault Fan fault.
34-
fan[1-4]_input Fan RPM.
35+
fan[1-8]_input Fan RPM. On the MAX31785A, inputs 5-8 correspond to the
36+
second rotor of fans 1-4
3537
fan[1-4]_target Fan input target
3638

3739
in[1-6]_crit Critical maximum output voltage

drivers/hwmon/pmbus/max31785.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,79 @@
1616

1717
enum max31785_regs {
1818
MFR_REVISION = 0x9b,
19+
MFR_FAN_CONFIG = 0xf1,
1920
};
2021

22+
#define MAX31785 0x3030
23+
#define MAX31785A 0x3040
24+
25+
#define MFR_FAN_CONFIG_DUAL_TACH BIT(12)
26+
2127
#define MAX31785_NR_PAGES 23
28+
#define MAX31785_NR_FAN_PAGES 6
29+
30+
static int max31785_read_byte_data(struct i2c_client *client, int page,
31+
int reg)
32+
{
33+
if (page < MAX31785_NR_PAGES)
34+
return -ENODATA;
35+
36+
switch (reg) {
37+
case PMBUS_VOUT_MODE:
38+
return -ENOTSUPP;
39+
case PMBUS_FAN_CONFIG_12:
40+
return pmbus_read_byte_data(client, page - MAX31785_NR_PAGES,
41+
reg);
42+
}
43+
44+
return -ENODATA;
45+
}
46+
47+
static int max31785_write_byte(struct i2c_client *client, int page, u8 value)
48+
{
49+
if (page < MAX31785_NR_PAGES)
50+
return -ENODATA;
51+
52+
return -ENOTSUPP;
53+
}
54+
55+
static int max31785_read_long_data(struct i2c_client *client, int page,
56+
int reg, u32 *data)
57+
{
58+
unsigned char cmdbuf[1];
59+
unsigned char rspbuf[4];
60+
int rc;
61+
62+
struct i2c_msg msg[2] = {
63+
{
64+
.addr = client->addr,
65+
.flags = 0,
66+
.len = sizeof(cmdbuf),
67+
.buf = cmdbuf,
68+
},
69+
{
70+
.addr = client->addr,
71+
.flags = I2C_M_RD,
72+
.len = sizeof(rspbuf),
73+
.buf = rspbuf,
74+
},
75+
};
76+
77+
cmdbuf[0] = reg;
78+
79+
rc = pmbus_set_page(client, page);
80+
if (rc < 0)
81+
return rc;
82+
83+
rc = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
84+
if (rc < 0)
85+
return rc;
86+
87+
*data = (rspbuf[0] << (0 * 8)) | (rspbuf[1] << (1 * 8)) |
88+
(rspbuf[2] << (2 * 8)) | (rspbuf[3] << (3 * 8));
89+
90+
return rc;
91+
}
2292

2393
static int max31785_get_pwm(struct i2c_client *client, int page)
2494
{
@@ -62,9 +132,30 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
62132
static int max31785_read_word_data(struct i2c_client *client, int page,
63133
int reg)
64134
{
135+
u32 val;
65136
int rv;
66137

67138
switch (reg) {
139+
case PMBUS_READ_FAN_SPEED_1:
140+
if (page < MAX31785_NR_PAGES)
141+
return -ENODATA;
142+
143+
rv = max31785_read_long_data(client, page - MAX31785_NR_PAGES,
144+
reg, &val);
145+
if (rv < 0)
146+
return rv;
147+
148+
rv = (val >> 16) & 0xffff;
149+
break;
150+
case PMBUS_FAN_COMMAND_1:
151+
/*
152+
* PMBUS_FAN_COMMAND_x is probed to judge whether or not to
153+
* expose fan control registers.
154+
*
155+
* Don't expose fan_target attribute for virtual pages.
156+
*/
157+
rv = (page >= MAX31785_NR_PAGES) ? -ENOTSUPP : -ENODATA;
158+
break;
68159
case PMBUS_VIRT_PWM_1:
69160
rv = max31785_get_pwm(client, page);
70161
break;
@@ -157,11 +248,15 @@ static int max31785_write_word_data(struct i2c_client *client, int page,
157248
#define MAX31785_VOUT_FUNCS \
158249
(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
159250

251+
#define MAX37185_NUM_FAN_PAGES 6
252+
160253
static const struct pmbus_driver_info max31785_info = {
161254
.pages = MAX31785_NR_PAGES,
162255

163256
.write_word_data = max31785_write_word_data,
257+
.read_byte_data = max31785_read_byte_data,
164258
.read_word_data = max31785_read_word_data,
259+
.write_byte = max31785_write_byte,
165260

166261
/* RPM */
167262
.format[PSC_FAN] = direct,
@@ -208,13 +303,46 @@ static const struct pmbus_driver_info max31785_info = {
208303
.func[22] = MAX31785_VOUT_FUNCS,
209304
};
210305

306+
static int max31785_configure_dual_tach(struct i2c_client *client,
307+
struct pmbus_driver_info *info)
308+
{
309+
int ret;
310+
int i;
311+
312+
for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) {
313+
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
314+
if (ret < 0)
315+
return ret;
316+
317+
ret = i2c_smbus_read_word_data(client, MFR_FAN_CONFIG);
318+
if (ret < 0)
319+
return ret;
320+
321+
if (ret & MFR_FAN_CONFIG_DUAL_TACH) {
322+
int virtual = MAX31785_NR_PAGES + i;
323+
324+
info->pages = virtual + 1;
325+
info->func[virtual] |= PMBUS_HAVE_FAN12;
326+
info->func[virtual] |= PMBUS_PAGE_VIRTUAL;
327+
}
328+
}
329+
330+
return 0;
331+
}
332+
211333
static int max31785_probe(struct i2c_client *client,
212334
const struct i2c_device_id *id)
213335
{
214336
struct device *dev = &client->dev;
215337
struct pmbus_driver_info *info;
338+
bool dual_tach = false;
216339
s64 ret;
217340

341+
if (!i2c_check_functionality(client->adapter,
342+
I2C_FUNC_SMBUS_BYTE_DATA |
343+
I2C_FUNC_SMBUS_WORD_DATA))
344+
return -ENODEV;
345+
218346
info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
219347
if (!info)
220348
return -ENOMEM;
@@ -225,6 +353,25 @@ static int max31785_probe(struct i2c_client *client,
225353
if (ret < 0)
226354
return ret;
227355

356+
ret = i2c_smbus_read_word_data(client, MFR_REVISION);
357+
if (ret < 0)
358+
return ret;
359+
360+
if (ret == MAX31785A) {
361+
dual_tach = true;
362+
} else if (ret == MAX31785) {
363+
if (!strcmp("max31785a", id->name))
364+
dev_warn(dev, "Expected max3175a, found max31785: cannot provide secondary tachometer readings\n");
365+
} else {
366+
return -ENODEV;
367+
}
368+
369+
if (dual_tach) {
370+
ret = max31785_configure_dual_tach(client, info);
371+
if (ret < 0)
372+
return ret;
373+
}
374+
228375
return pmbus_do_probe(client, id, info);
229376
}
230377

0 commit comments

Comments
 (0)