010-5-watchdog-qcom-add-option-for-standalone-watchdog-not-in-timer-block.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. From f0d9d0f4b44ae5503ea368e7f066b20f12ca1d37 Mon Sep 17 00:00:00 2001
  2. From: Matthew McClintock <mmcclint@codeaurora.org>
  3. Date: Wed, 29 Jun 2016 10:50:01 -0700
  4. Subject: watchdog: qcom: add option for standalone watchdog not in timer block
  5. Commit 0dfd582e026a ("watchdog: qcom: use timer devicetree
  6. binding") moved to use the watchdog as a subset timer
  7. register block. Some devices have the watchdog completely
  8. standalone with slightly different register offsets as
  9. well so let's account for the differences here.
  10. The existing "kpss-standalone" compatible string doesn't
  11. make it entirely clear exactly what the device is so
  12. rename to "kpss-wdt" to reflect watchdog timer
  13. functionality. Also update ipq4019 DTS with an SoC
  14. specific compatible.
  15. Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
  16. Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
  17. Reviewed-by: Guenter Roeck <linux@roeck-us.net>
  18. Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  19. Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
  20. ---
  21. .../devicetree/bindings/watchdog/qcom-wdt.txt | 2 +
  22. arch/arm/boot/dts/qcom-ipq4019.dtsi | 2 +-
  23. drivers/watchdog/qcom-wdt.c | 64 ++++++++++++++++------
  24. 3 files changed, 51 insertions(+), 17 deletions(-)
  25. --- a/drivers/watchdog/qcom-wdt.c
  26. +++ b/drivers/watchdog/qcom-wdt.c
  27. @@ -18,19 +18,42 @@
  28. #include <linux/of.h>
  29. #include <linux/platform_device.h>
  30. #include <linux/watchdog.h>
  31. +#include <linux/of_device.h>
  32. -#define WDT_RST 0x38
  33. -#define WDT_EN 0x40
  34. -#define WDT_STS 0x44
  35. -#define WDT_BITE_TIME 0x5C
  36. +enum wdt_reg {
  37. + WDT_RST,
  38. + WDT_EN,
  39. + WDT_STS,
  40. + WDT_BITE_TIME,
  41. +};
  42. +
  43. +static const u32 reg_offset_data_apcs_tmr[] = {
  44. + [WDT_RST] = 0x38,
  45. + [WDT_EN] = 0x40,
  46. + [WDT_STS] = 0x44,
  47. + [WDT_BITE_TIME] = 0x5C,
  48. +};
  49. +
  50. +static const u32 reg_offset_data_kpss[] = {
  51. + [WDT_RST] = 0x4,
  52. + [WDT_EN] = 0x8,
  53. + [WDT_STS] = 0xC,
  54. + [WDT_BITE_TIME] = 0x14,
  55. +};
  56. struct qcom_wdt {
  57. struct watchdog_device wdd;
  58. struct clk *clk;
  59. unsigned long rate;
  60. void __iomem *base;
  61. + const u32 *layout;
  62. };
  63. +static void __iomem *wdt_addr(struct qcom_wdt *wdt, enum wdt_reg reg)
  64. +{
  65. + return wdt->base + wdt->layout[reg];
  66. +}
  67. +
  68. static inline
  69. struct qcom_wdt *to_qcom_wdt(struct watchdog_device *wdd)
  70. {
  71. @@ -41,10 +64,10 @@ static int qcom_wdt_start(struct watchdo
  72. {
  73. struct qcom_wdt *wdt = to_qcom_wdt(wdd);
  74. - writel(0, wdt->base + WDT_EN);
  75. - writel(1, wdt->base + WDT_RST);
  76. - writel(wdd->timeout * wdt->rate, wdt->base + WDT_BITE_TIME);
  77. - writel(1, wdt->base + WDT_EN);
  78. + writel(0, wdt_addr(wdt, WDT_EN));
  79. + writel(1, wdt_addr(wdt, WDT_RST));
  80. + writel(wdd->timeout * wdt->rate, wdt_addr(wdt, WDT_BITE_TIME));
  81. + writel(1, wdt_addr(wdt, WDT_EN));
  82. return 0;
  83. }
  84. @@ -52,7 +75,7 @@ static int qcom_wdt_stop(struct watchdog
  85. {
  86. struct qcom_wdt *wdt = to_qcom_wdt(wdd);
  87. - writel(0, wdt->base + WDT_EN);
  88. + writel(0, wdt_addr(wdt, WDT_EN));
  89. return 0;
  90. }
  91. @@ -60,7 +83,7 @@ static int qcom_wdt_ping(struct watchdog
  92. {
  93. struct qcom_wdt *wdt = to_qcom_wdt(wdd);
  94. - writel(1, wdt->base + WDT_RST);
  95. + writel(1, wdt_addr(wdt, WDT_RST));
  96. return 0;
  97. }
  98. @@ -83,10 +106,10 @@ static int qcom_wdt_restart(struct watch
  99. */
  100. timeout = 128 * wdt->rate / 1000;
  101. - writel(0, wdt->base + WDT_EN);
  102. - writel(1, wdt->base + WDT_RST);
  103. - writel(timeout, wdt->base + WDT_BITE_TIME);
  104. - writel(1, wdt->base + WDT_EN);
  105. + writel(0, wdt_addr(wdt, WDT_EN));
  106. + writel(1, wdt_addr(wdt, WDT_RST));
  107. + writel(timeout, wdt_addr(wdt, WDT_BITE_TIME));
  108. + writel(1, wdt_addr(wdt, WDT_EN));
  109. /*
  110. * Actually make sure the above sequence hits hardware before sleeping.
  111. @@ -119,9 +142,16 @@ static int qcom_wdt_probe(struct platfor
  112. struct qcom_wdt *wdt;
  113. struct resource *res;
  114. struct device_node *np = pdev->dev.of_node;
  115. + const u32 *regs;
  116. u32 percpu_offset;
  117. int ret;
  118. + regs = of_device_get_match_data(&pdev->dev);
  119. + if (!regs) {
  120. + dev_err(&pdev->dev, "Unsupported QCOM WDT module\n");
  121. + return -ENODEV;
  122. + }
  123. +
  124. wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
  125. if (!wdt)
  126. return -ENOMEM;
  127. @@ -172,6 +202,7 @@ static int qcom_wdt_probe(struct platfor
  128. wdt->wdd.min_timeout = 1;
  129. wdt->wdd.max_timeout = 0x10000000U / wdt->rate;
  130. wdt->wdd.parent = &pdev->dev;
  131. + wdt->layout = regs;
  132. if (readl(wdt->base + WDT_STS) & 1)
  133. wdt->wdd.bootstatus = WDIOF_CARDRESET;
  134. @@ -208,8 +239,9 @@ static int qcom_wdt_remove(struct platfo
  135. }
  136. static const struct of_device_id qcom_wdt_of_table[] = {
  137. - { .compatible = "qcom,kpss-timer" },
  138. - { .compatible = "qcom,scss-timer" },
  139. + { .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr },
  140. + { .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr },
  141. + { .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss },
  142. { },
  143. };
  144. MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);