Hi, On Sat, Jun 26, 2021 at 12:47:44AM +0200, Emil Renner Berthing wrote: > The only way to reset the BeagleV Starlight v0.9 board[1] properly is to > tell the PMIC to reset itself which will then assert the external reset > lines of the SoC, USB hub and ethernet phy. > > This adds a driver to register a reset handler to do just that. > > [1] https://github.com/beagleboard/beaglev-starlight > > Signed-off-by: Emil Renner Berthing > --- Acked-by: Sebastian Reichel -- Sebastian > drivers/mfd/tps65086.c | 1 + > drivers/power/reset/Kconfig | 6 ++ > drivers/power/reset/Makefile | 1 + > drivers/power/reset/tps65086-restart.c | 99 ++++++++++++++++++++++++++ > 4 files changed, 107 insertions(+) > create mode 100644 drivers/power/reset/tps65086-restart.c > > diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c > index cc3478ee9a64..1bfba0758fcc 100644 > --- a/drivers/mfd/tps65086.c > +++ b/drivers/mfd/tps65086.c > @@ -24,6 +24,7 @@ > static const struct mfd_cell tps65086_cells[] = { > { .name = "tps65086-regulator", }, > { .name = "tps65086-gpio", }, > + { .name = "tps65086-restart", }, > }; > > static const struct regmap_range tps65086_yes_ranges[] = { > diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig > index 4d1192062508..4b563db3ab3e 100644 > --- a/drivers/power/reset/Kconfig > +++ b/drivers/power/reset/Kconfig > @@ -204,6 +204,12 @@ config POWER_RESET_ST > help > Reset support for STMicroelectronics boards. > > +config POWER_RESET_TPS65086 > + bool "TPS65086 restart driver" > + depends on MFD_TPS65086 > + help > + This driver adds support for resetting the TPS65086 PMIC on restart. > + > config POWER_RESET_VERSATILE > bool "ARM Versatile family reboot driver" > depends on ARM > diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile > index cf3f4d02d8a5..f606a2f60539 100644 > --- a/drivers/power/reset/Makefile > +++ b/drivers/power/reset/Makefile > @@ -23,6 +23,7 @@ obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o > obj-$(CONFIG_POWER_RESET_REGULATOR) += regulator-poweroff.o > obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o > obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o > +obj-$(CONFIG_POWER_RESET_TPS65086) += tps65086-restart.o > obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o > obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o > obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o > diff --git a/drivers/power/reset/tps65086-restart.c b/drivers/power/reset/tps65086-restart.c > new file mode 100644 > index 000000000000..ad9f2c5a84ac > --- /dev/null > +++ b/drivers/power/reset/tps65086-restart.c > @@ -0,0 +1,99 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2021 Emil Renner Berthing > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +struct tps65086_restart { > + struct notifier_block handler; > + struct tps65086 *tps; > + struct device *dev; > +}; > + > +static int tps65086_restart_notify(struct notifier_block *this, > + unsigned long mode, void *cmd) > +{ > + struct tps65086_restart *tps65086_restart = > + container_of(this, struct tps65086_restart, handler); > + int ret; > + > + ret = regmap_write(tps65086_restart->tps->regmap, TPS65086_FORCESHUTDN, 1); > + if (ret) { > + dev_err(tps65086_restart->dev, "%s: error writing to tps65086 pmic: %d\n", > + __func__, ret); > + return NOTIFY_DONE; > + } > + > + /* give it a little time */ > + mdelay(200); > + > + WARN_ON(1); > + > + return NOTIFY_DONE; > +} > + > +static int tps65086_restart_probe(struct platform_device *pdev) > +{ > + struct tps65086_restart *tps65086_restart; > + int ret; > + > + tps65086_restart = devm_kzalloc(&pdev->dev, sizeof(*tps65086_restart), GFP_KERNEL); > + if (!tps65086_restart) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, tps65086_restart); > + > + tps65086_restart->handler.notifier_call = tps65086_restart_notify; > + tps65086_restart->handler.priority = 192; > + tps65086_restart->tps = dev_get_drvdata(pdev->dev.parent); > + tps65086_restart->dev = &pdev->dev; > + > + ret = register_restart_handler(&tps65086_restart->handler); > + if (ret) { > + dev_err(&pdev->dev, "%s: cannot register restart handler: %d\n", > + __func__, ret); > + return -ENODEV; > + } > + > + return 0; > +} > + > +static int tps65086_restart_remove(struct platform_device *pdev) > +{ > + struct tps65086_restart *tps65086_restart = platform_get_drvdata(pdev); > + int ret; > + > + ret = unregister_restart_handler(&tps65086_restart->handler); > + if (ret) { > + dev_err(&pdev->dev, "%s: cannot unregister restart handler: %d\n", > + __func__, ret); > + return -ENODEV; > + } > + > + return 0; > +} > + > +static const struct platform_device_id tps65086_restart_id_table[] = { > + { "tps65086-restart", }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(platform, tps65086_restart_id_table); > + > +static struct platform_driver tps65086_restart_driver = { > + .driver = { > + .name = "tps65086-restart", > + }, > + .probe = tps65086_restart_probe, > + .remove = tps65086_restart_remove, > + .id_table = tps65086_restart_id_table, > +}; > +module_platform_driver(tps65086_restart_driver); > + > +MODULE_AUTHOR("Emil Renner Berthing "); > +MODULE_DESCRIPTION("TPS65086 restart driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.32.0 >