Thread (13 messages) read the whole thread 13 messages, 4 authors, 2013-10-31

Re: [PATCH V4 3/3] watchdog: s3c2410_wdt: use syscon regmap interface to configure pmu register

From: Leela Krishna Amudala <hidden>
Date: 2013-10-31 05:31:48
Also in: linux-samsung-soc, linux-watchdog

Hi Tomasz,

On Wed, Oct 30, 2013 at 8:09 PM, Tomasz Figa [off-list ref] wrote:
Hi Leela,

On Wednesday 30 of October 2013 15:21:13 Leela Krishna Amudala wrote:
quoted
The syscon regmap interface is used to configure AUTOMATIC_WDT_RESET_DISABLE
and MASK_WDT_RESET_REQUEST registers of PMU to mask/unmask enable/disable of
watchdog in probe and s2r scenarios.

Signed-off-by: Leela Krishna Amudala <redacted>
---
 .../devicetree/bindings/watchdog/samsung-wdt.txt   |   19 +++-
 drivers/watchdog/s3c2410_wdt.c                     |  112 ++++++++++++++++++--
 2 files changed, 122 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
index 2aa486c..5a9889b 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
@@ -5,10 +5,27 @@ after a preset amount of time during which the WDT reset event has not
 occurred.

 Required properties:
-- compatible : should be "samsung,s3c2410-wdt"
+- compatible : should be one among the following
+     (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs
+     (b) "samsung,exynos5250-wdt" for Exynos5250
+     (c) "samsung,exynos5420-wdt" for Exynos5420
+
 - reg : base physical address of the controller and length of memory mapped
      region.
 - interrupts : interrupt number to the cpu.
+- samsung,pmusysreg : reference node to pmu sysreg (required only in case of Exynos5250 and 5420)
I don't really like the name of this property. Maybe
samsung,syscon-phandle would be better?
Okay, changed.
I'm not sure if this property should be tied to PMU, as on future SoCs
those registers might be located in another syscon-style IP. The
description should note that in case of Exynos 5250 and 5420 this should
point to the PMU node, though.
Added
quoted
 Optional properties:
 - timeout-sec : contains the watchdog timeout in seconds.
+
+Example:
+
+watchdog@101D0000 {
+     compatible = "samsung,exynos5250-wdt";
+     reg = <0x101D0000 0x100>;
+     interrupts = <0 42 0>;
+     clocks = <&clock 336>;
+     clock-names = "watchdog";
+     samsung,sysreg = <&pmu_sys_reg>;
+     status = "okay";
+};
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 23aad7c..d8aefef 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -41,6 +41,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>

 #define S3C2410_WTCON                0x00
 #define S3C2410_WTDAT                0x04
@@ -61,6 +63,10 @@
 #define CONFIG_S3C2410_WATCHDOG_ATBOOT               (0)
 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)

+#define WDT_DISABLE_REG_OFFSET               0x0408
+#define WDT_MASK_RESET_REG_OFFSET    0x040c
+#define QUIRK_NEEDS_PMU_CONFIG               (1 << 0)
+
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int tmr_margin;
 static int tmr_atboot        = CONFIG_S3C2410_WATCHDOG_ATBOOT;
@@ -84,6 +90,12 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
                      "0 to reboot (default 0)");
 MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");

+struct pmu_config {
For the sake of future extensibility I'd rename this struct to
s3c2410_wdt_variant and add an u32 quirks field, which would has
the QUIRK_NEEDS_PMU_CONFIG set for 5250 and 5420 variants.
Modified
quoted
+     int     disable_reg;
+     int     mask_reset_reg;
+     int     mask_bit;
+};
+
 struct s3c2410_wdt {
      struct device           *dev;
      struct clk              *clock;
@@ -94,7 +106,34 @@ struct s3c2410_wdt {
      unsigned long           wtdat_save;
      struct watchdog_device  wdt_device;
      struct notifier_block   freq_transition;
+     struct pmu_config       *wdt_pmu_config;
+     struct regmap           *pmureg;
+     unsigned int            quirks;
Quirks should be a static per-variant property.
Taken care
quoted
+};
+
+#ifdef CONFIG_OF
+static struct pmu_config pmu_config_5250  = {
+     .disable_reg = WDT_DISABLE_REG_OFFSET,
+     .mask_reset_reg = WDT_MASK_RESET_REG_OFFSET,
+     .mask_bit = 20
+};
+
+static struct pmu_config pmu_config_5420 = {
+     .disable_reg = WDT_DISABLE_REG_OFFSET,
+     .mask_reset_reg = WDT_MASK_RESET_REG_OFFSET,
+     .mask_bit = 0
+};
+
+static const struct of_device_id s3c2410_wdt_match[] = {
+     { .compatible = "samsung,s3c2410-wdt" },
If you follow what I suggested above, the basic variant would also have
a variant struct associated with it, which would be more consistent.
quoted
+     { .compatible = "samsung,exynos5250-wdt",
+       .data = (struct pmu_config *) &pmu_config_5250 },
+     { .compatible = "samsung,exynos5420-wdt",
+       .data = (struct pmu_config *) &pmu_config_5420 },
+     {},
 };
+MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
+#endif

 /* watchdog control routines */
@@ -111,6 +150,38 @@ static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb)
      return container_of(nb, struct s3c2410_wdt, freq_transition);
 }

