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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
|
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2026 Free Mobile, Vincent Jardin
*
* PMBus 1.x command codes, numeric format decoders, and driver_info
* scaffolding for U-Boot.
*
* Intents
*
* U-Boot's PMBus support is not a hwmon clone. It shall be used to:
* 1. identify PMBus regulators a board carries at boot,
* 2. print telemetry so an operator can confirm rail voltages and
* fault status before handing off to the kernel,
* 3. decode chip alerts when a rail trips an over/under voltage,
* over current, or thermal threshold,
* 4. optionally trim a critical rail before kernel boot, to better
* protect the board.
*
* No periodic polling, no /sys, no userspace surface, no fan control
* loops. Linux owns those. See doc/develop/pmbus.rst for the full
* porting guide and policy notes.
*
* Linux relationship
*
* Constants (command codes, status bit names, sensor class enum,
* format enum) are mirrored verbatim from
* linux/drivers/hwmon/pmbus/pmbus.h
* with attribution; this is standardised data and copying it avoids
* accidental drift. Decoders (LINEAR11/16, DIRECT, VID, IEEE754) are
* reimplemented from the PMBus 1.x spec rather than copied. The
* surrounding kernel context (struct pmbus_data, hwmon caching,
* sysfs publication) does not apply to U-Boot.
*
* Tree level files (this header, lib/pmbus.c, future per chip drivers
* under drivers/power/regulator/) must stay platform agnostic. They
* may reference only the PMBus 1.x specification and chip datasheets,
* never a specific board, SoC, or product. Board specific quirks
* live under board/<vendor>/<board>/.
*/
#ifndef _PMBUS_H_
#define _PMBUS_H_
#include <linux/types.h>
struct udevice;
struct pmbus_driver_info;
struct pmbus_status_override;
/*
* PMBus 1.3 standard command codes (Part II).
*
* Subset relevant to U-Boot's needs:
* - configuration (PAGE, OPERATION, VOUT_*),
* - telemetry (READ_VIN, READ_IOUT, READ_TEMPERATURE_1, ...),
* - status (STATUS_WORD, STATUS_VOUT, ...),
* - identification (MFR_ID, MFR_MODEL, MFR_REVISION).
* Chip specific extensions (for example MPS PROTECTION_LAST 0xFB) shall be in
* the per chip driver file.
*/
#define PMBUS_PAGE 0x00
#define PMBUS_OPERATION 0x01
#define PMBUS_ON_OFF_CONFIG 0x02
#define PMBUS_CLEAR_FAULTS 0x03
#define PMBUS_PHASE 0x04
#define PMBUS_WRITE_PROTECT 0x10
#define PMBUS_CAPABILITY 0x19
#define PMBUS_QUERY 0x1a
#define PMBUS_SMBALERT_MASK 0x1b
#define PMBUS_VOUT_MODE 0x20
#define PMBUS_VOUT_COMMAND 0x21
#define PMBUS_VOUT_TRIM 0x22
#define PMBUS_VOUT_CAL_OFFSET 0x23
#define PMBUS_VOUT_MAX 0x24
#define PMBUS_VOUT_MARGIN_HIGH 0x25
#define PMBUS_VOUT_MARGIN_LOW 0x26
#define PMBUS_VOUT_TRANSITION_RATE 0x27
#define PMBUS_VOUT_DROOP 0x28
#define PMBUS_VOUT_SCALE_LOOP 0x29
#define PMBUS_VOUT_SCALE_MONITOR 0x2a
#define PMBUS_COEFFICIENTS 0x30
#define PMBUS_POUT_MAX 0x31
#define PMBUS_STATUS_BYTE 0x78
#define PMBUS_STATUS_WORD 0x79
#define PMBUS_STATUS_VOUT 0x7a
#define PMBUS_STATUS_IOUT 0x7b
#define PMBUS_STATUS_INPUT 0x7c
#define PMBUS_STATUS_TEMPERATURE 0x7d
#define PMBUS_STATUS_CML 0x7e
#define PMBUS_STATUS_OTHER 0x7f
#define PMBUS_STATUS_MFR_SPECIFIC 0x80
#define PMBUS_READ_VIN 0x88
#define PMBUS_READ_IIN 0x89
#define PMBUS_READ_VCAP 0x8a
#define PMBUS_READ_VOUT 0x8b
#define PMBUS_READ_IOUT 0x8c
#define PMBUS_READ_TEMPERATURE_1 0x8d
#define PMBUS_READ_TEMPERATURE_2 0x8e
#define PMBUS_READ_TEMPERATURE_3 0x8f
#define PMBUS_READ_DUTY_CYCLE 0x94
#define PMBUS_READ_FREQUENCY 0x95
#define PMBUS_READ_POUT 0x96
#define PMBUS_READ_PIN 0x97
#define PMBUS_REVISION 0x98
#define PMBUS_MFR_ID 0x99
#define PMBUS_MFR_MODEL 0x9a
#define PMBUS_MFR_REVISION 0x9b
#define PMBUS_MFR_LOCATION 0x9c
#define PMBUS_MFR_DATE 0x9d
#define PMBUS_MFR_SERIAL 0x9e
#define PMBUS_IC_DEVICE_ID 0xad
#define PMBUS_IC_DEVICE_REV 0xae
/* VOUT_MODE upper bits: numeric format selector (Part II sec 8.3). */
#define PB_VOUT_MODE_MODE_MASK 0xe0
#define PB_VOUT_MODE_PARAM_MASK 0x1f
#define PB_VOUT_MODE_LINEAR 0x00
#define PB_VOUT_MODE_VID 0x20
#define PB_VOUT_MODE_DIRECT 0x40
#define PB_VOUT_MODE_IEEE754 0x60
/* STATUS_WORD lower byte (= STATUS_BYTE), Part II sec 10.1.1. */
#define PB_STATUS_NONE_ABOVE BIT(0)
#define PB_STATUS_CML BIT(1)
#define PB_STATUS_TEMPERATURE BIT(2)
#define PB_STATUS_VIN_UV BIT(3)
#define PB_STATUS_IOUT_OC BIT(4)
#define PB_STATUS_VOUT_OV BIT(5)
#define PB_STATUS_OFF BIT(6)
#define PB_STATUS_BUSY BIT(7)
/* STATUS_WORD upper byte. */
#define PB_STATUS_UNKNOWN BIT(8)
#define PB_STATUS_OTHER BIT(9)
#define PB_STATUS_FANS BIT(10)
#define PB_STATUS_POWER_GOOD_N BIT(11)
#define PB_STATUS_WORD_MFR BIT(12)
#define PB_STATUS_INPUT BIT(13)
#define PB_STATUS_IOUT_POUT BIT(14)
#define PB_STATUS_VOUT BIT(15)
/* STATUS_VOUT (PMBus 1.3.1 Part II sec 17.3, Table 17). */
#define PB_VOLTAGE_VOUT_MAX_MIN_WARN BIT(3)
#define PB_VOLTAGE_UV_FAULT BIT(4)
#define PB_VOLTAGE_UV_WARNING BIT(5)
#define PB_VOLTAGE_OV_WARNING BIT(6)
#define PB_VOLTAGE_OV_FAULT BIT(7)
/* STATUS_IOUT (Part II sec 10.6). */
#define PB_POUT_OP_WARNING BIT(0)
#define PB_POUT_OP_FAULT BIT(1)
#define PB_POWER_LIMITING BIT(2)
#define PB_CURRENT_SHARE_FAULT BIT(3)
#define PB_IOUT_UC_FAULT BIT(4)
#define PB_IOUT_OC_WARNING BIT(5)
#define PB_IOUT_OC_LV_FAULT BIT(6)
#define PB_IOUT_OC_FAULT BIT(7)
/* STATUS_INPUT (Part II sec 10.7). */
#define PB_PIN_OP_WARNING BIT(0)
#define PB_IIN_OC_WARNING BIT(1)
#define PB_IIN_OC_FAULT BIT(2)
/* STATUS_TEMPERATURE (Part II sec 10.8). */
#define PB_TEMP_UT_FAULT BIT(4)
#define PB_TEMP_UT_WARNING BIT(5)
#define PB_TEMP_OT_WARNING BIT(6)
#define PB_TEMP_OT_FAULT BIT(7)
/* STATUS_CML (Part II sec 10.9). */
#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0)
#define PB_CML_FAULT_OTHER_COMM BIT(1)
#define PB_CML_FAULT_PROCESSOR BIT(3)
#define PB_CML_FAULT_MEMORY BIT(4)
#define PB_CML_FAULT_PACKET_ERROR BIT(5)
#define PB_CML_FAULT_INVALID_DATA BIT(6)
#define PB_CML_FAULT_INVALID_COMMAND BIT(7)
/*
* OPERATION (01h) command bits per PMBus 1.3 Part II sec 9.1. Bit[7]
* is the master rail enable; the lower bits select margin high/low
* and turn off behaviour (subset surfaced for the regulator helper).
*/
#define PB_OPERATION_ON BIT(7)
/*
* LINEAR11 numeric format (PMBus 1.3 Part II sec 7): 16 bit register
* with a signed 11 bit mantissa in bits[10:0] and a signed 5 bit
* exponent in bits[15:11]. Engineering value = mantissa * 2^exponent.
*/
#define PB_LINEAR11_MANT_MASK 0x07ff
#define PB_LINEAR11_MANT_BITS 11
#define PB_LINEAR11_EXP_SHIFT 11
#define PB_LINEAR11_EXP_MASK 0x1f
#define PB_LINEAR11_EXP_BITS 5
/*
* Cache buffer sizes for the active device singleton + MFR_* block
* reads. PMBus block reads return up to 32 bytes per the SMBus spec;
* 16 covers every MFR string seen in practice on regulator class
* chips and keeps the singleton compact.
*/
#define PMBUS_MFR_STRING_MAX 16
#define PMBUS_VENDOR_NAME_MAX 8
#define PMBUS_REGULATOR_NAME_MAX 24
/* PMBus revision identifiers reported by PMBUS_REVISION (98h). */
#define PMBUS_REV_10 0x00 /* PMBus 1.0 */
#define PMBUS_REV_11 0x11 /* PMBus 1.1 */
#define PMBUS_REV_12 0x22 /* PMBus 1.2 */
#define PMBUS_REV_13 0x33 /* PMBus 1.3 */
/*
* Numeric formats and sensor classes.
*
* Mirrors linux/drivers/hwmon/pmbus/pmbus.h enum pmbus_data_format
* and enum pmbus_sensor_classes. A chip's pmbus_driver_info wires
* each sensor class to one format and (for DIRECT) to its m/b/R
* coefficients.
*/
enum pmbus_data_format {
pmbus_fmt_linear = 0,
pmbus_fmt_ieee754,
pmbus_fmt_direct,
pmbus_fmt_vid,
};
enum pmbus_sensor_classes {
PSC_VOLTAGE_IN = 0,
PSC_VOLTAGE_OUT,
PSC_CURRENT_IN,
PSC_CURRENT_OUT,
PSC_POWER,
PSC_TEMPERATURE,
PSC_NUM_CLASSES
};
/*
* Per chip identification record. Each per chip driver declares one
* of these and points the framework at it. Subset of the kernel
* struct pmbus_driver_info: U-Boot has no per page caches, no fan
* accessors, no virtual registers, no async sysfs publication.
*
* pages number of PAGE distinct rails the chip exposes
* (1 for single rail parts).
* format[] numeric format per sensor class.
* m/b/R[] DIRECT format coefficients per sensor class. See
* pmbus_reg2data_direct() below for the formula.
* Unused for non DIRECT classes.
* read_byte_data, read_word_data
* optional per chip register translators. Return the
* standard register value on success, ENODATA to fall
* through to the generic transport, any other negative
* errno on bus error.
* identify optional probe time hook to discover format and
* page count from the chip itself (for example, the
* MPQ8785 VOUT_MODE switch between LINEAR and DIRECT).
*/
struct pmbus_driver_info {
int pages;
enum pmbus_data_format format[PSC_NUM_CLASSES];
int m[PSC_NUM_CLASSES];
int b[PSC_NUM_CLASSES];
int R[PSC_NUM_CLASSES];
int (*read_byte_data)(struct udevice *dev, int page, int reg);
int (*read_word_data)(struct udevice *dev, int page, int reg);
int (*identify)(struct udevice *dev, struct pmbus_driver_info *info);
/*
* Optional sparse table of chip specific STATUS_* bit name
* substitutions. Terminated by an entry with .name = NULL
* (matching the convention used by struct udevice_id and
* other U-Boot driver tables). NULL pointer means the chip
* uses only PMBus 1.x standard names. See struct
* pmbus_status_override and pmbus_print_status_bits().
*/
const struct pmbus_status_override *status_overrides;
/*
* Bitmask (BIT(enum pmbus_sensor_classes)) of the sensor classes
* this chip actually implements. When non-zero, pmbus_print_telemetry
* prints exactly these classes -- mirroring the kernel's per chip
* sensor set -- and skips the rest. This is how an MPS buck that
* ACKs READ_POUT / READ_IIN with an uncalibrated value still hides
* POWER / CURRENT_IN (the kernel's mpq8646 driver exposes neither).
* Zero means "not declared": the telemetry printer falls back to a
* live pmbus_word_command_supported() probe per class, which is what
* the generic driver (compatible = "pmbus") relies on.
*/
u8 classes_present;
};
/*
* Decoder helpers (raw register, returns engineering value in micro
* units).
*
* All return signed micro units (uV, uA, udegC), 64 bit to avoid
* overflow on large mantissa times exponent products. The caller
* divides by 1000 for milli units, or by 1_000_000 for the integer
* engineering value.
*/
/*
* LINEAR11. Bits[15:11] = signed 5 bit exponent Y, bits[10:0] =
* signed 11 bit mantissa N. Engineering value = N * 2^Y.
*
* Used by most PMBus chips for VIN, IIN, IOUT, TEMP. Some MPS
* parts deviate (they report DIRECT format with chip specific m/b/R
* coefficients); check the chip datasheet against PMBUS_VOUT_MODE
* and the Linux per chip driver if porting.
*/
s64 pmbus_reg2data_linear11(u16 raw);
/*
* LINEAR16. 16 bit unsigned mantissa multiplied by 2^Y, where Y is
* the signed 5 bit exponent supplied via VOUT_MODE bits[4:0]. The
* caller must read VOUT_MODE (cmd 0x20) and pass it in vout_mode.
* Only the mode_mask bits[7:5] = 0 selector is the LINEAR16 path.
*
* Used for READ_VOUT (8Bh) on chips whose VOUT_MODE selects Linear.
* Returns 0 if VOUT_MODE indicates a non Linear mode; the caller
* is then expected to dispatch to pmbus_reg2data_direct() with the
* appropriate per chip m/b/R, or to pmbus_reg2data_vid() / _ieee754()
* if the chip uses those formats.
*/
s64 pmbus_reg2data_linear16(u16 raw, u8 vout_mode);
/*
* DIRECT. PMBus 1.3 Part II sec 8.4. The chip stores a signed 16 bit
* value X; the engineering value Y is one over m, multiplied by the
* quantity (X scaled by ten to the power minus R, then offset by
* minus b), with chip specific (m, b, R) coefficients.
*
* In symbolic form: Y = (1/m) * (X * 10**(-R) - b). The negative
* exponent and trailing subtraction are math operators in the
* formula, not punctuation in the prose.
*
* Returns micro units. Implementation order matches the Linux
* reference (multiply before subtract, scale R then divide by m) to
* minimise quantisation drift. m == 0 returns 0.
*/
s64 pmbus_reg2data_direct(s16 raw, int m, int b, int R);
/*
* Encoder: engineering value (micro units) to LINEAR16 raw register
* value. Used by pre kernel rail trim code (see board/nxp/common/vid.c)
* to write VOUT_COMMAND from a target voltage. The exponent is
* recovered from VOUT_MODE.
*
* Returns 0 if VOUT_MODE indicates a non Linear format; the caller
* must then dispatch to pmbus_data2reg_direct() (DIRECT format) or
* the VID / IEEE754 encoders (when those land) per the chip's actual
* VOUT_MODE selector.
*/
u16 pmbus_data2reg_linear16(s64 micro, u8 vout_mode);
/*
* Encoder: engineering value (micro units) to DIRECT raw register
* value. Inverse of pmbus_reg2data_direct():
*
* X = (m * Y + b) * 10^R
*
* with chip specific (m, b, R) coefficients (typically taken from
* the chip's pmbus_driver_info[PSC_VOLTAGE_OUT]). m == 0 returns 0.
*
* The result is saturated to the s16 range mandated by the PMBus
* 1.3 Part II sec 8.4 DIRECT encoding; out of range targets return
* 0x7fff or 0x8000 rather than wrapping.
*/
u16 pmbus_data2reg_direct(s64 micro, int m, int b, int R);
/*
* Dispatcher: pick the right reg2data_* helper based on the chip's
* pmbus_driver_info[class]. vout_mode is consulted only for
* VOLTAGE_OUT in linear format. For DIRECT, m/b/R are taken from
* info. For VID and IEEE754 the dispatcher returns 0 (formats
* not yet wired up; add when a consumer lands).
*/
s64 pmbus_reg2data(const struct pmbus_driver_info *info,
enum pmbus_sensor_classes class,
u16 raw, u8 vout_mode);
/*
* Transport helpers.
*
* Thin wrappers over the U-Boot DM I2C primitives that handle PMBus
* framing details (little endian word layout, two stage block read,
* CLEAR_FAULTS pseudo command without payload).
*/
/* Read a byte register. */
int pmbus_read_byte(struct udevice *dev, u8 cmd, u8 *val);
/* Read a 16 bit register, little endian on the wire. */
int pmbus_read_word(struct udevice *dev, u8 cmd, u16 *val);
/* Write a byte register. */
int pmbus_write_byte(struct udevice *dev, u8 cmd, u8 val);
/* Write a 16 bit register, little endian on the wire. */
int pmbus_write_word(struct udevice *dev, u8 cmd, u16 val);
/*
* Block read of a vendor string register (MFR_ID, MFR_MODEL,
* MFR_REVISION). The first wire byte is the payload length; the
* helper does the second read for the payload itself, so even strict
* I2C controllers (which forbid over read on block transactions)
* work. Output is null terminated and printable only (non printable
* bytes are substituted with '.').
*
* reverse_bytes: some MPS NVM personalities store ASCII strings
* LSB first (chip returns "SPM" for the human string "MPS"); pass
* true to reverse on copy. Spec compliant chips pass false.
*
* Returns string length on success or a negative errno on bus error
* or invalid length byte. outsz must be at least 2.
*/
int pmbus_read_string(struct udevice *dev, u8 cmd, char *out, int outsz,
bool reverse_bytes);
/* Issue a CLEAR_FAULTS (03h) write. Clears RAM sticky STATUS_*. */
int pmbus_clear_faults(struct udevice *dev);
/*
* Capability probe: is a word sized command implemented by the chip?
*
* Primary signal is the bus NAK -- compliant parts do not ACK a
* command they do not implement, so the word read fails. Secondary
* signal is a clean -> dirty transition of STATUS_CML[INVALID_COMMAND]
* across the read (a chip that ACKs but does not implement the
* register raises it). Non destructive: never issues CLEAR_FAULTS, so
* sticky fault history survives for a subsequent pmbus status; a
* pre existing CML fault disables the secondary signal so it cannot
* produce a false "unsupported".
*
* Returns true if the command appears supported, false otherwise.
*/
bool pmbus_word_command_supported(struct udevice *dev, u8 reg);
/*
* High level snapshot printers shared by the pmbus CLI and board
* boot time diagnostics. Both operate on the current pmbus_active()
* device (select it first via pmbus_set_active()); chip is the I2C
* handle from pmbus_active_get_i2c() / the CLI's require_active().
*
* pmbus_print_telemetry: decodes VIN / VOUT / IIN / IOUT / POUT / TEMP
* through the active device's pmbus_driver_info (LINEAR / DIRECT / VID
* per VOUT_MODE and per class format), skipping commands the chip does
* not implement (pmbus_word_command_supported). Falls back to
* LINEAR16 / LINEAR11 when no driver_info is cached. Caller prints the
* header line.
*
* pmbus_print_status_word: reads + decodes STATUS_WORD with the active
* device's chip specific status_overrides, if any.
*/
void pmbus_print_telemetry(struct udevice *chip);
void pmbus_print_status_word(struct udevice *chip);
/*
* Regulator -> thermal bridge.
*
* Read READ_TEMPERATURE_1 (8Dh) from a UCLASS_REGULATOR device that
* was bound by a pmbus_helper based chip driver, decode it through
* the chip's pmbus_driver_info (so the MPS DIRECT 1 degC/LSB quirk
* and the standard LINEAR11 encoding are both handled), select the
* regulator's PAGE first on multi rail parts, and return the result
* in millidegrees Celsius.
*
* This is what the generic drivers/thermal/pmbus_thermal.c companion
* calls on its parent; keeping the decode here avoids exposing the
* regulator-private pmbus_regulator_priv layout to other subsystems.
*
* Returns 0 on success, or a negative errno (-ENODEV if reg is not a
* probed pmbus regulator, -EIO on bus error).
*/
int pmbus_regulator_read_temp(struct udevice *reg_dev, int *temp_mc);
/*
* Look up the pmbus_driver_info of a probed UCLASS_REGULATOR device at
* (bus_seq, addr) that is driven by a pmbus_helper based chip driver
* (mpq8785, pmbus_generic, ...). Probes the device so its identify
* hook has run and format[] is populated, then returns its
* driver_info. Returns NULL if no such regulator is bound at that
* address, if the device is not a pmbus regulator, or if
* CONFIG_DM_REGULATOR_PMBUS_HELPER is disabled.
*
* Lets pmbus_set_active() -- and thus the pmbus CLI and the board
* boot snapshots -- reuse the rich, VOUT_MODE detected driver_info of
* a DT bound generic / chip regulator when the device is selected by
* raw <bus>:<addr> (which has no chip-match registry entry and would
* otherwise fall back to blanket LINEAR16 / LINEAR11 decoding).
*/
const struct pmbus_driver_info *pmbus_regulator_info_by_addr(int bus_seq,
u8 addr);
/*
* Status bit name decoding.
*
* Sparse mask to name table. pmbus_print_bits() emits only the bits
* that are SET in v, joined by |; if no bit is set, prints
* clean. Bits not in the table are silently ignored (RESERVED bits
* or chip specific bits handled by a separate per chip table).
*/
struct pmbus_bit {
u16 mask;
const char *name;
};
void pmbus_print_bits(u16 v, const struct pmbus_bit *tab);
/*
* Per chip override entry. When a chip reuses a PMBus standard
* STATUS bit for a documented chip specific signal (for example MPS
* uses STATUS_WORD bit[12] = MFR_SPECIFIC as NVM_SUMMARY, bit[8] =
* UNKNOWN as WATCH_DOG, bit[0] = NONE_ABOVE as DRMOS_FAULT), the
* per chip driver supplies a sparse table of (reg, mask, name)
* triples and pmbus_print_status_bits() substitutes the chip name
* for the standard one when the bit is set.
*
* reg is one of PMBUS_STATUS_WORD / VOUT / IOUT / INPUT /
* TEMPERATURE / CML, so the same table can carry overrides for
* every status register on the chip in one place. Tables that omit
* a (reg, mask) leave the standard name in place.
*
* Override entries whose mask is NOT in the standard table are
* still printed (the chip can extend coverage beyond PMBus 1.x for
* vendor specific bits in standard registers).
*
* Tables are NULL terminated: the last entry has .name = NULL.
* Following the same convention U-Boot uses for struct udevice_id
* and other driver tables avoids the explicit-count foot-gun.
*/
struct pmbus_status_override {
u8 reg;
u16 mask;
const char *name;
};
/*
* Print the bit names of a STATUS_* register value. For each bit
* set in v, prefer a chip override matching (reg, mask) over the
* standard std table entry; if neither matches, the bit is
* silently skipped (RESERVED). If no bit is set at all, prints
* clean. Pass ovr = NULL to disable the override path.
*/
void pmbus_print_status_bits(u8 reg, u16 v,
const struct pmbus_bit *std,
const struct pmbus_status_override *ovr);
/*
* Built in PMBus 1.3 standard bit tables (use these from per chip
* drivers and board diagnostics; vendor extensions go in chip local
* tables that the per chip driver passes alongside these).
*/
/*
* All tables below are NULL terminated (last entry has .name = NULL),
* so callers walk with for (t = tab; t && t->name; t++) and the
* helpers above need no count argument.
*/
extern const struct pmbus_bit pmbus_status_word_bits[];
extern const struct pmbus_bit pmbus_status_vout_bits[];
extern const struct pmbus_bit pmbus_status_iout_bits[];
extern const struct pmbus_bit pmbus_status_input_bits[];
extern const struct pmbus_bit pmbus_status_temp_bits[];
extern const struct pmbus_bit pmbus_status_cml_bits[];
/*
* Active device tracking for the pmbus U-Boot CLI.
*
* The framework keeps one active PMBus device. It is selected by
* pmbus dev <bus>:<addr> (raw I2C tuple) and remembered across
* subcommands so subsequent invocations of pmbus telemetry,
* pmbus status, pmbus dump, etc. operate on the same chip
* without re-typing the address.
*
* pmbus_set_active() probes the chip's MFR_ID at the given address,
* looks the result up in the chip-match registry (populated by
* per chip drivers via pmbus_register_chip()), and caches the
* resulting struct pmbus_driver_info. Subcommands consult
* pmbus_active() to find the cached metadata.
*/
struct pmbus_active_dev {
bool valid;
int bus_seq;
u8 addr;
char vendor[PMBUS_VENDOR_NAME_MAX];
char name[PMBUS_REGULATOR_NAME_MAX]; /* DT regulator-name when bound; "" otherwise */
char mfr_id[PMBUS_MFR_STRING_MAX];
char mfr_model[PMBUS_MFR_STRING_MAX];
char mfr_revision[PMBUS_MFR_STRING_MAX];
bool mfr_reverse; /* chip stores MFR strings LSB first */
const struct pmbus_driver_info *info;
};
const struct pmbus_active_dev *pmbus_active(void);
int pmbus_active_get_i2c(struct udevice **i2c_dev);
int pmbus_set_active(int bus_seq, u8 addr);
void pmbus_clear_active(void);
/*
* Per chip driver / board file registers a chip match so the
* framework can associate an MFR_ID prefix (read at probe time)
* with a vendor namespace ("mps", "lltc", "renesas", ...) and a
* pmbus_driver_info pointer. The first matching entry wins.
*
* mfr_id_reverse flags MPS style chips that store the MFR_ID
* string LSB first (chip returns "SPM" for the human string
* "MPS"); the framework reads the string in both orderings and
* matches against the prefix in the natural reading.
*/
struct pmbus_chip_match {
const char *mfr_id;
bool mfr_id_reverse;
const char *vendor;
const struct pmbus_driver_info *info;
};
int pmbus_register_chip(const struct pmbus_chip_match *match);
/*
* Resolve a regulator-name (DT regulator-name property) to its
* (bus, addr) tuple by walking UCLASS_REGULATOR. Used by the
* pmbus dev <name> CLI alias so a chip bound through DT can be
* selected by its human readable rail name (e.g. "+0V8_VDD")
* instead of the i2c bus / address pair. Returns 0 on success
* (out parameters populated and the regulator probed), or a
* negative errno if no match is found or the bus / address cannot
* be derived. Available only when CONFIG_DM_REGULATOR is set.
*/
int pmbus_resolve_by_name(const char *name, int *bus_seq, u8 *addr);
/*
* Vendor extension dispatcher.
*
* When the user types pmbus <vendor> <args...>, the framework
* looks up the registered handler for <vendor> and calls it with
* the argv tail (argv[0] = "<vendor>"). The handler operates on
* pmbus_active(), or returns CMD_RET_USAGE if the active device is
* not from this vendor.
*
* Per chip drivers register their vendor handler at init time. The
* MPS extension publishes pmbus mps last, pmbus mps clear last,
* and pmbus mps clear force.
*/
typedef int (*pmbus_vendor_handler_t)(struct cmd_tbl *cmdtp, int flag,
int argc, char *const argv[]);
struct pmbus_vendor_op {
const char *vendor;
pmbus_vendor_handler_t handler;
const char *help;
};
int pmbus_register_vendor_handler(const struct pmbus_vendor_op *op);
const struct pmbus_vendor_op *pmbus_lookup_vendor(const char *vendor);
unsigned int pmbus_vendor_count(void);
const struct pmbus_vendor_op *pmbus_vendor_at(unsigned int i);
#endif /* _PMBUS_H_ */
|