xref: /linux/drivers/hwmon/pmbus/ina233.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1*b64b6cb1SLeo Yang // SPDX-License-Identifier: GPL-2.0-or-later
2*b64b6cb1SLeo Yang /*
3*b64b6cb1SLeo Yang  * Hardware monitoring driver for ina233
4*b64b6cb1SLeo Yang  *
5*b64b6cb1SLeo Yang  * Copyright (c) 2025 Leo Yang
6*b64b6cb1SLeo Yang  */
7*b64b6cb1SLeo Yang 
8*b64b6cb1SLeo Yang #include <linux/err.h>
9*b64b6cb1SLeo Yang #include <linux/i2c.h>
10*b64b6cb1SLeo Yang #include <linux/init.h>
11*b64b6cb1SLeo Yang #include <linux/kernel.h>
12*b64b6cb1SLeo Yang #include <linux/module.h>
13*b64b6cb1SLeo Yang #include "pmbus.h"
14*b64b6cb1SLeo Yang 
15*b64b6cb1SLeo Yang #define MFR_READ_VSHUNT 0xd1
16*b64b6cb1SLeo Yang #define MFR_CALIBRATION 0xd4
17*b64b6cb1SLeo Yang 
18*b64b6cb1SLeo Yang #define INA233_MAX_CURRENT_DEFAULT	32768000 /* uA */
19*b64b6cb1SLeo Yang #define INA233_RSHUNT_DEFAULT		2000 /* uOhm */
20*b64b6cb1SLeo Yang 
21*b64b6cb1SLeo Yang #define MAX_M_VAL 32767
22*b64b6cb1SLeo Yang 
23*b64b6cb1SLeo Yang static void calculate_coef(int *m, int *R, u32 current_lsb, int power_coef)
24*b64b6cb1SLeo Yang {
25*b64b6cb1SLeo Yang 	u64 scaled_m;
26*b64b6cb1SLeo Yang 	int scale_factor = 0;
27*b64b6cb1SLeo Yang 	int scale_coef = 1;
28*b64b6cb1SLeo Yang 
29*b64b6cb1SLeo Yang 	/*
30*b64b6cb1SLeo Yang 	 * 1000000 from Current_LSB A->uA .
31*b64b6cb1SLeo Yang 	 * scale_coef is for scaling up to minimize rounding errors,
32*b64b6cb1SLeo Yang 	 * If there is no decimal information, no need to scale.
33*b64b6cb1SLeo Yang 	 */
34*b64b6cb1SLeo Yang 	if (1000000 % current_lsb) {
35*b64b6cb1SLeo Yang 		/* Scaling to keep integer precision */
36*b64b6cb1SLeo Yang 		scale_factor = -3;
37*b64b6cb1SLeo Yang 		scale_coef = 1000;
38*b64b6cb1SLeo Yang 	}
39*b64b6cb1SLeo Yang 
40*b64b6cb1SLeo Yang 	/*
41*b64b6cb1SLeo Yang 	 * Unit Conversion (Current_LSB A->uA) and use scaling(scale_factor)
42*b64b6cb1SLeo Yang 	 * to keep integer precision.
43*b64b6cb1SLeo Yang 	 * Formulae referenced from spec.
44*b64b6cb1SLeo Yang 	 */
45*b64b6cb1SLeo Yang 	scaled_m = div64_u64(1000000 * scale_coef, (u64)current_lsb * power_coef);
46*b64b6cb1SLeo Yang 
47*b64b6cb1SLeo Yang 	/* Maximize while keeping it bounded.*/
48*b64b6cb1SLeo Yang 	while (scaled_m > MAX_M_VAL) {
49*b64b6cb1SLeo Yang 		scaled_m = div_u64(scaled_m, 10);
50*b64b6cb1SLeo Yang 		scale_factor++;
51*b64b6cb1SLeo Yang 	}
52*b64b6cb1SLeo Yang 	/* Scale up only if fractional part exists. */
53*b64b6cb1SLeo Yang 	while (scaled_m * 10 < MAX_M_VAL && scale_coef != 1) {
54*b64b6cb1SLeo Yang 		scaled_m *= 10;
55*b64b6cb1SLeo Yang 		scale_factor--;
56*b64b6cb1SLeo Yang 	}
57*b64b6cb1SLeo Yang 
58*b64b6cb1SLeo Yang 	*m = scaled_m;
59*b64b6cb1SLeo Yang 	*R = scale_factor;
60*b64b6cb1SLeo Yang }
61*b64b6cb1SLeo Yang 
62*b64b6cb1SLeo Yang static int ina233_read_word_data(struct i2c_client *client, int page,
63*b64b6cb1SLeo Yang 				 int phase, int reg)
64*b64b6cb1SLeo Yang {
65*b64b6cb1SLeo Yang 	int ret;
66*b64b6cb1SLeo Yang 
67*b64b6cb1SLeo Yang 	switch (reg) {
68*b64b6cb1SLeo Yang 	case PMBUS_VIRT_READ_VMON:
69*b64b6cb1SLeo Yang 		ret = pmbus_read_word_data(client, 0, 0xff, MFR_READ_VSHUNT);
70*b64b6cb1SLeo Yang 
71*b64b6cb1SLeo Yang 		/* Adjust returned value to match VIN coefficients */
72*b64b6cb1SLeo Yang 		/* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
73*b64b6cb1SLeo Yang 		ret = DIV_ROUND_CLOSEST(ret * 25, 12500);
74*b64b6cb1SLeo Yang 		break;
75*b64b6cb1SLeo Yang 	default:
76*b64b6cb1SLeo Yang 		ret = -ENODATA;
77*b64b6cb1SLeo Yang 		break;
78*b64b6cb1SLeo Yang 	}
79*b64b6cb1SLeo Yang 	return ret;
80*b64b6cb1SLeo Yang }
81*b64b6cb1SLeo Yang 
82*b64b6cb1SLeo Yang static int ina233_probe(struct i2c_client *client)
83*b64b6cb1SLeo Yang {
84*b64b6cb1SLeo Yang 	struct device *dev = &client->dev;
85*b64b6cb1SLeo Yang 	int ret, m, R;
86*b64b6cb1SLeo Yang 	u32 rshunt;
87*b64b6cb1SLeo Yang 	u32 max_current;
88*b64b6cb1SLeo Yang 	u32 current_lsb;
89*b64b6cb1SLeo Yang 	u16 calibration;
90*b64b6cb1SLeo Yang 	struct pmbus_driver_info *info;
91*b64b6cb1SLeo Yang 
92*b64b6cb1SLeo Yang 	info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info),
93*b64b6cb1SLeo Yang 			    GFP_KERNEL);
94*b64b6cb1SLeo Yang 	if (!info)
95*b64b6cb1SLeo Yang 		return -ENOMEM;
96*b64b6cb1SLeo Yang 
97*b64b6cb1SLeo Yang 	info->pages = 1;
98*b64b6cb1SLeo Yang 	info->format[PSC_VOLTAGE_IN] = direct;
99*b64b6cb1SLeo Yang 	info->format[PSC_VOLTAGE_OUT] = direct;
100*b64b6cb1SLeo Yang 	info->format[PSC_CURRENT_OUT] = direct;
101*b64b6cb1SLeo Yang 	info->format[PSC_POWER] = direct;
102*b64b6cb1SLeo Yang 	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_INPUT
103*b64b6cb1SLeo Yang 		| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
104*b64b6cb1SLeo Yang 		| PMBUS_HAVE_POUT
105*b64b6cb1SLeo Yang 		| PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
106*b64b6cb1SLeo Yang 	info->m[PSC_VOLTAGE_IN] = 8;
107*b64b6cb1SLeo Yang 	info->R[PSC_VOLTAGE_IN] = 2;
108*b64b6cb1SLeo Yang 	info->m[PSC_VOLTAGE_OUT] = 8;
109*b64b6cb1SLeo Yang 	info->R[PSC_VOLTAGE_OUT] = 2;
110*b64b6cb1SLeo Yang 	info->read_word_data = ina233_read_word_data;
111*b64b6cb1SLeo Yang 
112*b64b6cb1SLeo Yang 	/* If INA233 skips current/power, shunt-resistor and current-lsb aren't needed.	*/
113*b64b6cb1SLeo Yang 	/* read rshunt value (uOhm) */
114*b64b6cb1SLeo Yang 	ret = device_property_read_u32(dev, "shunt-resistor", &rshunt);
115*b64b6cb1SLeo Yang 	if (ret) {
116*b64b6cb1SLeo Yang 		if (ret != -EINVAL)
117*b64b6cb1SLeo Yang 			return dev_err_probe(dev, ret, "Shunt resistor property read fail.\n");
118*b64b6cb1SLeo Yang 		rshunt = INA233_RSHUNT_DEFAULT;
119*b64b6cb1SLeo Yang 	}
120*b64b6cb1SLeo Yang 	if (!rshunt)
121*b64b6cb1SLeo Yang 		return dev_err_probe(dev, -EINVAL,
122*b64b6cb1SLeo Yang 				     "Shunt resistor cannot be zero.\n");
123*b64b6cb1SLeo Yang 
124*b64b6cb1SLeo Yang 	/* read Maximum expected current value (uA) */
125*b64b6cb1SLeo Yang 	ret = device_property_read_u32(dev, "ti,maximum-expected-current-microamp", &max_current);
126*b64b6cb1SLeo Yang 	if (ret) {
127*b64b6cb1SLeo Yang 		if (ret != -EINVAL)
128*b64b6cb1SLeo Yang 			return dev_err_probe(dev, ret,
129*b64b6cb1SLeo Yang 					     "Maximum expected current property read fail.\n");
130*b64b6cb1SLeo Yang 		max_current = INA233_MAX_CURRENT_DEFAULT;
131*b64b6cb1SLeo Yang 	}
132*b64b6cb1SLeo Yang 	if (max_current < 32768)
133*b64b6cb1SLeo Yang 		return dev_err_probe(dev, -EINVAL,
134*b64b6cb1SLeo Yang 				     "Maximum expected current cannot less then 32768.\n");
135*b64b6cb1SLeo Yang 
136*b64b6cb1SLeo Yang 	/* Calculate Current_LSB according to the spec formula */
137*b64b6cb1SLeo Yang 	current_lsb = max_current / 32768;
138*b64b6cb1SLeo Yang 
139*b64b6cb1SLeo Yang 	/* calculate current coefficient */
140*b64b6cb1SLeo Yang 	calculate_coef(&m, &R, current_lsb, 1);
141*b64b6cb1SLeo Yang 	info->m[PSC_CURRENT_OUT] = m;
142*b64b6cb1SLeo Yang 	info->R[PSC_CURRENT_OUT] = R;
143*b64b6cb1SLeo Yang 
144*b64b6cb1SLeo Yang 	/* calculate power coefficient */
145*b64b6cb1SLeo Yang 	calculate_coef(&m, &R, current_lsb, 25);
146*b64b6cb1SLeo Yang 	info->m[PSC_POWER] = m;
147*b64b6cb1SLeo Yang 	info->R[PSC_POWER] = R;
148*b64b6cb1SLeo Yang 
149*b64b6cb1SLeo Yang 	/* write MFR_CALIBRATION register, Apply formula from spec with unit scaling. */
150*b64b6cb1SLeo Yang 	calibration = div64_u64(5120000000ULL, (u64)rshunt * current_lsb);
151*b64b6cb1SLeo Yang 	if (calibration > 0x7FFF)
152*b64b6cb1SLeo Yang 		return dev_err_probe(dev, -EINVAL,
153*b64b6cb1SLeo Yang 				     "Product of Current_LSB %u and shunt resistor %u too small, MFR_CALIBRATION reg exceeds 0x7FFF.\n",
154*b64b6cb1SLeo Yang 				     current_lsb, rshunt);
155*b64b6cb1SLeo Yang 	ret = i2c_smbus_write_word_data(client, MFR_CALIBRATION, calibration);
156*b64b6cb1SLeo Yang 	if (ret < 0)
157*b64b6cb1SLeo Yang 		return dev_err_probe(dev, ret, "Unable to write calibration.\n");
158*b64b6cb1SLeo Yang 
159*b64b6cb1SLeo Yang 	dev_dbg(dev, "power monitor %s (Rshunt = %u uOhm, Current_LSB = %u uA/bit)\n",
160*b64b6cb1SLeo Yang 		client->name, rshunt, current_lsb);
161*b64b6cb1SLeo Yang 
162*b64b6cb1SLeo Yang 	return pmbus_do_probe(client, info);
163*b64b6cb1SLeo Yang }
164*b64b6cb1SLeo Yang 
165*b64b6cb1SLeo Yang static const struct i2c_device_id ina233_id[] = {
166*b64b6cb1SLeo Yang 	{"ina233", 0},
167*b64b6cb1SLeo Yang 	{}
168*b64b6cb1SLeo Yang };
169*b64b6cb1SLeo Yang MODULE_DEVICE_TABLE(i2c, ina233_id);
170*b64b6cb1SLeo Yang 
171*b64b6cb1SLeo Yang static const struct of_device_id __maybe_unused ina233_of_match[] = {
172*b64b6cb1SLeo Yang 	{ .compatible = "ti,ina233" },
173*b64b6cb1SLeo Yang 	{}
174*b64b6cb1SLeo Yang };
175*b64b6cb1SLeo Yang MODULE_DEVICE_TABLE(of, ina233_of_match);
176*b64b6cb1SLeo Yang 
177*b64b6cb1SLeo Yang static struct i2c_driver ina233_driver = {
178*b64b6cb1SLeo Yang 	.driver = {
179*b64b6cb1SLeo Yang 		   .name = "ina233",
180*b64b6cb1SLeo Yang 		   .of_match_table = of_match_ptr(ina233_of_match),
181*b64b6cb1SLeo Yang 	},
182*b64b6cb1SLeo Yang 	.probe = ina233_probe,
183*b64b6cb1SLeo Yang 	.id_table = ina233_id,
184*b64b6cb1SLeo Yang };
185*b64b6cb1SLeo Yang 
186*b64b6cb1SLeo Yang module_i2c_driver(ina233_driver);
187*b64b6cb1SLeo Yang 
188*b64b6cb1SLeo Yang MODULE_AUTHOR("Leo Yang <leo.yang.sy0@gmail.com>");
189*b64b6cb1SLeo Yang MODULE_DESCRIPTION("PMBus driver for INA233 and compatible chips");
190*b64b6cb1SLeo Yang MODULE_LICENSE("GPL");
191*b64b6cb1SLeo Yang MODULE_IMPORT_NS("PMBUS");
192