ts72xx_wdt.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Watchdog driver for Technologic Systems TS-72xx based SBCs
  3. * (TS-7200, TS-7250 and TS-7260). These boards have external
  4. * glue logic CPLD chip, which includes programmable watchdog
  5. * timer.
  6. *
  7. * Copyright (c) 2009 Mika Westerberg <mika.westerberg@iki.fi>
  8. *
  9. * This driver is based on ep93xx_wdt and wm831x_wdt drivers.
  10. *
  11. * This file is licensed under the terms of the GNU General Public
  12. * License version 2. This program is licensed "as is" without any
  13. * warranty of any kind, whether express or implied.
  14. */
  15. #include <linux/platform_device.h>
  16. #include <linux/module.h>
  17. #include <linux/watchdog.h>
  18. #include <linux/io.h>
  19. #define TS72XX_WDT_DEFAULT_TIMEOUT 30
  20. static int timeout;
  21. module_param(timeout, int, 0);
  22. MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds.");
  23. static bool nowayout = WATCHDOG_NOWAYOUT;
  24. module_param(nowayout, bool, 0);
  25. MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
  26. /* priv->control_reg */
  27. #define TS72XX_WDT_CTRL_DISABLE 0x00
  28. #define TS72XX_WDT_CTRL_250MS 0x01
  29. #define TS72XX_WDT_CTRL_500MS 0x02
  30. #define TS72XX_WDT_CTRL_1SEC 0x03
  31. #define TS72XX_WDT_CTRL_RESERVED 0x04
  32. #define TS72XX_WDT_CTRL_2SEC 0x05
  33. #define TS72XX_WDT_CTRL_4SEC 0x06
  34. #define TS72XX_WDT_CTRL_8SEC 0x07
  35. /* priv->feed_reg */
  36. #define TS72XX_WDT_FEED_VAL 0x05
  37. struct ts72xx_wdt_priv {
  38. void __iomem *control_reg;
  39. void __iomem *feed_reg;
  40. struct watchdog_device wdd;
  41. unsigned char regval;
  42. };
  43. static int ts72xx_wdt_start(struct watchdog_device *wdd)
  44. {
  45. struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
  46. writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
  47. writeb(priv->regval, priv->control_reg);
  48. return 0;
  49. }
  50. static int ts72xx_wdt_stop(struct watchdog_device *wdd)
  51. {
  52. struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
  53. writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
  54. writeb(TS72XX_WDT_CTRL_DISABLE, priv->control_reg);
  55. return 0;
  56. }
  57. static int ts72xx_wdt_ping(struct watchdog_device *wdd)
  58. {
  59. struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
  60. writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
  61. return 0;
  62. }
  63. static int ts72xx_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
  64. {
  65. struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
  66. if (to == 1) {
  67. priv->regval = TS72XX_WDT_CTRL_1SEC;
  68. } else if (to == 2) {
  69. priv->regval = TS72XX_WDT_CTRL_2SEC;
  70. } else if (to <= 4) {
  71. priv->regval = TS72XX_WDT_CTRL_4SEC;
  72. to = 4;
  73. } else {
  74. priv->regval = TS72XX_WDT_CTRL_8SEC;
  75. if (to <= 8)
  76. to = 8;
  77. }
  78. wdd->timeout = to;
  79. if (watchdog_active(wdd)) {
  80. ts72xx_wdt_stop(wdd);
  81. ts72xx_wdt_start(wdd);
  82. }
  83. return 0;
  84. }
  85. static const struct watchdog_info ts72xx_wdt_ident = {
  86. .options = WDIOF_KEEPALIVEPING |
  87. WDIOF_SETTIMEOUT |
  88. WDIOF_MAGICCLOSE,
  89. .firmware_version = 1,
  90. .identity = "TS-72XX WDT",
  91. };
  92. static const struct watchdog_ops ts72xx_wdt_ops = {
  93. .owner = THIS_MODULE,
  94. .start = ts72xx_wdt_start,
  95. .stop = ts72xx_wdt_stop,
  96. .ping = ts72xx_wdt_ping,
  97. .set_timeout = ts72xx_wdt_settimeout,
  98. };
  99. static int ts72xx_wdt_probe(struct platform_device *pdev)
  100. {
  101. struct device *dev = &pdev->dev;
  102. struct ts72xx_wdt_priv *priv;
  103. struct watchdog_device *wdd;
  104. int ret;
  105. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  106. if (!priv)
  107. return -ENOMEM;
  108. priv->control_reg = devm_platform_ioremap_resource(pdev, 0);
  109. if (IS_ERR(priv->control_reg))
  110. return PTR_ERR(priv->control_reg);
  111. priv->feed_reg = devm_platform_ioremap_resource(pdev, 1);
  112. if (IS_ERR(priv->feed_reg))
  113. return PTR_ERR(priv->feed_reg);
  114. wdd = &priv->wdd;
  115. wdd->info = &ts72xx_wdt_ident;
  116. wdd->ops = &ts72xx_wdt_ops;
  117. wdd->min_timeout = 1;
  118. wdd->max_hw_heartbeat_ms = 8000;
  119. wdd->parent = dev;
  120. watchdog_set_nowayout(wdd, nowayout);
  121. wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
  122. watchdog_init_timeout(wdd, timeout, dev);
  123. watchdog_set_drvdata(wdd, priv);
  124. ret = devm_watchdog_register_device(dev, wdd);
  125. if (ret)
  126. return ret;
  127. dev_info(dev, "TS-72xx Watchdog driver\n");
  128. return 0;
  129. }
  130. static struct platform_driver ts72xx_wdt_driver = {
  131. .probe = ts72xx_wdt_probe,
  132. .driver = {
  133. .name = "ts72xx-wdt",
  134. },
  135. };
  136. module_platform_driver(ts72xx_wdt_driver);
  137. MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
  138. MODULE_DESCRIPTION("TS-72xx SBC Watchdog");
  139. MODULE_LICENSE("GPL");
  140. MODULE_ALIAS("platform:ts72xx-wdt");