On Thu, Sep 04, 2014 at 10:19:17AM +0100, Lee Jones wrote: > Wim, > > Still waiting on a Watchdog Ack, so I can take this set in. > Wasn't there a more recent version of this patch ? Thanks, Guenter > > This adds a driver for the watchdog timer available in Ricoh RN5T618 > > PMIC. The device supports a programmable expiration time of 1, 8, 32 > > or 128 seconds. > > > > Signed-off-by: Beniamino Galvani <b.galvani@xxxxxxxxx> > > --- > > drivers/watchdog/Kconfig | 11 +++ > > drivers/watchdog/Makefile | 1 + > > drivers/watchdog/rn5t618_wdt.c | 196 ++++++++++++++++++++++++++++++++++++++++ > > include/linux/mfd/rn5t618.h | 4 + > > 4 files changed, 212 insertions(+) > > create mode 100644 drivers/watchdog/rn5t618_wdt.c > > > > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig > > index f57312f..9eba6af 100644 > > --- a/drivers/watchdog/Kconfig > > +++ b/drivers/watchdog/Kconfig > > @@ -309,6 +309,17 @@ config ORION_WATCHDOG > > To compile this driver as a module, choose M here: the > > module will be called orion_wdt. > > > > +config RN5T618_WATCHDOG > > + tristate "Ricoh RN5T618 watchdog" > > + depends on MFD_RN5T618 > > + select WATCHDOG_CORE > > + help > > + If you say yes here you get support for watchdog on the Ricoh > > + RN5T618 PMIC. > > + > > + This driver can also be built as a module. If so, the module > > + will be called rn5t618_wdt. > > + > > config SUNXI_WATCHDOG > > tristate "Allwinner SoCs watchdog support" > > depends on ARCH_SUNXI > > diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile > > index 468c320..0afa343 100644 > > --- a/drivers/watchdog/Makefile > > +++ b/drivers/watchdog/Makefile > > @@ -47,6 +47,7 @@ obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o > > obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o > > obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o > > obj-$(CONFIG_SUNXI_WATCHDOG) += sunxi_wdt.o > > +obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o > > obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o > > obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o > > obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o > > diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c > > new file mode 100644 > > index 0000000..3a76ad7 > > --- /dev/null > > +++ b/drivers/watchdog/rn5t618_wdt.c > > @@ -0,0 +1,196 @@ > > +/* > > + * Watchdog driver for Ricoh RN5T618 PMIC > > + * > > + * Copyright (C) 2014 Beniamino Galvani <b.galvani@xxxxxxxxx> > > + * > > + * This program is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU General Public License > > + * version 2 as published by the Free Software Foundation. > > + * > > + * You should have received a copy of the GNU General Public License > > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > > + */ > > + > > +#include <linux/device.h> > > +#include <linux/mfd/rn5t618.h> > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/watchdog.h> > > + > > +#define DRIVER_NAME "rn5t618-wdt" > > + > > +static bool nowayout = WATCHDOG_NOWAYOUT; > > +static unsigned int heartbeat = -1; > > + > > +module_param(heartbeat, int, 0); > > +MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds"); > > + > > +module_param(nowayout, bool, 0); > > +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" > > + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); > > + > > +struct rn5t618_wdt { > > + struct watchdog_device wdt_dev; > > + struct rn5t618 *rn5t618; > > +}; > > + > > +/* > > + * This array encodes the values of WDOGTIM field for the supported > > + * watchdog expiration times. If the watchdog is not accessed before > > + * the timer expiration, the PMU generates an interrupt and if the CPU > > + * doesn't clear it within one second the system is restarted. > > + */ > > +static const struct { > > + u8 reg_val; > > + int time; > > +} rn5t618_wdt_map[] = { > > + { 0, 1 }, > > + { 1, 8 }, > > + { 2, 32 }, > > + { 3, 128 }, > > +}; > > + > > +static int rn5t618_wdt_set_timeout(struct watchdog_device *wdt_dev, > > + unsigned int timeout) > > +{ > > + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); > > + int ret, i; > > + > > + for (i = 0; i < ARRAY_SIZE(rn5t618_wdt_map); i++) { > > + if (rn5t618_wdt_map[i].time + 1 >= timeout) > > + break; > > + } > > + > > + if (i == ARRAY_SIZE(rn5t618_wdt_map)) > > + ret = -EINVAL; > > + else > > + ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG, > > + RN5T618_WATCHDOG_WDOGTIM_M, > > + rn5t618_wdt_map[i].reg_val); > > + if (!ret) > > + wdt_dev->timeout = rn5t618_wdt_map[i].time; > > + > > + return ret; > > +} > > + > > +static int rn5t618_wdt_start(struct watchdog_device *wdt_dev) > > +{ > > + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); > > + int ret; > > + > > + ret = rn5t618_wdt_set_timeout(wdt_dev, wdt_dev->timeout); > > + if (ret) > > + return ret; > > + > > + /* enable repower-on */ > > + ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_REPCNT, > > + RN5T618_REPCNT_REPWRON, > > + RN5T618_REPCNT_REPWRON); > > + if (ret) > > + return ret; > > + > > + /* enable watchdog */ > > + ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG, > > + RN5T618_WATCHDOG_WDOGEN, > > + RN5T618_WATCHDOG_WDOGEN); > > + if (ret) > > + return ret; > > + > > + /* enable watchdog interrupt */ > > + return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_PWRIREN, > > + RN5T618_PWRIRQ_IR_WDOG, > > + RN5T618_PWRIRQ_IR_WDOG); > > +} > > + > > +static int rn5t618_wdt_stop(struct watchdog_device *wdt_dev) > > +{ > > + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); > > + > > + return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG, > > + RN5T618_WATCHDOG_WDOGEN, 0); > > +} > > + > > +static int rn5t618_wdt_ping(struct watchdog_device *wdt_dev) > > +{ > > + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); > > + unsigned int val; > > + int ret; > > + > > + /* The counter is restarted after a R/W access to watchdog register */ > > + ret = regmap_read(wdt->rn5t618->regmap, RN5T618_WATCHDOG, &val); > > + if (ret) > > + return ret; > > + > > + ret = regmap_write(wdt->rn5t618->regmap, RN5T618_WATCHDOG, val); > > + if (ret) > > + return ret; > > + > > + /* Clear pending watchdog interrupt */ > > + return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_PWRIRQ, > > + RN5T618_PWRIRQ_IR_WDOG, 0); > > +} > > + > > +static struct watchdog_info rn5t618_wdt_info = { > > + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | > > + WDIOF_KEEPALIVEPING, > > + .identity = DRIVER_NAME, > > +}; > > + > > +static struct watchdog_ops rn5t618_wdt_ops = { > > + .owner = THIS_MODULE, > > + .start = rn5t618_wdt_start, > > + .stop = rn5t618_wdt_stop, > > + .ping = rn5t618_wdt_ping, > > + .set_timeout = rn5t618_wdt_set_timeout, > > +}; > > + > > +static int rn5t618_wdt_probe(struct platform_device *pdev) > > +{ > > + struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); > > + struct rn5t618_wdt *wdt; > > + int min_timeout, max_timeout; > > + > > + wdt = devm_kzalloc(&pdev->dev, sizeof(struct rn5t618_wdt), GFP_KERNEL); > > + if (!wdt) > > + return -ENOMEM; > > + > > + min_timeout = rn5t618_wdt_map[0].time; > > + max_timeout = rn5t618_wdt_map[ARRAY_SIZE(rn5t618_wdt_map) - 1].time; > > + > > + wdt->rn5t618 = rn5t618; > > + wdt->wdt_dev.info = &rn5t618_wdt_info; > > + wdt->wdt_dev.ops = &rn5t618_wdt_ops; > > + wdt->wdt_dev.min_timeout = min_timeout; > > + wdt->wdt_dev.max_timeout = max_timeout; > > + wdt->wdt_dev.timeout = max_timeout; > > + wdt->wdt_dev.parent = &pdev->dev; > > + > > + watchdog_set_drvdata(&wdt->wdt_dev, wdt); > > + watchdog_init_timeout(&wdt->wdt_dev, heartbeat, &pdev->dev); > > + watchdog_set_nowayout(&wdt->wdt_dev, nowayout); > > + > > + return watchdog_register_device(&wdt->wdt_dev); > > +} > > + > > +static int rn5t618_wdt_remove(struct platform_device *pdev) > > +{ > > + struct watchdog_device *wdt_dev = platform_get_drvdata(pdev); > > + > > + watchdog_unregister_device(wdt_dev); > > + > > + return 0; > > +} > > + > > +static struct platform_driver rn5t618_wdt_driver = { > > + .probe = rn5t618_wdt_probe, > > + .remove = rn5t618_wdt_remove, > > + .driver = { > > + .name = DRIVER_NAME, > > + }, > > +}; > > + > > +module_platform_driver(rn5t618_wdt_driver); > > + > > +MODULE_AUTHOR("Beniamino Galvani <b.galvani@xxxxxxxxx>"); > > +MODULE_DESCRIPTION("RN5T618 watchdog driver"); > > +MODULE_LICENSE("GPL v2"); > > diff --git a/include/linux/mfd/rn5t618.h b/include/linux/mfd/rn5t618.h > > index e3571d1..c72d534 100644 > > --- a/include/linux/mfd/rn5t618.h > > +++ b/include/linux/mfd/rn5t618.h > > @@ -202,6 +202,10 @@ > > > > #define RN5T618_REPCNT_REPWRON BIT(0) > > #define RN5T618_SLPCNT_SWPWROFF BIT(0) > > +#define RN5T618_WATCHDOG_WDOGEN BIT(2) > > +#define RN5T618_WATCHDOG_WDOGTIM_M (BIT(0) | BIT(1)) > > +#define RN5T618_WATCHDOG_WDOGTIM_S 0 > > +#define RN5T618_PWRIRQ_IR_WDOG BIT(6) > > > > enum { > > RN5T618_DCDC1, > > -- > Lee Jones > Linaro STMicroelectronics Landing Team Lead > Linaro.org │ Open source software for ARM SoCs > Follow Linaro: Facebook | Twitter | Blog > -- > To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html