xref: /linux/drivers/hwmon/pmbus/xdp720.c (revision 46576fa32908043975471bd26fe833a7d8015b35)
1*a0c370a6SAshish Yadav // SPDX-License-Identifier: GPL-2.0+
2*a0c370a6SAshish Yadav /*
3*a0c370a6SAshish Yadav  * Hardware monitoring driver for Infineon XDP720 Digital eFuse Controller
4*a0c370a6SAshish Yadav  *
5*a0c370a6SAshish Yadav  * Copyright (c) 2026 Infineon Technologies. All rights reserved.
6*a0c370a6SAshish Yadav  */
7*a0c370a6SAshish Yadav 
8*a0c370a6SAshish Yadav #include <linux/i2c.h>
9*a0c370a6SAshish Yadav #include <linux/module.h>
10*a0c370a6SAshish Yadav #include <linux/init.h>
11*a0c370a6SAshish Yadav #include <linux/kernel.h>
12*a0c370a6SAshish Yadav #include <linux/of_device.h>
13*a0c370a6SAshish Yadav #include <linux/bitops.h>
14*a0c370a6SAshish Yadav #include <linux/math64.h>
15*a0c370a6SAshish Yadav #include "pmbus.h"
16*a0c370a6SAshish Yadav 
17*a0c370a6SAshish Yadav /*
18*a0c370a6SAshish Yadav  * The IMON resistor required to generate the system overcurrent protection.
19*a0c370a6SAshish Yadav  * Arbitrary default Rimon value: 2k Ohm
20*a0c370a6SAshish Yadav  */
21*a0c370a6SAshish Yadav #define XDP720_DEFAULT_RIMON 2000000000 /* 2k ohm */
22*a0c370a6SAshish Yadav #define XDP720_TELEMETRY_AVG 0xE9
23*a0c370a6SAshish Yadav 
24*a0c370a6SAshish Yadav static struct pmbus_driver_info xdp720_info = {
25*a0c370a6SAshish Yadav 	.pages = 1,
26*a0c370a6SAshish Yadav 	.format[PSC_VOLTAGE_IN] = direct,
27*a0c370a6SAshish Yadav 	.format[PSC_VOLTAGE_OUT] = direct,
28*a0c370a6SAshish Yadav 	.format[PSC_CURRENT_OUT] = direct,
29*a0c370a6SAshish Yadav 	.format[PSC_POWER] = direct,
30*a0c370a6SAshish Yadav 	.format[PSC_TEMPERATURE] = direct,
31*a0c370a6SAshish Yadav 
32*a0c370a6SAshish Yadav 	.m[PSC_VOLTAGE_IN] = 4653,
33*a0c370a6SAshish Yadav 	.b[PSC_VOLTAGE_IN] = 0,
34*a0c370a6SAshish Yadav 	.R[PSC_VOLTAGE_IN] = -2,
35*a0c370a6SAshish Yadav 	.m[PSC_VOLTAGE_OUT] = 4653,
36*a0c370a6SAshish Yadav 	.b[PSC_VOLTAGE_OUT] = 0,
37*a0c370a6SAshish Yadav 	.R[PSC_VOLTAGE_OUT] = -2,
38*a0c370a6SAshish Yadav 	/*
39*a0c370a6SAshish Yadav 	 * Current and Power measurement depends on the RIMON (kOhm) and
40*a0c370a6SAshish Yadav 	 * GIMON(microA/A) values.
41*a0c370a6SAshish Yadav 	 */
42*a0c370a6SAshish Yadav 	.m[PSC_CURRENT_OUT] = 24668,
43*a0c370a6SAshish Yadav 	.b[PSC_CURRENT_OUT] = 0,
44*a0c370a6SAshish Yadav 	.R[PSC_CURRENT_OUT] = -4,
45*a0c370a6SAshish Yadav 	.m[PSC_POWER] = 4486,
46*a0c370a6SAshish Yadav 	.b[PSC_POWER] = 0,
47*a0c370a6SAshish Yadav 	.R[PSC_POWER] = -1,
48*a0c370a6SAshish Yadav 	.m[PSC_TEMPERATURE] = 54,
49*a0c370a6SAshish Yadav 	.b[PSC_TEMPERATURE] = 22521,
50*a0c370a6SAshish Yadav 	.R[PSC_TEMPERATURE] = -1,
51*a0c370a6SAshish Yadav 
52*a0c370a6SAshish Yadav 	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_PIN |
53*a0c370a6SAshish Yadav 		   PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_INPUT |
54*a0c370a6SAshish Yadav 		   PMBUS_HAVE_STATUS_TEMP,
55*a0c370a6SAshish Yadav };
56*a0c370a6SAshish Yadav 
57*a0c370a6SAshish Yadav static int xdp720_probe(struct i2c_client *client)
58*a0c370a6SAshish Yadav {
59*a0c370a6SAshish Yadav 	struct pmbus_driver_info *info;
60*a0c370a6SAshish Yadav 	int ret;
61*a0c370a6SAshish Yadav 	u32 rimon;
62*a0c370a6SAshish Yadav 	int gimon;
63*a0c370a6SAshish Yadav 
64*a0c370a6SAshish Yadav 	info = devm_kmemdup(&client->dev, &xdp720_info, sizeof(*info),
65*a0c370a6SAshish Yadav 			    GFP_KERNEL);
66*a0c370a6SAshish Yadav 	if (!info)
67*a0c370a6SAshish Yadav 		return -ENOMEM;
68*a0c370a6SAshish Yadav 
69*a0c370a6SAshish Yadav 	ret = devm_regulator_get_enable(&client->dev, "vdd-vin");
70*a0c370a6SAshish Yadav 	if (ret)
71*a0c370a6SAshish Yadav 		return dev_err_probe(&client->dev, ret,
72*a0c370a6SAshish Yadav 			"failed to enable vdd-vin supply\n");
73*a0c370a6SAshish Yadav 
74*a0c370a6SAshish Yadav 	ret = i2c_smbus_read_word_data(client, XDP720_TELEMETRY_AVG);
75*a0c370a6SAshish Yadav 	if (ret < 0) {
76*a0c370a6SAshish Yadav 		dev_err(&client->dev, "Can't get TELEMETRY_AVG\n");
77*a0c370a6SAshish Yadav 		return ret;
78*a0c370a6SAshish Yadav 	}
79*a0c370a6SAshish Yadav 
80*a0c370a6SAshish Yadav 	ret >>= 10; /* 10th bit of TELEMETRY_AVG REG for GIMON Value */
81*a0c370a6SAshish Yadav 	ret &= GENMASK(0, 0);
82*a0c370a6SAshish Yadav 	if (ret == 1)
83*a0c370a6SAshish Yadav 		gimon = 18200; /* output gain 18.2 microA/A */
84*a0c370a6SAshish Yadav 	else
85*a0c370a6SAshish Yadav 		gimon = 9100; /* output gain 9.1 microA/A */
86*a0c370a6SAshish Yadav 
87*a0c370a6SAshish Yadav 	if (of_property_read_u32(client->dev.of_node,
88*a0c370a6SAshish Yadav 				 "infineon,rimon-micro-ohms", &rimon))
89*a0c370a6SAshish Yadav 		rimon = XDP720_DEFAULT_RIMON; /* Default if not set via DT */
90*a0c370a6SAshish Yadav 	if (rimon == 0)
91*a0c370a6SAshish Yadav 		return -EINVAL;
92*a0c370a6SAshish Yadav 
93*a0c370a6SAshish Yadav 	/* Adapt the current and power scale for each instance */
94*a0c370a6SAshish Yadav 	info->m[PSC_CURRENT_OUT] = DIV64_U64_ROUND_CLOSEST((u64)
95*a0c370a6SAshish Yadav 		info->m[PSC_CURRENT_OUT] * rimon * gimon, 1000000000000ULL);
96*a0c370a6SAshish Yadav 	info->m[PSC_POWER] = DIV64_U64_ROUND_CLOSEST((u64)
97*a0c370a6SAshish Yadav 		info->m[PSC_POWER] * rimon * gimon, 1000000000000000ULL);
98*a0c370a6SAshish Yadav 
99*a0c370a6SAshish Yadav 	return pmbus_do_probe(client, info);
100*a0c370a6SAshish Yadav }
101*a0c370a6SAshish Yadav 
102*a0c370a6SAshish Yadav static const struct of_device_id xdp720_of_match[] = {
103*a0c370a6SAshish Yadav 	{ .compatible = "infineon,xdp720" },
104*a0c370a6SAshish Yadav 	{}
105*a0c370a6SAshish Yadav };
106*a0c370a6SAshish Yadav MODULE_DEVICE_TABLE(of, xdp720_of_match);
107*a0c370a6SAshish Yadav 
108*a0c370a6SAshish Yadav static const struct i2c_device_id xdp720_id[] = {
109*a0c370a6SAshish Yadav 	{ "xdp720" },
110*a0c370a6SAshish Yadav 	{}
111*a0c370a6SAshish Yadav };
112*a0c370a6SAshish Yadav MODULE_DEVICE_TABLE(i2c, xdp720_id);
113*a0c370a6SAshish Yadav 
114*a0c370a6SAshish Yadav static struct i2c_driver xdp720_driver = {
115*a0c370a6SAshish Yadav 	.driver = {
116*a0c370a6SAshish Yadav 		   .name = "xdp720",
117*a0c370a6SAshish Yadav 		   .of_match_table = xdp720_of_match,
118*a0c370a6SAshish Yadav 	},
119*a0c370a6SAshish Yadav 	.probe = xdp720_probe,
120*a0c370a6SAshish Yadav 	.id_table = xdp720_id,
121*a0c370a6SAshish Yadav };
122*a0c370a6SAshish Yadav 
123*a0c370a6SAshish Yadav module_i2c_driver(xdp720_driver);
124*a0c370a6SAshish Yadav 
125*a0c370a6SAshish Yadav MODULE_AUTHOR("Ashish Yadav <ashish.yadav@infineon.com>");
126*a0c370a6SAshish Yadav MODULE_DESCRIPTION("PMBus driver for Infineon XDP720 Digital eFuse Controller");
127*a0c370a6SAshish Yadav MODULE_LICENSE("GPL");
128*a0c370a6SAshish Yadav MODULE_IMPORT_NS("PMBUS");
129