summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pmbus/xdpe1a2g7b.c
blob: 9455ef443b2b35c6f7617fc9489a9af24f513e77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: GPL-2.0+
/*
 * Hardware monitoring driver for Infineon Multi-phase Digital XDPE1A2G5B
 * and XDPE1A2G7B Controllers
 *
 * Copyright (c) 2026 Infineon Technologies. All rights reserved.
 */

#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"

#define XDPE1A2G7B_PAGE_NUM 2
#define XDPE1A2G7B_NVIDIA_195MV 0x1E /* NVIDIA mode 1.95mV, VID step is 5mV */

static int xdpe1a2g7b_identify(struct i2c_client *client,
			       struct pmbus_driver_info *info)
{
	u8 vout_params;
	int vout_mode;

	/*
	 * XDPE1A2G5B and XDPE1A2G7B support both Linear and NVIDIA PWM VID data
	 * formats via VOUT_MODE. Note that the device pages/loops are not fully
	 * independent: configuration is shared, so programming each page/loop
	 * separately is not supported.
	 */
	vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
	if (vout_mode < 0)
		return vout_mode;

	switch (vout_mode >> 5) {
	case 0:
		info->format[PSC_VOLTAGE_OUT] = linear;
		return 0;
	case 1:
		info->format[PSC_VOLTAGE_OUT] = vid;
		vout_params = vout_mode & GENMASK(4, 0);
		/* Check for VID Code Type */
		switch (vout_params) {
		case XDPE1A2G7B_NVIDIA_195MV:
			/* VID vrm_version for PAGE0 and PAGE1 */
			info->vrm_version[0] = nvidia195mv;
			info->vrm_version[1] = nvidia195mv;
			break;
		default:
			return -EINVAL;
		}
		break;
	default:
		return -ENODEV;
	}

	return 0;
}

#if IS_ENABLED(CONFIG_SENSORS_XDPE1A2G7B_REGULATOR)
static const struct regulator_desc xdpe1a2g7b_reg_desc[] = {
	PMBUS_REGULATOR("vout", 0),
	PMBUS_REGULATOR("vout", 1),
};
#endif

static struct pmbus_driver_info xdpe1a2g7b_info = {
	.pages = XDPE1A2G7B_PAGE_NUM,
	.identify = xdpe1a2g7b_identify,
	.format[PSC_VOLTAGE_IN] = linear,
	.format[PSC_TEMPERATURE] = linear,
	.format[PSC_CURRENT_IN] = linear,
	.format[PSC_CURRENT_OUT] = linear,
	.format[PSC_POWER] = linear,
	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
		   PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
		   PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP |
		   PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
	.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
		   PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
		   PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_STATUS_INPUT,
#if IS_ENABLED(CONFIG_SENSORS_XDPE1A2G7B_REGULATOR)
	.num_regulators = XDPE1A2G7B_PAGE_NUM,
	.reg_desc = xdpe1a2g7b_reg_desc,
#endif
};

static int xdpe1a2g7b_probe(struct i2c_client *client)
{
	struct pmbus_driver_info *info;

	info = devm_kmemdup(&client->dev, &xdpe1a2g7b_info, sizeof(*info),
			    GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	return pmbus_do_probe(client, info);
}

static const struct i2c_device_id xdpe1a2g7b_id[] = {
	{ .name = "xdpe1a2g5b" },
	{ .name = "xdpe1a2g7b" },
	{ }
};

MODULE_DEVICE_TABLE(i2c, xdpe1a2g7b_id);

static const struct of_device_id __maybe_unused xdpe1a2g7b_of_match[] = {
	{ .compatible = "infineon,xdpe1a2g5b" },
	{ .compatible = "infineon,xdpe1a2g7b" },
	{}
};

MODULE_DEVICE_TABLE(of, xdpe1a2g7b_of_match);

static struct i2c_driver xdpe1a2g7b_driver = {
	.driver = {
		.name = "xdpe1a2g7b",
		.of_match_table = of_match_ptr(xdpe1a2g7b_of_match),
	},
	.probe = xdpe1a2g7b_probe,
	.id_table = xdpe1a2g7b_id,
};

module_i2c_driver(xdpe1a2g7b_driver);

MODULE_AUTHOR("Ashish Yadav <ashish.yadav@infineon.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon XDPE1A2G5B/7B");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("PMBUS");