[PATCH 07/11] reboot-mode: pm8916-pon: add new driver
Sam Day via B4 Relay
devnull+me.samcday.com at kernel.org
Sat Jun 6 10:47:38 CEST 2026
From: Sam Day <me at samcday.com>
The PM8916 provides a PON_SOFT_RB_SPARE register that survives across
reboots.
Signed-off-by: Sam Day <me at samcday.com>
---
drivers/misc/pm8916_pon.c | 7 +++
drivers/reboot-mode/Makefile | 1 +
drivers/reboot-mode/reboot-mode-pm8916-pon.c | 88 ++++++++++++++++++++++++++++
3 files changed, 96 insertions(+)
diff --git a/drivers/misc/pm8916_pon.c b/drivers/misc/pm8916_pon.c
index 4cd8921a08a..c889d2d4e6e 100644
--- a/drivers/misc/pm8916_pon.c
+++ b/drivers/misc/pm8916_pon.c
@@ -142,6 +142,13 @@ static int pm8916_pon_bind(struct udevice *dev)
dev_warn(dev, "failed to bind qcom_pwrkey: %d\n", ret);
}
+ if (CONFIG_IS_ENABLED(DM_REBOOT_MODE)) {
+ ret = device_bind_driver_to_node(dev, "pm8916_pon_reboot_mode",
+ "reboot_mode", dev_ofnode(dev), NULL);
+ if (ret)
+ dev_warn(dev, "failed to bind reboot_mode: %d\n", ret);
+ }
+
return 0;
}
diff --git a/drivers/reboot-mode/Makefile b/drivers/reboot-mode/Makefile
index 48c8ab7fe71..467334d010e 100644
--- a/drivers/reboot-mode/Makefile
+++ b/drivers/reboot-mode/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode-uclass.o
obj-$(CONFIG_DM_REBOOT_MODE_GPIO) += reboot-mode-gpio.o
obj-$(CONFIG_DM_REBOOT_MODE_RTC) += reboot-mode-rtc.o
obj-$(CONFIG_REBOOT_MODE_NVMEM) += reboot-mode-nvmem.o
+obj-$(CONFIG_PM8916_PON) += reboot-mode-pm8916-pon.o
diff --git a/drivers/reboot-mode/reboot-mode-pm8916-pon.c b/drivers/reboot-mode/reboot-mode-pm8916-pon.c
new file mode 100644
index 00000000000..fa8d0ecaa77
--- /dev/null
+++ b/drivers/reboot-mode/reboot-mode-pm8916-pon.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/read.h>
+#include <fdtdec.h>
+#include <power/pmic.h>
+#include <reboot-mode/reboot-mode.h>
+
+#define PON_SOFT_RB_SPARE 0x8f
+
+#define GEN1_REASON_SHIFT 2
+
+struct pm8916_pon_reboot_mode_priv {
+ struct udevice *pmic;
+ phys_addr_t base;
+};
+
+static int pm8916_pon_reboot_mode_get(struct udevice *dev, u32 *rebootmode)
+{
+ struct pm8916_pon_reboot_mode_priv *priv = dev_get_priv(dev);
+ int reg;
+ uint mask = GENMASK(7, GEN1_REASON_SHIFT);
+
+ reg = pmic_reg_read(priv->pmic, priv->base + PON_SOFT_RB_SPARE);
+ if (reg < 0) {
+ dev_warn(dev, "Failed to read PON_SOFT_RB_SPARE: %d\n", reg);
+ return reg;
+ }
+
+ *rebootmode = (reg & mask) >> GEN1_REASON_SHIFT;
+
+ return 0;
+}
+
+static int pm8916_pon_reboot_mode_set(struct udevice *dev, u32 rebootmode)
+{
+ struct pm8916_pon_reboot_mode_priv *priv = dev_get_priv(dev);
+ uint mask = GENMASK(7, GEN1_REASON_SHIFT);
+ int ret;
+
+ ret = pmic_clrsetbits(priv->pmic, priv->base + PON_SOFT_RB_SPARE, mask,
+ rebootmode << GEN1_REASON_SHIFT);
+ if (ret) {
+ dev_warn(dev, "Failed to write PON_SOFT_RB_SPARE: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct reboot_mode_ops pm8916_pon_reboot_mode_ops = {
+ .get = pm8916_pon_reboot_mode_get,
+ .set = pm8916_pon_reboot_mode_set,
+};
+
+static int pm8916_pon_reboot_mode_probe(struct udevice *dev)
+{
+ struct pm8916_pon_reboot_mode_priv *priv = dev_get_priv(dev);
+ struct udevice *pon = dev_get_parent(dev);
+ fdt_addr_t base;
+
+ /* this driver only works as a child of pm8916_pon */
+ if (!pon || !pon->driver || strcmp(pon->driver->name, "pm8916_pon"))
+ return -EINVAL;
+
+ priv->pmic = dev_get_parent(pon);
+ if (!priv->pmic) {
+ dev_err(dev, "PMIC driver not found\n");
+ return -EINVAL;
+ }
+
+ base = dev_read_addr(pon);
+ if (base == FDT_ADDR_T_NONE) {
+ dev_err(dev, "missing PON reg base\n");
+ return -EINVAL;
+ }
+ priv->base = base;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(pm8916_pon_reboot_mode) = {
+ .name = "pm8916_pon_reboot_mode",
+ .id = UCLASS_REBOOT_MODE,
+ .probe = pm8916_pon_reboot_mode_probe,
+ .ops = &pm8916_pon_reboot_mode_ops,
+ .priv_auto = sizeof(struct pm8916_pon_reboot_mode_priv),
+};
--
2.54.0
More information about the U-Boot
mailing list