1 // SPDX-License-Identifier: GPL-2.0+
3 * Hardware monitoring driver for Vicor PLI1209BC Digital Supervisor
5 * Copyright (c) 2022 9elements GmbH
8 #include <linux/delay.h>
10 #include <linux/module.h>
11 #include <linux/pmbus.h>
12 #include <linux/regulator/driver.h>
16 * The capability command is only supported at page 0. Probing the device while
17 * the page register is set to 1 will falsely enable PEC support. Disable
18 * capability probing accordingly, since the PLI1209BC does not have any
19 * additional capabilities.
21 static struct pmbus_platform_data pli1209bc_plat_data
= {
22 .flags
= PMBUS_NO_CAPABILITY
,
25 static int pli1209bc_read_word_data(struct i2c_client
*client
, int page
,
31 /* PMBUS_READ_POUT uses a direct format with R=0 */
33 data
= pmbus_read_word_data(client
, page
, phase
, reg
);
36 data
= sign_extend32(data
, 15) * 10;
37 return clamp_val(data
, -32768, 32767) & 0xffff;
39 * PMBUS_READ_VOUT and PMBUS_READ_TEMPERATURE_1 return invalid data
40 * when the BCM is turned off. Since it is not possible to return
41 * ENODATA error, return zero instead.
44 case PMBUS_READ_TEMPERATURE_1
:
45 data
= pmbus_read_word_data(client
, page
, phase
,
49 if (data
& PB_STATUS_POWER_GOOD_N
)
51 return pmbus_read_word_data(client
, page
, phase
, reg
);
57 #if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
58 static const struct regulator_desc pli1209bc_reg_desc
= {
61 .of_match
= of_match_ptr("vout2"),
62 .regulators_node
= of_match_ptr("regulators"),
63 .ops
= &pmbus_regulator_ops
,
64 .type
= REGULATOR_VOLTAGE
,
69 static struct pmbus_driver_info pli1209bc_info
= {
71 .format
[PSC_VOLTAGE_IN
] = direct
,
72 .format
[PSC_VOLTAGE_OUT
] = direct
,
73 .format
[PSC_CURRENT_IN
] = direct
,
74 .format
[PSC_CURRENT_OUT
] = direct
,
75 .format
[PSC_POWER
] = direct
,
76 .format
[PSC_TEMPERATURE
] = direct
,
77 .m
[PSC_VOLTAGE_IN
] = 1,
78 .b
[PSC_VOLTAGE_IN
] = 0,
79 .R
[PSC_VOLTAGE_IN
] = 1,
80 .m
[PSC_VOLTAGE_OUT
] = 1,
81 .b
[PSC_VOLTAGE_OUT
] = 0,
82 .R
[PSC_VOLTAGE_OUT
] = 1,
83 .m
[PSC_CURRENT_IN
] = 1,
84 .b
[PSC_CURRENT_IN
] = 0,
85 .R
[PSC_CURRENT_IN
] = 3,
86 .m
[PSC_CURRENT_OUT
] = 1,
87 .b
[PSC_CURRENT_OUT
] = 0,
88 .R
[PSC_CURRENT_OUT
] = 2,
92 .m
[PSC_TEMPERATURE
] = 1,
93 .b
[PSC_TEMPERATURE
] = 0,
94 .R
[PSC_TEMPERATURE
] = 0,
96 * Page 0 sums up all attributes except voltage readings.
97 * The pli1209 digital supervisor only contains a single BCM, making
100 .func
[1] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
101 | PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT
102 | PMBUS_HAVE_PIN
| PMBUS_HAVE_POUT
103 | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_TEMP
104 | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT
,
105 .read_word_data
= pli1209bc_read_word_data
,
107 #if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
109 .reg_desc
= &pli1209bc_reg_desc
,
113 static int pli1209bc_probe(struct i2c_client
*client
)
115 client
->dev
.platform_data
= &pli1209bc_plat_data
;
116 return pmbus_do_probe(client
, &pli1209bc_info
);
119 static const struct i2c_device_id pli1209bc_id
[] = {
124 MODULE_DEVICE_TABLE(i2c
, pli1209bc_id
);
127 static const struct of_device_id pli1209bc_of_match
[] = {
128 { .compatible
= "vicor,pli1209bc" },
131 MODULE_DEVICE_TABLE(of
, pli1209bc_of_match
);
134 static struct i2c_driver pli1209bc_driver
= {
137 .of_match_table
= of_match_ptr(pli1209bc_of_match
),
139 .probe
= pli1209bc_probe
,
140 .id_table
= pli1209bc_id
,
143 module_i2c_driver(pli1209bc_driver
);
145 MODULE_AUTHOR("Marcello Sylvester Bauer <sylv@sylv.io>");
146 MODULE_DESCRIPTION("PMBus driver for Vicor PLI1209BC");
147 MODULE_LICENSE("GPL");
148 MODULE_IMPORT_NS("PMBUS");