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