diff options
| author | Tom Rini <trini@konsulko.com> | 2026-07-14 07:59:50 -0600 |
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2026-07-14 07:59:50 -0600 |
| commit | 501d76ca801343cce6dafb17740a8b679ed17072 (patch) | |
| tree | 1751270d21bbb6eb5feb444bd77dee625e41c3ad /drivers/power/regulator/sandbox_pmbus.c | |
| parent | 83f6cbb87177350e32eabcbe6dd92b951dabae25 (diff) | |
| parent | 722a82278752f4b9e6cf052a67e722508503f2c7 (diff) | |
Merge tag 'mmc-for-2026.10-rc1' of https://git.u-boot-project.org/u-boot/custodians/u-boot-mmcHEADmaster
CI: https://git.u-boot-project.org/u-boot/custodians/u-boot-mmc/-/pipelines/614
- Add PMBUS regulator, thermal and test
- Add regulator helper to set voltage within an acceptable range
- Update dw_mmc to use in-spec voltage range for vqmmc
- Fix regulator_enable/disable() macros
- Clear LPUART OR STAT in tstc to avoid hang
- Add MAINTAINERS entry for SDHCI
Diffstat (limited to 'drivers/power/regulator/sandbox_pmbus.c')
| -rw-r--r-- | drivers/power/regulator/sandbox_pmbus.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/drivers/power/regulator/sandbox_pmbus.c b/drivers/power/regulator/sandbox_pmbus.c new file mode 100644 index 00000000000..7b52d2ca293 --- /dev/null +++ b/drivers/power/regulator/sandbox_pmbus.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile - Vincent Jardin + * + * Sandbox PMBus 1.x chip stub (UCLASS_I2C_EMUL). + * + * Stub a DT i2c node so the PMBus framework, the generic pmbus + * regulator and the pmbus CLI command can be tested. + * The model is a flat per-command 16 bit + * register file combined with some fixed identification strings. + */ + +#include <dm.h> +#include <i2c.h> +#include <pmbus.h> +#include <linux/ctype.h> + +#define PMBUS_EMUL_NREG 256 + +struct sandbox_pmbus_priv { + u16 reg[PMBUS_EMUL_NREG]; + bool supported[PMBUS_EMUL_NREG]; +}; + +/* Identification strings reported in the natural (forward) byte order. */ +static const char *pmbus_emul_string(u8 cmd) +{ + switch (cmd) { + case PMBUS_MFR_ID: + return "SANDBOX"; + case PMBUS_MFR_MODEL: + return "PMBUS-EMUL"; + case PMBUS_MFR_REVISION: + return "1.0"; + default: + return NULL; + } +} + +static int sandbox_pmbus_read(struct sandbox_pmbus_priv *priv, u8 cmd, + u8 *buf, int len) +{ + const char *str = pmbus_emul_string(cmd); + int i; + + if (len < 1) + return -EINVAL; + + if (str) { + int slen = strlen(str); + + /* + * Block payload: [length][bytes...]. A one-byte read is + * the SMBus length probe and reports the true length (the + * master just NAKs early). Any longer read must have room + * for length + payload, otherwise the length byte would + * lie about the data actually returned. + */ + if (len > 1 && len < slen + 1) + return -EREMOTEIO; + buf[0] = (u8)slen; + for (i = 1; i < len; i++) + buf[i] = (i - 1 < slen) ? (u8)str[i - 1] : 0; + return 0; + } + + if (!priv->supported[cmd]) + return -EREMOTEIO; /* chip NAKs an unimplemented command */ + + for (i = 0; i < len; i++) + buf[i] = (u8)(priv->reg[cmd] >> (8 * i)); + return 0; +} + +static int sandbox_pmbus_write(struct sandbox_pmbus_priv *priv, u8 cmd, + const u8 *buf, int len) +{ + if (len == 0) + return 0; /* send-byte (eg CLEAR_FAULTS): just ACK */ + if (!priv->supported[cmd]) + return -EREMOTEIO; + if (len == 1) + priv->reg[cmd] = buf[0]; + else + priv->reg[cmd] = (u16)buf[0] | ((u16)buf[1] << 8); + return 0; +} + +static int sandbox_pmbus_xfer(struct udevice *emul, struct i2c_msg *msg, + int nmsgs) +{ + struct sandbox_pmbus_priv *priv = dev_get_priv(emul); + u8 cmd; + + if (nmsgs == 0) + return 0; + /* A PMBus transaction always opens with the command-code write. */ + if (msg[0].flags & I2C_M_RD) + return -EIO; + if (msg[0].len == 0) + return 0; /* address-only probe */ + cmd = msg[0].buf[0]; + + if (nmsgs >= 2 && (msg[1].flags & I2C_M_RD)) + return sandbox_pmbus_read(priv, cmd, msg[1].buf, msg[1].len); + + return sandbox_pmbus_write(priv, cmd, msg[0].buf + 1, msg[0].len - 1); +} + +static void sandbox_pmbus_support(struct sandbox_pmbus_priv *priv, u8 cmd, + u16 val) +{ + priv->supported[cmd] = true; + priv->reg[cmd] = val; +} + +static int sandbox_pmbus_probe(struct udevice *emul) +{ + struct sandbox_pmbus_priv *priv = dev_get_priv(emul); + + /* Configuration / identification. */ + sandbox_pmbus_support(priv, PMBUS_PAGE, 0); + sandbox_pmbus_support(priv, PMBUS_OPERATION, PB_OPERATION_ON); + sandbox_pmbus_support(priv, PMBUS_ON_OFF_CONFIG, 0); + sandbox_pmbus_support(priv, PMBUS_WRITE_PROTECT, 0); + sandbox_pmbus_support(priv, PMBUS_CAPABILITY, 0x30); + sandbox_pmbus_support(priv, PMBUS_VOUT_MODE, 0x18); /* LINEAR 2^-8 */ + sandbox_pmbus_support(priv, PMBUS_VOUT_COMMAND, 0x0200); + sandbox_pmbus_support(priv, PMBUS_VOUT_TRIM, 0); + sandbox_pmbus_support(priv, PMBUS_VOUT_MAX, 0x0400); + sandbox_pmbus_support(priv, PMBUS_VOUT_SCALE_LOOP, 0); + sandbox_pmbus_support(priv, PMBUS_REVISION, PMBUS_REV_13); + + /* Status registers, all clean. */ + sandbox_pmbus_support(priv, PMBUS_STATUS_BYTE, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_WORD, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_VOUT, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_IOUT, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_INPUT, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_TEMPERATURE, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_CML, 0); + + /* + * Telemetry the emulated chip implements. READ_IIN and READ_POUT + * are intentionally absent so callers see the unsupported path. + */ + sandbox_pmbus_support(priv, PMBUS_READ_VIN, 0x0abc); + sandbox_pmbus_support(priv, PMBUS_READ_VOUT, 0x0200); + sandbox_pmbus_support(priv, PMBUS_READ_IOUT, 0x0123); + sandbox_pmbus_support(priv, PMBUS_READ_TEMPERATURE_1, 0x0019); + + return 0; +} + +static struct dm_i2c_ops sandbox_pmbus_emul_ops = { + .xfer = sandbox_pmbus_xfer, +}; + +static const struct udevice_id sandbox_pmbus_ids[] = { + { .compatible = "sandbox,i2c-pmbus" }, + { } +}; + +U_BOOT_DRIVER(sandbox_pmbus_emul) = { + .name = "sandbox_pmbus_emul", + .id = UCLASS_I2C_EMUL, + .of_match = sandbox_pmbus_ids, + .probe = sandbox_pmbus_probe, + .priv_auto = sizeof(struct sandbox_pmbus_priv), + .ops = &sandbox_pmbus_emul_ops, +}; |
