xref: /linux/drivers/hwmon/pmbus/ltc4286.c (revision 0c459759ca971ee49a313b19ba50fc499c6cf8ca)
1*0c459759SDelphine CC Chiu // SPDX-License-Identifier: GPL-2.0-or-later
2*0c459759SDelphine CC Chiu 
3*0c459759SDelphine CC Chiu #include <linux/err.h>
4*0c459759SDelphine CC Chiu #include <linux/i2c.h>
5*0c459759SDelphine CC Chiu #include <linux/init.h>
6*0c459759SDelphine CC Chiu #include <linux/kernel.h>
7*0c459759SDelphine CC Chiu #include <linux/module.h>
8*0c459759SDelphine CC Chiu #include <linux/pmbus.h>
9*0c459759SDelphine CC Chiu #include "pmbus.h"
10*0c459759SDelphine CC Chiu 
11*0c459759SDelphine CC Chiu /* LTC4286 register */
12*0c459759SDelphine CC Chiu #define LTC4286_MFR_CONFIG1	0xF2
13*0c459759SDelphine CC Chiu 
14*0c459759SDelphine CC Chiu /* LTC4286 configuration */
15*0c459759SDelphine CC Chiu #define VRANGE_SELECT_BIT	BIT(1)
16*0c459759SDelphine CC Chiu 
17*0c459759SDelphine CC Chiu #define LTC4286_MFR_ID_SIZE	3
18*0c459759SDelphine CC Chiu 
19*0c459759SDelphine CC Chiu /*
20*0c459759SDelphine CC Chiu  * Initialize the MBR as default settings which is referred to LTC4286 datasheet
21*0c459759SDelphine CC Chiu  * (March 22, 2022 version) table 3 page 16
22*0c459759SDelphine CC Chiu  */
23*0c459759SDelphine CC Chiu static struct pmbus_driver_info ltc4286_info = {
24*0c459759SDelphine CC Chiu 	.pages = 1,
25*0c459759SDelphine CC Chiu 	.format[PSC_VOLTAGE_IN] = direct,
26*0c459759SDelphine CC Chiu 	.format[PSC_VOLTAGE_OUT] = direct,
27*0c459759SDelphine CC Chiu 	.format[PSC_CURRENT_OUT] = direct,
28*0c459759SDelphine CC Chiu 	.format[PSC_POWER] = direct,
29*0c459759SDelphine CC Chiu 	.format[PSC_TEMPERATURE] = direct,
30*0c459759SDelphine CC Chiu 	.m[PSC_VOLTAGE_IN] = 32,
31*0c459759SDelphine CC Chiu 	.b[PSC_VOLTAGE_IN] = 0,
32*0c459759SDelphine CC Chiu 	.R[PSC_VOLTAGE_IN] = 1,
33*0c459759SDelphine CC Chiu 	.m[PSC_VOLTAGE_OUT] = 32,
34*0c459759SDelphine CC Chiu 	.b[PSC_VOLTAGE_OUT] = 0,
35*0c459759SDelphine CC Chiu 	.R[PSC_VOLTAGE_OUT] = 1,
36*0c459759SDelphine CC Chiu 	.m[PSC_CURRENT_OUT] = 1024,
37*0c459759SDelphine CC Chiu 	.b[PSC_CURRENT_OUT] = 0,
38*0c459759SDelphine CC Chiu 	/*
39*0c459759SDelphine CC Chiu 	 * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit.
40*0c459759SDelphine CC Chiu 	 * However, the rsense value that user input is micro ohm.
41*0c459759SDelphine CC Chiu 	 * Thus, the MBR setting which involves rsense should be shifted by 6 digits.
42*0c459759SDelphine CC Chiu 	 */
43*0c459759SDelphine CC Chiu 	.R[PSC_CURRENT_OUT] = 3 - 6,
44*0c459759SDelphine CC Chiu 	.m[PSC_POWER] = 1,
45*0c459759SDelphine CC Chiu 	.b[PSC_POWER] = 0,
46*0c459759SDelphine CC Chiu 	/*
47*0c459759SDelphine CC Chiu 	 * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit.
48*0c459759SDelphine CC Chiu 	 * However, the rsense value that user input is micro ohm.
49*0c459759SDelphine CC Chiu 	 * Thus, the MBR setting which involves rsense should be shifted by 6 digits.
50*0c459759SDelphine CC Chiu 	 */
51*0c459759SDelphine CC Chiu 	.R[PSC_POWER] = 4 - 6,
52*0c459759SDelphine CC Chiu 	.m[PSC_TEMPERATURE] = 1,
53*0c459759SDelphine CC Chiu 	.b[PSC_TEMPERATURE] = 273,
54*0c459759SDelphine CC Chiu 	.R[PSC_TEMPERATURE] = 0,
55*0c459759SDelphine CC Chiu 	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
56*0c459759SDelphine CC Chiu 		   PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT |
57*0c459759SDelphine CC Chiu 		   PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP,
58*0c459759SDelphine CC Chiu };
59*0c459759SDelphine CC Chiu 
60*0c459759SDelphine CC Chiu static const struct i2c_device_id ltc4286_id[] = {
61*0c459759SDelphine CC Chiu 	{ "ltc4286", 0 },
62*0c459759SDelphine CC Chiu 	{ "ltc4287", 1 },
63*0c459759SDelphine CC Chiu 	{}
64*0c459759SDelphine CC Chiu };
65*0c459759SDelphine CC Chiu MODULE_DEVICE_TABLE(i2c, ltc4286_id);
66*0c459759SDelphine CC Chiu 
67*0c459759SDelphine CC Chiu static int ltc4286_probe(struct i2c_client *client)
68*0c459759SDelphine CC Chiu {
69*0c459759SDelphine CC Chiu 	int ret;
70*0c459759SDelphine CC Chiu 	const struct i2c_device_id *mid;
71*0c459759SDelphine CC Chiu 	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
72*0c459759SDelphine CC Chiu 	struct pmbus_driver_info *info;
73*0c459759SDelphine CC Chiu 	u32 rsense;
74*0c459759SDelphine CC Chiu 	int vrange_nval, vrange_oval;
75*0c459759SDelphine CC Chiu 
76*0c459759SDelphine CC Chiu 	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
77*0c459759SDelphine CC Chiu 	if (ret < 0) {
78*0c459759SDelphine CC Chiu 		return dev_err_probe(&client->dev, ret,
79*0c459759SDelphine CC Chiu 				     "Failed to read manufacturer id\n");
80*0c459759SDelphine CC Chiu 	}
81*0c459759SDelphine CC Chiu 
82*0c459759SDelphine CC Chiu 	/*
83*0c459759SDelphine CC Chiu 	 * Refer to ltc4286 datasheet page 20
84*0c459759SDelphine CC Chiu 	 * the manufacturer id is LTC
85*0c459759SDelphine CC Chiu 	 */
86*0c459759SDelphine CC Chiu 	if (ret != LTC4286_MFR_ID_SIZE ||
87*0c459759SDelphine CC Chiu 	    strncmp(block_buffer, "LTC", LTC4286_MFR_ID_SIZE)) {
88*0c459759SDelphine CC Chiu 		return dev_err_probe(&client->dev, -ENODEV,
89*0c459759SDelphine CC Chiu 				     "Manufacturer id mismatch\n");
90*0c459759SDelphine CC Chiu 	}
91*0c459759SDelphine CC Chiu 
92*0c459759SDelphine CC Chiu 	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
93*0c459759SDelphine CC Chiu 	if (ret < 0) {
94*0c459759SDelphine CC Chiu 		return dev_err_probe(&client->dev, ret,
95*0c459759SDelphine CC Chiu 				     "Failed to read manufacturer model\n");
96*0c459759SDelphine CC Chiu 	}
97*0c459759SDelphine CC Chiu 
98*0c459759SDelphine CC Chiu 	for (mid = ltc4286_id; mid->name[0]; mid++) {
99*0c459759SDelphine CC Chiu 		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
100*0c459759SDelphine CC Chiu 			break;
101*0c459759SDelphine CC Chiu 	}
102*0c459759SDelphine CC Chiu 	if (!mid->name[0])
103*0c459759SDelphine CC Chiu 		return dev_err_probe(&client->dev, -ENODEV,
104*0c459759SDelphine CC Chiu 				     "Unsupported device\n");
105*0c459759SDelphine CC Chiu 
106*0c459759SDelphine CC Chiu 	if (of_property_read_u32(client->dev.of_node,
107*0c459759SDelphine CC Chiu 				 "shunt-resistor-micro-ohms", &rsense))
108*0c459759SDelphine CC Chiu 		rsense = 300; /* 0.3 mOhm if not set via DT */
109*0c459759SDelphine CC Chiu 
110*0c459759SDelphine CC Chiu 	if (rsense == 0)
111*0c459759SDelphine CC Chiu 		return -EINVAL;
112*0c459759SDelphine CC Chiu 
113*0c459759SDelphine CC Chiu 	/* Check for the latter MBR value won't overflow */
114*0c459759SDelphine CC Chiu 	if (rsense > (INT_MAX / 1024))
115*0c459759SDelphine CC Chiu 		return -EINVAL;
116*0c459759SDelphine CC Chiu 
117*0c459759SDelphine CC Chiu 	info = devm_kmemdup(&client->dev, &ltc4286_info, sizeof(*info),
118*0c459759SDelphine CC Chiu 			    GFP_KERNEL);
119*0c459759SDelphine CC Chiu 	if (!info)
120*0c459759SDelphine CC Chiu 		return -ENOMEM;
121*0c459759SDelphine CC Chiu 
122*0c459759SDelphine CC Chiu 	/* Check MFR1 CONFIG register bit 1 VRANGE_SELECT before driver loading */
123*0c459759SDelphine CC Chiu 	vrange_oval = i2c_smbus_read_word_data(client, LTC4286_MFR_CONFIG1);
124*0c459759SDelphine CC Chiu 	if (vrange_oval < 0)
125*0c459759SDelphine CC Chiu 		return dev_err_probe(&client->dev, vrange_oval,
126*0c459759SDelphine CC Chiu 				     "Failed to read manufacturer configuration one\n");
127*0c459759SDelphine CC Chiu 	vrange_nval = vrange_oval;
128*0c459759SDelphine CC Chiu 
129*0c459759SDelphine CC Chiu 	if (device_property_read_bool(&client->dev, "adi,vrange-low-enable")) {
130*0c459759SDelphine CC Chiu 		vrange_nval &=
131*0c459759SDelphine CC Chiu 			~VRANGE_SELECT_BIT; /* VRANGE_SELECT = 0, 25.6 volts */
132*0c459759SDelphine CC Chiu 
133*0c459759SDelphine CC Chiu 		info->m[PSC_VOLTAGE_IN] = 128;
134*0c459759SDelphine CC Chiu 		info->m[PSC_VOLTAGE_OUT] = 128;
135*0c459759SDelphine CC Chiu 		info->m[PSC_POWER] = 4 * rsense;
136*0c459759SDelphine CC Chiu 	} else {
137*0c459759SDelphine CC Chiu 		vrange_nval |=
138*0c459759SDelphine CC Chiu 			VRANGE_SELECT_BIT; /* VRANGE_SELECT = 1, 102.4 volts */
139*0c459759SDelphine CC Chiu 
140*0c459759SDelphine CC Chiu 		info->m[PSC_POWER] = rsense;
141*0c459759SDelphine CC Chiu 	}
142*0c459759SDelphine CC Chiu 	if (vrange_nval != vrange_oval) {
143*0c459759SDelphine CC Chiu 		/* Set MFR1 CONFIG register bit 1 VRANGE_SELECT */
144*0c459759SDelphine CC Chiu 		ret = i2c_smbus_write_word_data(client, LTC4286_MFR_CONFIG1,
145*0c459759SDelphine CC Chiu 						vrange_nval);
146*0c459759SDelphine CC Chiu 		if (ret < 0)
147*0c459759SDelphine CC Chiu 			return dev_err_probe(&client->dev, ret,
148*0c459759SDelphine CC Chiu 					     "Failed to set vrange\n");
149*0c459759SDelphine CC Chiu 	}
150*0c459759SDelphine CC Chiu 
151*0c459759SDelphine CC Chiu 	info->m[PSC_CURRENT_OUT] = 1024 * rsense;
152*0c459759SDelphine CC Chiu 
153*0c459759SDelphine CC Chiu 	return pmbus_do_probe(client, info);
154*0c459759SDelphine CC Chiu }
155*0c459759SDelphine CC Chiu 
156*0c459759SDelphine CC Chiu static const struct of_device_id ltc4286_of_match[] = {
157*0c459759SDelphine CC Chiu 	{ .compatible = "lltc,ltc4286" },
158*0c459759SDelphine CC Chiu 	{ .compatible = "lltc,ltc4287" },
159*0c459759SDelphine CC Chiu 	{}
160*0c459759SDelphine CC Chiu };
161*0c459759SDelphine CC Chiu 
162*0c459759SDelphine CC Chiu static struct i2c_driver ltc4286_driver = {
163*0c459759SDelphine CC Chiu 	.driver = {
164*0c459759SDelphine CC Chiu 		.name = "ltc4286",
165*0c459759SDelphine CC Chiu 		.of_match_table = ltc4286_of_match,
166*0c459759SDelphine CC Chiu 	},
167*0c459759SDelphine CC Chiu 	.probe = ltc4286_probe,
168*0c459759SDelphine CC Chiu 	.id_table = ltc4286_id,
169*0c459759SDelphine CC Chiu };
170*0c459759SDelphine CC Chiu 
171*0c459759SDelphine CC Chiu module_i2c_driver(ltc4286_driver);
172*0c459759SDelphine CC Chiu 
173*0c459759SDelphine CC Chiu MODULE_AUTHOR("Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>");
174*0c459759SDelphine CC Chiu MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles");
175*0c459759SDelphine CC Chiu MODULE_LICENSE("GPL");
176