+static void s3c2410wdt_mask_and_disable_reset(int mask, struct s3c2410_wdt *wdt)
+{
+     unsigned int disable, mask_reset;
+     int ret;
+
+     ret = regmap_read(wdt->pmureg, wdt->wdt_pmu_config->disable_reg,
+                                                             &disable);
+     if (ret < 0) {
+             dev_err(wdt->dev, "failed to read disable reg(%d)\n", ret);
+             return;
+     }
+
+     ret = regmap_read(wdt->pmureg, wdt->wdt_pmu_config->mask_reset_reg,
+                                                             &mask_reset);
+     if (ret < 0) {
+             dev_err(wdt->dev, "failed to read mask reset reg(%d)\n", ret);
+             return;
+     }
+
+     if (mask) {
+             disable |= (1 << wdt->wdt_pmu_config->mask_bit);
+             mask_reset |= (1 << wdt->wdt_pmu_config->mask_bit);
+     } else {
+             disable &= ~(1 << wdt->wdt_pmu_config->mask_bit);
+             mask_reset &= ~(1 << wdt->wdt_pmu_config->mask_bit);
+     }
+
+     regmap_write(wdt->pmureg, wdt->wdt_pmu_config->disable_reg, disable);
+     regmap_write(wdt->pmureg, wdt->wdt_pmu_config->mask_reset_reg,
+                                                             mask_reset);
I believe you can (and on some SoCs even have to, due to other bits in the
registers being used for other purposes) use regmap_update_bits() for
read-modify-write sequences above.
Okay, Modified
quoted
+}
+
 static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
 {
      struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
@@ -332,6 +403,14 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 }
 #endif

+/* s3c2410_get_wdt_driver_data */
+static inline unsigned int get_wdt_driver_data(struct platform_device *pdev)
+{
+     const struct of_device_id *match;
+     match = of_match_node(s3c2410_wdt_match, pdev->dev.of_node);
+     return (unsigned int)match->data;
Why do you need this cast? I believe this function should simply return
(const struct pmu_config *) or (const struct s3c2410_wdt_variant *) when
my comments above get addressed.
My mistake, Changed
quoted
+}
+
 static int s3c2410wdt_probe(struct platform_device *pdev)
 {
      struct device *dev;
@@ -354,6 +433,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
      spin_lock_init(&wdt->lock);
      wdt->wdt_device = s3c2410_wdd;

+     wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                             "samsung,pmusysreg");
+     if (IS_ERR(wdt->pmureg)) {
+             dev_err(dev, "syscon regmap lookup failed.\n");
+             return PTR_ERR(wdt->pmureg);
+     }
This should be performed only if given variant has the
QUIRK_NEEDS_PMU_CONFIG flag set in its variant data. Otherwise you don't
have any distinction between cases when PMU is not needed (and so
unspecified) and PMU is needed, but unspecified.
Okay, Taken care
quoted
+
+     wdt->wdt_pmu_config = (struct pmu_config *) get_wdt_driver_data(pdev);
+     if (wdt->wdt_pmu_config)
+             wdt->quirks = QUIRK_NEEDS_PMU_CONFIG;
See my comment on quirks above.
quoted
+
      wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
      if (wdt_irq == NULL) {
              dev_err(dev, "no irq resource specified\n");
@@ -444,6 +534,8 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
               (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis",
               (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis");

+     if (wdt->quirks & QUIRK_NEEDS_PMU_CONFIG)
+             s3c2410wdt_mask_and_disable_reset(0, wdt);
nit: Blank line here would be nice.
Done.

Best Wishes,
Leela Krishna
Best regards,
Tomasz

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help