Based on snooping around the linux kernel rk8xx driver. Tested on an ASUS C201.
Signed-off-by: Urja Rannikko <urja...@gmail.com> --- drivers/power/pmic/Kconfig | 1 + drivers/power/pmic/rk8xx.c | 62 +++++++++++++++++++++++++++++++++++--- include/power/rk8xx_pmic.h | 4 +++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 5c6c045fad..d95f9aeafb 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -124,6 +124,7 @@ config PMIC_PM8916 config PMIC_RK8XX bool "Enable support for Rockchip PMIC RK8XX" depends on DM_PMIC + select SYSRESET_CMD_POWEROFF if CMD_POWEROFF ---help--- The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, an RTC and two low Rds (resistance (drain to source)) switches. It is diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index 25c339ab12..52e41051ae 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -6,6 +6,9 @@ #include <common.h> #include <dm.h> +#include <sysreset.h> +#include <dm/device.h> +#include <dm/lists.h> #include <errno.h> #include <power/rk8xx_pmic.h> #include <power/pmic.h> @@ -49,9 +52,9 @@ static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len) return 0; } -#if CONFIG_IS_ENABLED(PMIC_CHILDREN) static int rk8xx_bind(struct udevice *dev) { +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) ofnode regulators_node; int children; @@ -68,10 +71,15 @@ static int rk8xx_bind(struct udevice *dev) if (!children) debug("%s: %s - no child found\n", __func__, dev->name); +#endif + + if (CONFIG_IS_ENABLED(SYSRESET)) + return device_bind_driver(dev, "rk8xx-sysreset", + "rk8xx-sysreset", NULL); + /* Always return success for this device */ return 0; } -#endif static int rk8xx_probe(struct udevice *dev) { @@ -103,10 +111,56 @@ U_BOOT_DRIVER(pmic_rk8xx) = { .name = "rk8xx pmic", .id = UCLASS_PMIC, .of_match = rk8xx_ids, -#if CONFIG_IS_ENABLED(PMIC_CHILDREN) .bind = rk8xx_bind, -#endif .priv_auto_alloc_size = sizeof(struct rk8xx_priv), .probe = rk8xx_probe, .ops = &rk8xx_ops, }; + +#if IS_ENABLED(CONFIG_SYSRESET) +/* NOTE: Should only enable this function if the rockchip,system-power-manager + * property is in the device tree node, but it is there in every board that has + * an rk8xx in u-boot currently, so this is left as an excercise for later. + */ +static int rk8xx_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct udevice *pmic_dev; + struct rk8xx_priv *priv; + int ret; + u8 bits; + + if (type != SYSRESET_POWER_OFF) + return -EPROTONOSUPPORT; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_rk8xx), + &pmic_dev); + + if (ret) + return -EOPNOTSUPP; + + priv = dev_get_priv(pmic_dev); + + if (priv->variant == RK818_ID) + bits = DEV_OFF; + else + bits = DEV_OFF_RST; + + ret = pmic_clrsetbits(pmic_dev, REG_DEVCTRL, 0, bits); + + if (ret < 0) + return ret; + + return -EINPROGRESS; +} + +static struct sysreset_ops rk8xx_sysreset_ops = { + .request = rk8xx_sysreset_request, +}; + +U_BOOT_DRIVER(rk8xx_sysreset) = { + .name = "rk8xx-sysreset", + .id = UCLASS_SYSRESET, + .ops = &rk8xx_sysreset_ops, +}; +#endif diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h index c06248f751..565b35985e 100644 --- a/include/power/rk8xx_pmic.h +++ b/include/power/rk8xx_pmic.h @@ -177,6 +177,10 @@ enum { #define RK8XX_ID_MSK 0xfff0 +/* DEVCTRL bits for poweroff */ +#define DEV_OFF_RST BIT(3) +#define DEV_OFF BIT(0) + struct rk8xx_reg_table { char *name; u8 reg_ctl; -- 2.21.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot