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
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2026 Free Mobile, Vincent Jardin
*
* Generic PMBus 1.x compatible voltage regulator driver.
*
* Catch all driver bound to compatible = "pmbus" for chips that have
* no per chip driver under drivers/power/regulator/. The probe path
* detects the VOUT numeric format from VOUT_MODE bits[7:5]:
*
* - 0 LINEAR16 with the exponent supplied via VOUT_MODE bits[4:0]
* - 1 VID; mapped to pmbus_fmt_vid (decoder returns 0 today; per
* chip driver still required to plug a VID table)
* - 2 DIRECT; default coefficients m=1, b=0, R=0 (per chip
* coefficients arrive via PMBUS_QUERY / PMBUS_COEFFICIENTS,
* not yet consumed by U-Boot; values may need a per chip
* driver if telemetry numbers are wrong)
* - 3 IEEE754; mapped to pmbus_fmt_ieee754 (decoder returns 0
* today; per chip driver required)
*
* Other sensor classes (VIN, IIN, IOUT, TEMPERATURE) default to
* LINEAR which is the spec baseline for compliant chips. If an
* operator sees wrong telemetry numbers on this driver, the answer
* is to write a per chip driver with the correct format[] / m / b / R.
*
* Adapted in spirit from linux/drivers/hwmon/pmbus/pmbus.c (the
* kernel's generic probe driver). The U-Boot version drops the
* page count auto detection (most generic compliant parts are
* single rail; multi rail chips are quirky enough to need a per
* chip driver) and the kernel hwmon publication layers.
*/
#include <dm.h>
#include <i2c.h>
#include <log.h>
#include <pmbus.h>
#include <power/regulator.h>
#include "pmbus_helper.h"
struct pmbus_generic_priv {
struct pmbus_regulator_priv base; /* must be first */
struct pmbus_driver_info info;
};
static int pmbus_generic_probe(struct udevice *dev)
{
struct pmbus_generic_priv *gpriv = dev_get_priv(dev);
struct pmbus_driver_info *info = &gpriv->info;
enum pmbus_sensor_classes c;
int ret;
info->pages = 1;
for (c = 0; c < PSC_NUM_CLASSES; c++) {
info->format[c] = pmbus_fmt_linear;
info->m[c] = 0;
info->b[c] = 0;
info->R[c] = 0;
}
ret = pmbus_regulator_probe_common(dev, info, 0);
if (ret)
return ret;
/*
* Avoid reading non supported pages to avoid device's sticky
* status.
*/
info->pages = dev_read_u32_default(dev, "pmbus,num-pages", 1);
if (info->pages < 1)
info->pages = 1;
pmbus_regulator_identify_vout(gpriv->base.i2c_dev, info);
return 0;
}
static const struct udevice_id pmbus_generic_ids[] = {
{ .compatible = "pmbus" },
{ }
};
U_BOOT_DRIVER(pmbus_generic_regulator) = {
.name = "pmbus_generic_regulator",
.id = UCLASS_REGULATOR,
.of_match = pmbus_generic_ids,
.probe = pmbus_generic_probe,
.ops = &pmbus_regulator_ops,
.priv_auto = sizeof(struct pmbus_generic_priv),
};
|