diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2018-01-05 12:08:20 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2018-01-05 12:08:20 +0100 |
commit | 4797aa72b8e4f7696627f2459a0732d1ca51b37d (patch) | |
tree | d59f35402120e399fbb54b985c329d0d2d0cbd8f | |
parent | 3dbe78ab5c0be677b142a6c111942557ba761f1c (diff) | |
parent | a41fc5eba7719dad32e1024a0b1743cbbce3def3 (diff) | |
download | barebox-4797aa72b8e4f7696627f2459a0732d1ca51b37d.tar.gz barebox-4797aa72b8e4f7696627f2459a0732d1ca51b37d.tar.xz |
Merge branch 'for-next/wd'
-rw-r--r-- | arch/mips/dts/ar9331.dtsi | 6 | ||||
-rw-r--r-- | arch/mips/dts/ar9344-tl-wdr4300-v1.7.dts | 4 | ||||
-rw-r--r-- | arch/mips/dts/ar9344.dtsi | 7 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 6 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/ar9344_wdt.c | 138 |
6 files changed, 162 insertions, 0 deletions
diff --git a/arch/mips/dts/ar9331.dtsi b/arch/mips/dts/ar9331.dtsi index b4b8b766b9..42baae1e89 100644 --- a/arch/mips/dts/ar9331.dtsi +++ b/arch/mips/dts/ar9331.dtsi @@ -1,5 +1,11 @@ / { ahb { + wdt0: wdt@18060008 { + compatible = "qca,ar9331-wdt", "qca,ar9344-wdt"; + reg = <0x18060008 0x8>; + clocks = <&pll ATH79_CLK_CPU>; + }; + mac0: mac@19000000 { compatible = "qca,ar9331-ge0"; reg = <0x18070000 0x00000100>, diff --git a/arch/mips/dts/ar9344-tl-wdr4300-v1.7.dts b/arch/mips/dts/ar9344-tl-wdr4300-v1.7.dts index d16cab0052..5216cdc1e2 100644 --- a/arch/mips/dts/ar9344-tl-wdr4300-v1.7.dts +++ b/arch/mips/dts/ar9344-tl-wdr4300-v1.7.dts @@ -38,6 +38,10 @@ clock-frequency = <40000000>; }; +&wdt0 { + status = "okay"; +}; + &spi { num-chipselects = <1>; status = "okay"; diff --git a/arch/mips/dts/ar9344.dtsi b/arch/mips/dts/ar9344.dtsi index 0a7171b8dc..009ff6f87a 100644 --- a/arch/mips/dts/ar9344.dtsi +++ b/arch/mips/dts/ar9344.dtsi @@ -58,6 +58,13 @@ #clock-cells = <1>; }; + wdt0: wdt@18060008 { + compatible = "qca,ar9344-wdt"; + reg = <0x18060008 0x8>; + clocks = <&pll ATH79_CLK_CPU>; + status = "disabled"; + }; + spi: spi@1f000000 { compatible = "qca,ar7100-spi", "qca,ar9344-spi"; reg = <0x1f000000 0x1c>; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 83b6528a5f..a8f9492ac3 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -10,6 +10,12 @@ menuconfig WATCHDOG if WATCHDOG +config WATCHDOG_AR9344 + bool "QCA AR9344" + depends on SOC_QCA_AR9344 || SOC_QCA_AR9331 + help + Add support for watchdog on the QCA AR9344 SoC. + config WATCHDOG_DAVINCI bool "TI Davinci" depends on ARCH_DAVINCI diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index a3b26675ce..c607f75090 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_WATCHDOG) += wd_core.o +obj-$(CONFIG_WATCHDOG_AR9344) += ar9344_wdt.o obj-$(CONFIG_WATCHDOG_DAVINCI) += davinci_wdt.o obj-$(CONFIG_WATCHDOG_OMAP) += omap_wdt.o obj-$(CONFIG_WATCHDOG_MXS28) += im28wd.o diff --git a/drivers/watchdog/ar9344_wdt.c b/drivers/watchdog/ar9344_wdt.c new file mode 100644 index 0000000000..d570cb40fd --- /dev/null +++ b/drivers/watchdog/ar9344_wdt.c @@ -0,0 +1,138 @@ +/* + * AR9344 Watchdog driver + * + * Copyright (C) 2017 Oleksij Rempel <linux@rempel-privat.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <common.h> +#include <errno.h> +#include <init.h> +#include <io.h> +#include <linux/clk.h> +#include <of.h> +#include <reset_source.h> +#include <watchdog.h> + +#define AR9344_WD_REG_CTRL 0x00 +#define AR9344_WD_CTRL_LAST_RESET BIT(31) +#define AR9344_WD_CTRL_ACTION_MASK 3 +#define AR9344_WD_CTRL_ACTION_NONE 0 /* no action */ +#define AR9344_WD_CTRL_ACTION_GPI 1 /* general purpose interrupt */ +#define AR9344_WD_CTRL_ACTION_NMI 2 /* NMI */ +#define AR9344_WD_CTRL_ACTION_FCR 3 /* full chip reset */ + +#define AR9344_WD_REG_TIMER 0x04 + +#define to_ar9344_wd(h) container_of(h, struct ar9344_wd, wd) + +struct ar9344_wd { + struct watchdog wd; + void __iomem *base; + struct clk *clk; + struct device_d *dev; +}; + +static int ar9344_watchdog_set_timeout(struct watchdog *wd, unsigned timeout) +{ + struct ar9344_wd *priv = to_ar9344_wd(wd); + u32 val, ctrl, rate, max_timout; + + rate = clk_get_rate(priv->clk); + max_timout = U32_MAX / rate; + + if (timeout > max_timout) { + dev_err(priv->dev, "timeout value out of range: %d > %d\n", + timeout, max_timout); + return -EINVAL; + } + + if (timeout) { + ctrl = AR9344_WD_CTRL_ACTION_FCR; + val = timeout * rate; + } else { + ctrl = AR9344_WD_CTRL_ACTION_NONE; + val = U32_MAX; + } + + dev_dbg(priv->dev, "%s: %d, timer:%x, ctrl: %x \n", __func__, + timeout, val, ctrl); + + iowrite32be(val, priv->base + AR9344_WD_REG_TIMER); + iowrite32be(ctrl, priv->base + AR9344_WD_REG_CTRL); + + return 0; +} + +static void ar9344_watchdog_detect_reset_source(struct ar9344_wd *priv) +{ + u32 val = readw(priv->base + AR9344_WD_REG_CTRL); + + if (val & AR9344_WD_CTRL_LAST_RESET) + reset_source_set(RESET_WDG); + + /* else keep the default 'unknown' state */ +} + +static int ar9344_wdt_probe(struct device_d *dev) +{ + struct resource *iores; + struct ar9344_wd *priv; + int ret; + + priv = xzalloc(sizeof(struct ar9344_wd)); + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) { + dev_err(dev, "could not get memory region\n"); + ret = PTR_ERR(iores); + goto on_error; + } + + priv->base = IOMEM(iores->start); + priv->wd.set_timeout = ar9344_watchdog_set_timeout; + priv->wd.dev = dev; + priv->dev = dev; + + dev->priv = priv; + + ar9344_watchdog_detect_reset_source(priv); + + priv->clk = clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "could not get clk\n"); + ret = PTR_ERR(priv->clk); + goto on_error; + } + + clk_enable(priv->clk); + + ret = watchdog_register(&priv->wd); + if (ret) + goto on_error; + + return 0; + +on_error: + free(priv); + return ret; +} + +static __maybe_unused struct of_device_id ar9344_wdt_dt_ids[] = { + { + .compatible = "qca,ar9344-wdt", + }, { + /* sentinel */ + } +}; + +static struct driver_d ar9344_wdt_driver = { + .name = "ar9344-wdt", + .probe = ar9344_wdt_probe, + .of_compatible = DRV_OF_COMPAT(ar9344_wdt_dt_ids), +}; +device_platform_driver(ar9344_wdt_driver); |