135fe06d9SPeter Yin // SPDX-License-Identifier: GPL-2.0-or-later
235fe06d9SPeter Yin /*
335fe06d9SPeter Yin * Driver for Infineon XDP710 Hot-Swap Controller
435fe06d9SPeter Yin */
535fe06d9SPeter Yin
635fe06d9SPeter Yin #include <linux/bitops.h>
735fe06d9SPeter Yin #include <linux/i2c.h>
835fe06d9SPeter Yin #include <linux/module.h>
935fe06d9SPeter Yin #include <linux/of_device.h>
1035fe06d9SPeter Yin #include "pmbus.h"
1135fe06d9SPeter Yin
1235fe06d9SPeter Yin #define XDP710_REG_CFG 0xD3
1335fe06d9SPeter Yin #define XDP710_V_SNS_CFG 0xD4
1435fe06d9SPeter Yin #define XDP710_CS_RNG 0xD5
1535fe06d9SPeter Yin
1635fe06d9SPeter Yin /*
1735fe06d9SPeter Yin * The table to map configuration register values
1835fe06d9SPeter Yin * to sense resistor values
1935fe06d9SPeter Yin */
2035fe06d9SPeter Yin static const int micro_ohm_rsense[] = {
2135fe06d9SPeter Yin 200, 250, 300, 330, 400, 470, 500, 600,
2235fe06d9SPeter Yin 670, 700, 750, 800, 900, 1000, 1100, 1200,
2335fe06d9SPeter Yin 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900,
2435fe06d9SPeter Yin 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
2535fe06d9SPeter Yin 2800, 3000, 3100, 3200, 3300, 3400, 3500, 3600,
2635fe06d9SPeter Yin 3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400,
2735fe06d9SPeter Yin 4500, 4600, 4700, 4800, 4900, 5000, 5500, 6000,
2835fe06d9SPeter Yin 6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000
2935fe06d9SPeter Yin };
3035fe06d9SPeter Yin
3135fe06d9SPeter Yin static struct pmbus_driver_info xdp710_info = {
3235fe06d9SPeter Yin .pages = 1,
3335fe06d9SPeter Yin .format[PSC_VOLTAGE_IN] = direct,
3435fe06d9SPeter Yin .format[PSC_VOLTAGE_OUT] = direct,
3535fe06d9SPeter Yin .format[PSC_CURRENT_OUT] = direct,
3635fe06d9SPeter Yin .format[PSC_POWER] = direct,
3735fe06d9SPeter Yin .format[PSC_TEMPERATURE] = direct,
3835fe06d9SPeter Yin .m[PSC_VOLTAGE_IN] = 4653,
3935fe06d9SPeter Yin .b[PSC_VOLTAGE_IN] = 0,
4035fe06d9SPeter Yin .R[PSC_VOLTAGE_IN] = -2,
4135fe06d9SPeter Yin .m[PSC_VOLTAGE_OUT] = 4653,
4235fe06d9SPeter Yin .b[PSC_VOLTAGE_OUT] = 0,
4335fe06d9SPeter Yin .R[PSC_VOLTAGE_OUT] = -2,
4435fe06d9SPeter Yin .m[PSC_CURRENT_OUT] = 23165,
4535fe06d9SPeter Yin .b[PSC_CURRENT_OUT] = 0,
4635fe06d9SPeter Yin .R[PSC_CURRENT_OUT] = -2,
4735fe06d9SPeter Yin .m[PSC_POWER] = 4211,
4835fe06d9SPeter Yin .b[PSC_POWER] = 0,
4935fe06d9SPeter Yin .R[PSC_POWER] = -2,
5035fe06d9SPeter Yin .m[PSC_TEMPERATURE] = 52,
5135fe06d9SPeter Yin .b[PSC_TEMPERATURE] = 14321,
5235fe06d9SPeter Yin .R[PSC_TEMPERATURE] = -1,
5335fe06d9SPeter Yin .func[0] =
5435fe06d9SPeter Yin PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_PIN |
5535fe06d9SPeter Yin PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT |
5635fe06d9SPeter Yin PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
5735fe06d9SPeter Yin };
5835fe06d9SPeter Yin
xdp710_probe(struct i2c_client * client)5935fe06d9SPeter Yin static int xdp710_probe(struct i2c_client *client)
6035fe06d9SPeter Yin {
6135fe06d9SPeter Yin struct pmbus_driver_info *info;
6235fe06d9SPeter Yin u8 cs_rng;
6335fe06d9SPeter Yin u8 vtlm_rng;
6435fe06d9SPeter Yin int rsense;
6535fe06d9SPeter Yin int ret;
6635fe06d9SPeter Yin int m = 0;
6735fe06d9SPeter Yin
6835fe06d9SPeter Yin info = devm_kmemdup(&client->dev, &xdp710_info, sizeof(*info),
6935fe06d9SPeter Yin GFP_KERNEL);
7035fe06d9SPeter Yin if (!info)
7135fe06d9SPeter Yin return -ENOMEM;
7235fe06d9SPeter Yin
7335fe06d9SPeter Yin ret = i2c_smbus_read_word_data(client, XDP710_CS_RNG);
7435fe06d9SPeter Yin if (ret < 0) {
7535fe06d9SPeter Yin dev_err(&client->dev, "Can't get CS_RNG");
7635fe06d9SPeter Yin return ret;
7735fe06d9SPeter Yin }
7835fe06d9SPeter Yin cs_rng = (ret >> 6) & GENMASK(1, 0);
7935fe06d9SPeter Yin
8035fe06d9SPeter Yin ret = i2c_smbus_read_word_data(client, XDP710_V_SNS_CFG);
8135fe06d9SPeter Yin if (ret < 0) {
8235fe06d9SPeter Yin dev_err(&client->dev, "Can't get V_SNS_CFG");
8335fe06d9SPeter Yin return ret;
8435fe06d9SPeter Yin }
8535fe06d9SPeter Yin vtlm_rng = ret & GENMASK(1, 0);
8635fe06d9SPeter Yin
8735fe06d9SPeter Yin ret = i2c_smbus_read_word_data(client, XDP710_REG_CFG);
8835fe06d9SPeter Yin if (ret < 0) {
8935fe06d9SPeter Yin dev_err(&client->dev, "Can't get REG_CFG");
9035fe06d9SPeter Yin return ret;
9135fe06d9SPeter Yin }
9235fe06d9SPeter Yin ret &= GENMASK(5, 0);
9335fe06d9SPeter Yin rsense = micro_ohm_rsense[ret];
9435fe06d9SPeter Yin
9535fe06d9SPeter Yin info->m[PSC_VOLTAGE_IN] <<= vtlm_rng;
9635fe06d9SPeter Yin info->m[PSC_VOLTAGE_OUT] <<= vtlm_rng;
9735fe06d9SPeter Yin
9835fe06d9SPeter Yin m = info->m[PSC_CURRENT_OUT];
9935fe06d9SPeter Yin info->m[PSC_CURRENT_OUT] = DIV_ROUND_CLOSEST(m * rsense >> cs_rng, 1000);
10035fe06d9SPeter Yin
10135fe06d9SPeter Yin m = info->m[PSC_POWER];
10235fe06d9SPeter Yin info->m[PSC_POWER] = DIV_ROUND_CLOSEST(m * rsense >> cs_rng, 1000);
10335fe06d9SPeter Yin
10435fe06d9SPeter Yin return pmbus_do_probe(client, info);
10535fe06d9SPeter Yin }
10635fe06d9SPeter Yin
10735fe06d9SPeter Yin static const struct of_device_id xdp710_of_match[] = {
10835fe06d9SPeter Yin { .compatible = "infineon,xdp710" },
10935fe06d9SPeter Yin {}
11035fe06d9SPeter Yin };
11135fe06d9SPeter Yin
11235fe06d9SPeter Yin static const struct i2c_device_id xdp710_id[] = {
113*d8a66f36SUwe Kleine-König {"xdp710"},
11435fe06d9SPeter Yin { }
11535fe06d9SPeter Yin };
11635fe06d9SPeter Yin MODULE_DEVICE_TABLE(i2c, xdp710_id);
11735fe06d9SPeter Yin
11835fe06d9SPeter Yin static struct i2c_driver xdp710_driver = {
11935fe06d9SPeter Yin .driver = {
12035fe06d9SPeter Yin .name = "xdp710",
12135fe06d9SPeter Yin .of_match_table = xdp710_of_match,
12235fe06d9SPeter Yin },
12335fe06d9SPeter Yin .probe = xdp710_probe,
12435fe06d9SPeter Yin .id_table = xdp710_id,
12535fe06d9SPeter Yin };
12635fe06d9SPeter Yin module_i2c_driver(xdp710_driver);
12735fe06d9SPeter Yin
12835fe06d9SPeter Yin MODULE_AUTHOR("Peter Yin <peter.yin@quantatw.com>");
12935fe06d9SPeter Yin MODULE_DESCRIPTION("PMBus driver for XDP710 HSC");
13035fe06d9SPeter Yin MODULE_LICENSE("GPL");
13135fe06d9SPeter Yin MODULE_IMPORT_NS(PMBUS);
132