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