1 // SPDX-License-Identifier: GPL-2.0+
3 * Hardware monitoring driver for Infineon TDA38640
5 * Copyright (c) 2023 9elements GmbH
10 #include <linux/i2c.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/regulator/driver.h>
17 static const struct regulator_desc __maybe_unused tda38640_reg_desc
[] = {
18 PMBUS_REGULATOR_ONE("vout"),
21 struct tda38640_data
{
22 struct pmbus_driver_info info
;
26 #define to_tda38640_data(x) container_of(x, struct tda38640_data, info)
29 * Map PB_ON_OFF_CONFIG_POLARITY_HIGH to PB_OPERATION_CONTROL_ON.
31 static int tda38640_read_byte_data(struct i2c_client
*client
, int page
, int reg
)
33 const struct pmbus_driver_info
*info
= pmbus_get_driver_info(client
);
34 struct tda38640_data
*data
= to_tda38640_data(info
);
35 int ret
, on_off_config
, enabled
;
37 if (reg
!= PMBUS_OPERATION
)
40 ret
= pmbus_read_byte_data(client
, page
, reg
);
44 on_off_config
= pmbus_read_byte_data(client
, page
,
46 if (on_off_config
< 0)
49 enabled
= !!(on_off_config
& PB_ON_OFF_CONFIG_POLARITY_HIGH
);
51 enabled
^= data
->en_pin_lvl
;
53 ret
&= ~PB_OPERATION_CONTROL_ON
;
55 ret
|= PB_OPERATION_CONTROL_ON
;
61 * Map PB_OPERATION_CONTROL_ON to PB_ON_OFF_CONFIG_POLARITY_HIGH.
63 static int tda38640_write_byte_data(struct i2c_client
*client
, int page
,
66 const struct pmbus_driver_info
*info
= pmbus_get_driver_info(client
);
67 struct tda38640_data
*data
= to_tda38640_data(info
);
70 if (reg
!= PMBUS_OPERATION
)
73 enable
= !!(byte
& PB_OPERATION_CONTROL_ON
);
75 byte
&= ~PB_OPERATION_CONTROL_ON
;
76 ret
= pmbus_write_byte_data(client
, page
, reg
, byte
);
80 enable
^= data
->en_pin_lvl
;
82 return pmbus_update_byte_data(client
, page
, PMBUS_ON_OFF_CONFIG
,
83 PB_ON_OFF_CONFIG_POLARITY_HIGH
,
84 enable
? 0 : PB_ON_OFF_CONFIG_POLARITY_HIGH
);
87 static int svid_mode(struct i2c_client
*client
, struct tda38640_data
*data
)
89 /* PMBUS_MFR_READ(0xD0) + MTP Address offset */
90 u8 write_buf
[] = {0xd0, 0x44, 0x00};
93 bool off
, reg_en_pin_pol
;
95 struct i2c_msg msgs
[2] = {
100 .len
= sizeof(write_buf
),
103 .addr
= client
->addr
,
106 .len
= sizeof(read_buf
),
110 ret
= i2c_transfer(client
->adapter
, msgs
, 2);
112 dev_err(&client
->dev
, "i2c_transfer failed. %d", ret
);
117 * 0x44[15] determines PMBus Operating Mode
118 * If bit is set then it is SVID mode.
120 svid
= !!(read_buf
[1] & BIT(7));
123 * Determine EN pin level for use in SVID mode.
124 * This is done with help of STATUS_BYTE bit 6(OFF) & ON_OFF_CONFIG bit 2(EN pin polarity).
127 ret
= i2c_smbus_read_byte_data(client
, PMBUS_STATUS_BYTE
);
130 off
= !!(ret
& PB_STATUS_OFF
);
132 ret
= i2c_smbus_read_byte_data(client
, PMBUS_ON_OFF_CONFIG
);
135 reg_en_pin_pol
= !!(ret
& PB_ON_OFF_CONFIG_POLARITY_HIGH
);
136 data
->en_pin_lvl
= off
^ reg_en_pin_pol
;
142 static struct pmbus_driver_info tda38640_info
= {
144 .format
[PSC_VOLTAGE_IN
] = linear
,
145 .format
[PSC_VOLTAGE_OUT
] = linear
,
146 .format
[PSC_CURRENT_OUT
] = linear
,
147 .format
[PSC_CURRENT_IN
] = linear
,
148 .format
[PSC_POWER
] = linear
,
149 .format
[PSC_TEMPERATURE
] = linear
,
150 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_STATUS_INPUT
151 | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_TEMP
153 | PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT
154 | PMBUS_HAVE_IOUT
| PMBUS_HAVE_STATUS_IOUT
155 | PMBUS_HAVE_POUT
| PMBUS_HAVE_PIN
,
156 #if IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR)
158 .reg_desc
= tda38640_reg_desc
,
162 static int tda38640_probe(struct i2c_client
*client
)
164 struct tda38640_data
*data
;
167 data
= devm_kzalloc(&client
->dev
, sizeof(*data
), GFP_KERNEL
);
170 memcpy(&data
->info
, &tda38640_info
, sizeof(tda38640_info
));
172 if (IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR
) &&
173 of_property_read_bool(client
->dev
.of_node
, "infineon,en-pin-fixed-level")) {
174 svid
= svid_mode(client
, data
);
176 dev_err_probe(&client
->dev
, svid
, "Could not determine operating mode.");
181 * Apply ON_OFF_CONFIG workaround as enabling the regulator using the
182 * OPERATION register doesn't work in SVID mode.
184 * One should configure PMBUS_ON_OFF_CONFIG here, but
185 * PB_ON_OFF_CONFIG_POWERUP_CONTROL and PB_ON_OFF_CONFIG_EN_PIN_REQ
186 * are ignored by the device.
187 * Only PB_ON_OFF_CONFIG_POLARITY_HIGH has an effect.
190 data
->info
.read_byte_data
= tda38640_read_byte_data
;
191 data
->info
.write_byte_data
= tda38640_write_byte_data
;
194 return pmbus_do_probe(client
, &data
->info
);
197 static const struct i2c_device_id tda38640_id
[] = {
201 MODULE_DEVICE_TABLE(i2c
, tda38640_id
);
203 static const struct of_device_id __maybe_unused tda38640_of_match
[] = {
204 { .compatible
= "infineon,tda38640"},
207 MODULE_DEVICE_TABLE(of
, tda38640_of_match
);
209 /* This is the driver that will be inserted */
210 static struct i2c_driver tda38640_driver
= {
213 .of_match_table
= of_match_ptr(tda38640_of_match
),
215 .probe
= tda38640_probe
,
216 .id_table
= tda38640_id
,
219 module_i2c_driver(tda38640_driver
);
221 MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>");
222 MODULE_DESCRIPTION("PMBus driver for Infineon TDA38640");
223 MODULE_LICENSE("GPL");
224 MODULE_IMPORT_NS("PMBUS");