1 // SPDX-License-Identifier: GPL-2.0+
3 * Hardware monitoring driver for Analog Devices LT7182S
5 * Copyright (c) 2022 Guenter Roeck
9 #include <linux/bits.h>
10 #include <linux/err.h>
11 #include <linux/i2c.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
18 #define LT7182S_NUM_PAGES 2
20 #define MFR_READ_EXTVCC 0xcd
21 #define MFR_READ_ITH 0xce
22 #define MFR_CONFIG_ALL_LT7182S 0xd1
23 #define MFR_IOUT_PEAK 0xd7
24 #define MFR_ADC_CONTROL_LT7182S 0xd8
26 #define MFR_DEBUG_TELEMETRY BIT(0)
28 #define MFR_VOUT_PEAK 0xdd
29 #define MFR_VIN_PEAK 0xde
30 #define MFR_TEMPERATURE_1_PEAK 0xdf
31 #define MFR_CLEAR_PEAKS 0xe3
33 #define MFR_CONFIG_IEEE BIT(8)
35 static int lt7182s_read_word_data(struct i2c_client
*client
, int page
, int phase
, int reg
)
40 case PMBUS_VIRT_READ_VMON
:
41 if (page
== 0 || page
== 1)
42 ret
= pmbus_read_word_data(client
, page
, phase
, MFR_READ_ITH
);
44 ret
= pmbus_read_word_data(client
, 0, phase
, MFR_READ_EXTVCC
);
46 case PMBUS_VIRT_READ_IOUT_MAX
:
47 ret
= pmbus_read_word_data(client
, page
, phase
, MFR_IOUT_PEAK
);
49 case PMBUS_VIRT_READ_VOUT_MAX
:
50 ret
= pmbus_read_word_data(client
, page
, phase
, MFR_VOUT_PEAK
);
52 case PMBUS_VIRT_READ_VIN_MAX
:
53 ret
= pmbus_read_word_data(client
, page
, phase
, MFR_VIN_PEAK
);
55 case PMBUS_VIRT_READ_TEMP_MAX
:
56 ret
= pmbus_read_word_data(client
, page
, phase
, MFR_TEMPERATURE_1_PEAK
);
58 case PMBUS_VIRT_RESET_VIN_HISTORY
:
59 ret
= (page
== 0) ? 0 : -ENODATA
;
68 static int lt7182s_write_word_data(struct i2c_client
*client
, int page
, int reg
, u16 word
)
73 case PMBUS_VIRT_RESET_VIN_HISTORY
:
74 ret
= pmbus_write_byte(client
, 0, MFR_CLEAR_PEAKS
);
83 static struct pmbus_driver_info lt7182s_info
= {
84 .pages
= LT7182S_NUM_PAGES
,
85 .format
[PSC_VOLTAGE_IN
] = linear
,
86 .format
[PSC_VOLTAGE_OUT
] = linear
,
87 .format
[PSC_CURRENT_IN
] = linear
,
88 .format
[PSC_CURRENT_OUT
] = linear
,
89 .format
[PSC_TEMPERATURE
] = linear
,
90 .format
[PSC_POWER
] = linear
,
91 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
|
92 PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT
| PMBUS_HAVE_POUT
|
93 PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_IOUT
|
94 PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_STATUS_TEMP
,
95 .func
[1] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
|
96 PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT
| PMBUS_HAVE_POUT
|
97 PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_IOUT
|
98 PMBUS_HAVE_STATUS_INPUT
,
99 .read_word_data
= lt7182s_read_word_data
,
100 .write_word_data
= lt7182s_write_word_data
,
103 static int lt7182s_probe(struct i2c_client
*client
)
105 struct device
*dev
= &client
->dev
;
106 struct pmbus_driver_info
*info
;
107 u8 buf
[I2C_SMBUS_BLOCK_MAX
+ 1];
110 if (!i2c_check_functionality(client
->adapter
,
111 I2C_FUNC_SMBUS_READ_BYTE_DATA
|
112 I2C_FUNC_SMBUS_READ_WORD_DATA
|
113 I2C_FUNC_SMBUS_READ_BLOCK_DATA
))
116 ret
= i2c_smbus_read_block_data(client
, PMBUS_MFR_ID
, buf
);
118 dev_err(dev
, "Failed to read PMBUS_MFR_ID\n");
121 if (ret
!= 3 || strncmp(buf
, "ADI", 3)) {
123 dev_err(dev
, "Manufacturer '%s' not supported\n", buf
);
127 ret
= i2c_smbus_read_block_data(client
, PMBUS_MFR_MODEL
, buf
);
129 dev_err(dev
, "Failed to read PMBUS_MFR_MODEL\n");
132 if (ret
!= 7 || strncmp(buf
, "LT7182S", 7)) {
134 dev_err(dev
, "Model '%s' not supported\n", buf
);
138 info
= devm_kmemdup(dev
, <7182s_info
,
139 sizeof(struct pmbus_driver_info
), GFP_KERNEL
);
143 /* Set data format to IEEE754 if configured */
144 ret
= i2c_smbus_read_word_data(client
, MFR_CONFIG_ALL_LT7182S
);
147 if (ret
& MFR_CONFIG_IEEE
) {
148 info
->format
[PSC_VOLTAGE_IN
] = ieee754
;
149 info
->format
[PSC_VOLTAGE_OUT
] = ieee754
;
150 info
->format
[PSC_CURRENT_IN
] = ieee754
;
151 info
->format
[PSC_CURRENT_OUT
] = ieee754
;
152 info
->format
[PSC_TEMPERATURE
] = ieee754
;
153 info
->format
[PSC_POWER
] = ieee754
;
156 /* Enable VMON output if configured */
157 ret
= i2c_smbus_read_byte_data(client
, MFR_ADC_CONTROL_LT7182S
);
160 if (ret
& MFR_DEBUG_TELEMETRY
) {
162 info
->func
[0] |= PMBUS_HAVE_VMON
;
163 info
->func
[1] |= PMBUS_HAVE_VMON
;
164 info
->func
[2] = PMBUS_HAVE_VMON
;
167 return pmbus_do_probe(client
, info
);
170 static const struct i2c_device_id lt7182s_id
[] = {
174 MODULE_DEVICE_TABLE(i2c
, lt7182s_id
);
176 static const struct of_device_id __maybe_unused lt7182s_of_match
[] = {
177 { .compatible
= "adi,lt7182s" },
181 static struct i2c_driver lt7182s_driver
= {
184 .of_match_table
= of_match_ptr(lt7182s_of_match
),
186 .probe
= lt7182s_probe
,
187 .id_table
= lt7182s_id
,
190 module_i2c_driver(lt7182s_driver
);
192 MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
193 MODULE_DESCRIPTION("PMBus driver for Analog Devices LT7182S");
194 MODULE_LICENSE("GPL");
195 MODULE_IMPORT_NS(PMBUS
);