1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT nordic_npm2100_wdt
7
8 #include <errno.h>
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/drivers/watchdog.h>
13 #include <zephyr/drivers/mfd/npm2100.h>
14
15 #define TIMER_TASKS_START 0xB0U
16 #define TIMER_TASKS_STOP 0xB1U
17 #define TIMER_TASKS_KICK 0xB2U
18 #define TIMER_CONFIG 0xB3U
19 #define TIMER_TARGET_HI 0xB4U
20 #define TIMER_TARGET_MID 0xB5U
21 #define TIMER_TARGET_LO 0xB6U
22 #define TIMER_STATUS 0xB7U
23 #define TIMER_BOOT_MON 0xB8U
24
25 struct wdt_npm2100_config {
26 const struct device *mfd;
27 struct i2c_dt_spec i2c;
28 };
29
30 struct wdt_npm2100_data {
31 bool timeout_valid;
32 };
33
wdt_npm2100_setup(const struct device * dev,uint8_t options)34 static int wdt_npm2100_setup(const struct device *dev, uint8_t options)
35 {
36 const struct wdt_npm2100_config *config = dev->config;
37 struct wdt_npm2100_data *data = dev->data;
38
39 if (!data->timeout_valid) {
40 return -EINVAL;
41 }
42
43 return mfd_npm2100_start_timer(config->mfd);
44 }
45
wdt_npm2100_disable(const struct device * dev)46 static int wdt_npm2100_disable(const struct device *dev)
47 {
48 const struct wdt_npm2100_config *config = dev->config;
49 struct wdt_npm2100_data *data = dev->data;
50 int ret;
51
52 ret = i2c_reg_write_byte_dt(&config->i2c, TIMER_TASKS_STOP, 1U);
53 if (ret < 0) {
54 return ret;
55 }
56
57 data->timeout_valid = false;
58
59 return 0;
60 }
61
wdt_npm2100_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * timeout)62 static int wdt_npm2100_install_timeout(const struct device *dev,
63 const struct wdt_timeout_cfg *timeout)
64 {
65 const struct wdt_npm2100_config *config = dev->config;
66 struct wdt_npm2100_data *data = dev->data;
67 uint8_t mode;
68 int ret;
69
70 if (data->timeout_valid) {
71 return -ENOMEM;
72 }
73
74 if (timeout->window.min != 0U) {
75 return -EINVAL;
76 }
77
78 switch (timeout->flags & WDT_FLAG_RESET_MASK) {
79 case WDT_FLAG_RESET_NONE:
80 /* Watchdog expiry causes event only, and does not reset */
81 mode = NPM2100_TIMER_MODE_GENERAL_PURPOSE;
82 break;
83 case WDT_FLAG_RESET_CPU_CORE:
84 /* Watchdog expiry asserts reset output */
85 mode = NPM2100_TIMER_MODE_WDT_RESET;
86 break;
87 case WDT_FLAG_RESET_SOC:
88 /* Watchdog expiry causes full power cycle */
89 mode = NPM2100_TIMER_MODE_WDT_POWER_CYCLE;
90 break;
91 default:
92 return -EINVAL;
93 }
94
95 ret = mfd_npm2100_set_timer(config->mfd, timeout->window.max, mode);
96 if (ret < 0) {
97 return ret;
98 }
99
100 data->timeout_valid = true;
101
102 return 0;
103 }
104
wdt_npm2100_feed(const struct device * dev,int channel_id)105 static int wdt_npm2100_feed(const struct device *dev, int channel_id)
106 {
107 const struct wdt_npm2100_config *config = dev->config;
108
109 if (channel_id != 0) {
110 return -EINVAL;
111 }
112
113 return i2c_reg_write_byte_dt(&config->i2c, TIMER_TASKS_KICK, 1U);
114 }
115
116 static DEVICE_API(wdt, wdt_npm2100_api) = {
117 .setup = wdt_npm2100_setup,
118 .disable = wdt_npm2100_disable,
119 .install_timeout = wdt_npm2100_install_timeout,
120 .feed = wdt_npm2100_feed,
121 };
122
wdt_npm2100_init(const struct device * dev)123 static int wdt_npm2100_init(const struct device *dev)
124 {
125 const struct wdt_npm2100_config *config = dev->config;
126
127 if (!i2c_is_ready_dt(&config->i2c)) {
128 return -ENODEV;
129 }
130
131 /* Disable boot monitor */
132 return wdt_npm2100_disable(dev);
133 }
134
135 #define WDT_NPM2100_DEFINE(n) \
136 static struct wdt_npm2100_data data##n; \
137 \
138 static const struct wdt_npm2100_config config##n = { \
139 .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \
140 .i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(n)), \
141 }; \
142 \
143 DEVICE_DT_INST_DEFINE(n, &wdt_npm2100_init, NULL, &data##n, &config##n, POST_KERNEL, \
144 CONFIG_WDT_NPM2100_INIT_PRIORITY, &wdt_npm2100_api);
145
146 DT_INST_FOREACH_STATUS_OKAY(WDT_NPM2100_DEFINE)
147