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