On Wed, 29 Jun 2022 at 10:48, Stephan Gerhold <stephan.gerhold@xxxxxxxxxxxxxxx> wrote: > > The PM8916 PMIC provides "power-off reason" (POFF_REASON) registers > to allow detecting why the board was powered off or rebooted. This > can be used to expose if a reset happened due to a watchdog timeout. > The watchdog API also provides status bits for overtemperature and > undervoltage which happen to be reported in the same PMIC register. > > Make this information available as part of the watchdog device > so userspace can decide to handle the situation accordingly. > > Signed-off-by: Stephan Gerhold <stephan.gerhold@xxxxxxxxxxxxxxx> Reviewed-by: Loic Poulain <loic.poulain@xxxxxxxxxx> > --- > Changes in v2: Improve error handling (suggested by Guenter) > --- > drivers/watchdog/pm8916_wdt.c | 26 +++++++++++++++++++++++++- > 1 file changed, 25 insertions(+), 1 deletion(-) > > diff --git a/drivers/watchdog/pm8916_wdt.c b/drivers/watchdog/pm8916_wdt.c > index 670cd79f4cf9..49f1a5204526 100644 > --- a/drivers/watchdog/pm8916_wdt.c > +++ b/drivers/watchdog/pm8916_wdt.c > @@ -9,6 +9,12 @@ > #include <linux/regmap.h> > #include <linux/watchdog.h> > > +#define PON_POFF_REASON1 0x0c > +#define PON_POFF_REASON1_PMIC_WD BIT(2) > +#define PON_POFF_REASON2 0x0d > +#define PON_POFF_REASON2_UVLO BIT(5) > +#define PON_POFF_REASON2_OTST3 BIT(6) > + > #define PON_INT_RT_STS 0x10 > #define PMIC_WD_BARK_STS_BIT BIT(6) > > @@ -110,12 +116,14 @@ static irqreturn_t pm8916_wdt_isr(int irq, void *arg) > } > > static const struct watchdog_info pm8916_wdt_ident = { > - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, > + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | > + WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_POWERUNDER, > .identity = "QCOM PM8916 PON WDT", > }; > > static const struct watchdog_info pm8916_wdt_pt_ident = { > .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | > + WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_POWERUNDER | > WDIOF_PRETIMEOUT, > .identity = "QCOM PM8916 PON WDT", > }; > @@ -135,6 +143,7 @@ static int pm8916_wdt_probe(struct platform_device *pdev) > struct pm8916_wdt *wdt; > struct device *parent; > int err, irq; > + u8 poff[2]; > > wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); > if (!wdt) > @@ -175,6 +184,21 @@ static int pm8916_wdt_probe(struct platform_device *pdev) > wdt->wdev.info = &pm8916_wdt_ident; > } > > + err = regmap_bulk_read(wdt->regmap, wdt->baseaddr + PON_POFF_REASON1, > + &poff, ARRAY_SIZE(poff)); > + if (err) { > + dev_err(dev, "failed to read POFF reason: %d\n", err); > + return err; > + } > + > + dev_dbg(dev, "POFF reason: %#x %#x\n", poff[0], poff[1]); > + if (poff[0] & PON_POFF_REASON1_PMIC_WD) > + wdt->wdev.bootstatus |= WDIOF_CARDRESET; > + if (poff[1] & PON_POFF_REASON2_UVLO) > + wdt->wdev.bootstatus |= WDIOF_POWERUNDER; > + if (poff[1] & PON_POFF_REASON2_OTST3) > + wdt->wdev.bootstatus |= WDIOF_OVERHEAT; > + > /* Configure watchdog to hard-reset mode */ > err = regmap_write(wdt->regmap, > wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL, > -- > 2.30.2 >