max6370_wdt.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // SPDX-License-Identifier: GPL-2.0+
  2. // (C) 2022 Pali Rohár <pali@kernel.org>
  3. #include <asm/io.h>
  4. #include <asm-generic/gpio.h>
  5. #include <dm.h>
  6. #include <linux/delay.h>
  7. #include <wdt.h>
  8. #define MAX6370_SET_MASK 0x7
  9. #define MAX6370_SET_1MS 0x0
  10. #define MAX6370_SET_10MS 0x1
  11. #define MAX6370_SET_30MS 0x2
  12. #define MAX6370_SET_DISABLE 0x3
  13. #define MAX6370_SET_100MS 0x4
  14. #define MAX6370_SET_1S 0x5
  15. #define MAX6370_SET_10S 0x6
  16. #define MAX6370_SET_60S 0x7
  17. #define MAX6370_WDI 0x8
  18. struct max6370_wdt {
  19. void __iomem *reg;
  20. struct gpio_desc gpio_wdi;
  21. };
  22. static int max6370_wdt_start(struct udevice *dev, u64 ms, ulong flags)
  23. {
  24. struct max6370_wdt *wdt = dev_get_priv(dev);
  25. u8 val;
  26. val = readb(wdt->reg);
  27. val &= ~MAX6370_SET_MASK;
  28. if (ms <= 1)
  29. val |= MAX6370_SET_1MS;
  30. else if (ms <= 10)
  31. val |= MAX6370_SET_10MS;
  32. else if (ms <= 30)
  33. val |= MAX6370_SET_30MS;
  34. else if (ms <= 100)
  35. val |= MAX6370_SET_100MS;
  36. else if (ms <= 1000)
  37. val |= MAX6370_SET_1S;
  38. else if (ms <= 10000)
  39. val |= MAX6370_SET_10S;
  40. else
  41. val |= MAX6370_SET_60S;
  42. writeb(val, wdt->reg);
  43. return 0;
  44. }
  45. static int max6370_wdt_stop(struct udevice *dev)
  46. {
  47. struct max6370_wdt *wdt = dev_get_priv(dev);
  48. u8 val;
  49. val = readb(wdt->reg);
  50. val &= ~MAX6370_SET_MASK;
  51. val |= MAX6370_SET_DISABLE;
  52. writeb(val, wdt->reg);
  53. return 0;
  54. }
  55. static int max6370_wdt_reset(struct udevice *dev)
  56. {
  57. struct max6370_wdt *wdt = dev_get_priv(dev);
  58. u8 val;
  59. if (dm_gpio_is_valid(&wdt->gpio_wdi)) {
  60. dm_gpio_set_value(&wdt->gpio_wdi, 1);
  61. __udelay(1);
  62. dm_gpio_set_value(&wdt->gpio_wdi, 0);
  63. } else {
  64. val = readb(wdt->reg);
  65. writeb(val | MAX6370_WDI, wdt->reg);
  66. writeb(val & ~MAX6370_WDI, wdt->reg);
  67. }
  68. return 0;
  69. }
  70. static int max6370_wdt_probe(struct udevice *dev)
  71. {
  72. struct max6370_wdt *wdt = dev_get_priv(dev);
  73. wdt->reg = dev_read_addr_ptr(dev);
  74. if (!wdt->reg)
  75. return -EINVAL;
  76. /* WDI gpio is optional */
  77. gpio_request_by_name(dev, "gpios", 0, &wdt->gpio_wdi, GPIOD_IS_OUT);
  78. return 0;
  79. }
  80. static const struct wdt_ops max6370_wdt_ops = {
  81. .start = max6370_wdt_start,
  82. .stop = max6370_wdt_stop,
  83. .reset = max6370_wdt_reset,
  84. };
  85. static const struct udevice_id max6370_wdt_ids[] = {
  86. { .compatible = "maxim,max6370" },
  87. {}
  88. };
  89. U_BOOT_DRIVER(max6370_wdt) = {
  90. .name = "max6370_wdt",
  91. .id = UCLASS_WDT,
  92. .of_match = max6370_wdt_ids,
  93. .probe = max6370_wdt_probe,
  94. .priv_auto = sizeof(struct max6370_wdt),
  95. .ops = &max6370_wdt_ops,
  96. };