stpmic1_wdt.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) STMicroelectronics 2018
  3. // Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
  4. #include <linux/kernel.h>
  5. #include <linux/mfd/stpmic1.h>
  6. #include <linux/module.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/of.h>
  9. #include <linux/regmap.h>
  10. #include <linux/slab.h>
  11. #include <linux/watchdog.h>
  12. /* WATCHDOG CONTROL REGISTER bit */
  13. #define WDT_START BIT(0)
  14. #define WDT_PING BIT(1)
  15. #define WDT_START_MASK BIT(0)
  16. #define WDT_PING_MASK BIT(1)
  17. #define WDT_STOP 0
  18. #define PMIC_WDT_MIN_TIMEOUT 1
  19. #define PMIC_WDT_MAX_TIMEOUT 256
  20. #define PMIC_WDT_DEFAULT_TIMEOUT 30
  21. static bool nowayout = WATCHDOG_NOWAYOUT;
  22. module_param(nowayout, bool, 0);
  23. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  24. __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  25. struct stpmic1_wdt {
  26. struct stpmic1 *pmic;
  27. struct watchdog_device wdtdev;
  28. };
  29. static int pmic_wdt_start(struct watchdog_device *wdd)
  30. {
  31. struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
  32. return regmap_update_bits(wdt->pmic->regmap,
  33. WCHDG_CR, WDT_START_MASK, WDT_START);
  34. }
  35. static int pmic_wdt_stop(struct watchdog_device *wdd)
  36. {
  37. struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
  38. return regmap_update_bits(wdt->pmic->regmap,
  39. WCHDG_CR, WDT_START_MASK, WDT_STOP);
  40. }
  41. static int pmic_wdt_ping(struct watchdog_device *wdd)
  42. {
  43. struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
  44. return regmap_update_bits(wdt->pmic->regmap,
  45. WCHDG_CR, WDT_PING_MASK, WDT_PING);
  46. }
  47. static int pmic_wdt_set_timeout(struct watchdog_device *wdd,
  48. unsigned int timeout)
  49. {
  50. struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
  51. wdd->timeout = timeout;
  52. /* timeout is equal to register value + 1 */
  53. return regmap_write(wdt->pmic->regmap, WCHDG_TIMER_CR, timeout - 1);
  54. }
  55. static const struct watchdog_info pmic_watchdog_info = {
  56. .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
  57. .identity = "STPMIC1 PMIC Watchdog",
  58. };
  59. static const struct watchdog_ops pmic_watchdog_ops = {
  60. .owner = THIS_MODULE,
  61. .start = pmic_wdt_start,
  62. .stop = pmic_wdt_stop,
  63. .ping = pmic_wdt_ping,
  64. .set_timeout = pmic_wdt_set_timeout,
  65. };
  66. static int pmic_wdt_probe(struct platform_device *pdev)
  67. {
  68. struct device *dev = &pdev->dev;
  69. int ret;
  70. struct stpmic1 *pmic;
  71. struct stpmic1_wdt *wdt;
  72. if (!dev->parent)
  73. return -EINVAL;
  74. pmic = dev_get_drvdata(dev->parent);
  75. if (!pmic)
  76. return -EINVAL;
  77. wdt = devm_kzalloc(dev, sizeof(struct stpmic1_wdt), GFP_KERNEL);
  78. if (!wdt)
  79. return -ENOMEM;
  80. wdt->pmic = pmic;
  81. wdt->wdtdev.info = &pmic_watchdog_info;
  82. wdt->wdtdev.ops = &pmic_watchdog_ops;
  83. wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT;
  84. wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT;
  85. wdt->wdtdev.parent = dev;
  86. wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT;
  87. watchdog_init_timeout(&wdt->wdtdev, 0, dev);
  88. watchdog_set_nowayout(&wdt->wdtdev, nowayout);
  89. watchdog_set_drvdata(&wdt->wdtdev, wdt);
  90. ret = devm_watchdog_register_device(dev, &wdt->wdtdev);
  91. if (ret)
  92. return ret;
  93. dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n");
  94. return 0;
  95. }
  96. static const struct of_device_id of_pmic_wdt_match[] = {
  97. { .compatible = "st,stpmic1-wdt" },
  98. { },
  99. };
  100. MODULE_DEVICE_TABLE(of, of_pmic_wdt_match);
  101. static struct platform_driver stpmic1_wdt_driver = {
  102. .probe = pmic_wdt_probe,
  103. .driver = {
  104. .name = "stpmic1-wdt",
  105. .of_match_table = of_pmic_wdt_match,
  106. },
  107. };
  108. module_platform_driver(stpmic1_wdt_driver);
  109. MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device");
  110. MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
  111. MODULE_LICENSE("GPL v2");