1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers
5 * Copyright (c) 2020 Mellanox Technologies. All rights reserved.
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
15 #define XDPE122_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
16 #define XDPE122_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
17 #define XDPE122_PROT_IMVP9_10MV 0x03 /* IMVP9 mode, 10-mV DAC */
18 #define XDPE122_AMD_625MV 0x10 /* AMD mode 6.25mV */
19 #define XDPE122_PAGE_NUM 2
21 static int xdpe122_read_word_data(struct i2c_client
*client
, int page
,
24 const struct pmbus_driver_info
*info
= pmbus_get_driver_info(client
);
31 case PMBUS_VOUT_OV_FAULT_LIMIT
:
32 case PMBUS_VOUT_UV_FAULT_LIMIT
:
33 ret
= pmbus_read_word_data(client
, page
, phase
, reg
);
37 /* Convert register value to LINEAR11 data. */
38 exponent
= ((s16
)ret
) >> 11;
39 mantissa
= ((s16
)((ret
& GENMASK(10, 0)) << 5)) >> 5;
40 val
= mantissa
* 1000L;
46 /* Convert data to VID register. */
47 switch (info
->vrm_version
[page
]) {
50 return 1 + DIV_ROUND_CLOSEST(val
- 500, 10);
54 return 1 + DIV_ROUND_CLOSEST(val
- 250, 5);
58 return 1 + DIV_ROUND_CLOSEST(val
- 200, 10);
61 if (val
>= 200 && val
<= 1550)
62 return DIV_ROUND_CLOSEST((1550 - val
) * 100,
75 static int xdpe122_identify(struct i2c_client
*client
,
76 struct pmbus_driver_info
*info
)
81 for (i
= 0; i
< XDPE122_PAGE_NUM
; i
++) {
82 /* Read the register with VOUT scaling value.*/
83 ret
= pmbus_read_byte_data(client
, i
, PMBUS_VOUT_MODE
);
87 vout_params
= ret
& GENMASK(4, 0);
89 switch (vout_params
) {
90 case XDPE122_PROT_VR12_5_10MV
:
91 info
->vrm_version
[i
] = vr13
;
93 case XDPE122_PROT_VR12_5MV
:
94 info
->vrm_version
[i
] = vr12
;
96 case XDPE122_PROT_IMVP9_10MV
:
97 info
->vrm_version
[i
] = imvp9
;
99 case XDPE122_AMD_625MV
:
100 info
->vrm_version
[i
] = amd625mv
;
110 static struct pmbus_driver_info xdpe122_info
= {
111 .pages
= XDPE122_PAGE_NUM
,
112 .format
[PSC_VOLTAGE_IN
] = linear
,
113 .format
[PSC_VOLTAGE_OUT
] = vid
,
114 .format
[PSC_TEMPERATURE
] = linear
,
115 .format
[PSC_CURRENT_IN
] = linear
,
116 .format
[PSC_CURRENT_OUT
] = linear
,
117 .format
[PSC_POWER
] = linear
,
118 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT
|
119 PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT
| PMBUS_HAVE_STATUS_IOUT
|
120 PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_TEMP
|
121 PMBUS_HAVE_POUT
| PMBUS_HAVE_PIN
| PMBUS_HAVE_STATUS_INPUT
,
122 .func
[1] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT
|
123 PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT
| PMBUS_HAVE_STATUS_IOUT
|
124 PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_TEMP
|
125 PMBUS_HAVE_POUT
| PMBUS_HAVE_PIN
| PMBUS_HAVE_STATUS_INPUT
,
126 .identify
= xdpe122_identify
,
127 .read_word_data
= xdpe122_read_word_data
,
130 static int xdpe122_probe(struct i2c_client
*client
)
132 struct pmbus_driver_info
*info
;
134 info
= devm_kmemdup(&client
->dev
, &xdpe122_info
, sizeof(*info
),
139 return pmbus_do_probe(client
, info
);
142 static const struct i2c_device_id xdpe122_id
[] = {
148 MODULE_DEVICE_TABLE(i2c
, xdpe122_id
);
150 static const struct of_device_id __maybe_unused xdpe122_of_match
[] = {
151 {.compatible
= "infineon,xdpe12254"},
152 {.compatible
= "infineon,xdpe12284"},
155 MODULE_DEVICE_TABLE(of
, xdpe122_of_match
);
157 static struct i2c_driver xdpe122_driver
= {
160 .of_match_table
= of_match_ptr(xdpe122_of_match
),
162 .probe_new
= xdpe122_probe
,
163 .id_table
= xdpe122_id
,
166 module_i2c_driver(xdpe122_driver
);
168 MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
169 MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family");
170 MODULE_LICENSE("GPL");