1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT nordic_npm1300
7
8 #include <errno.h>
9
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/gpio/gpio_utils.h>
15 #include <zephyr/drivers/mfd/npm1300.h>
16
17 #define TIME_BASE 0x07U
18 #define MAIN_BASE 0x00U
19 #define SHIP_BASE 0x0BU
20 #define GPIO_BASE 0x06U
21
22 #define TIME_OFFSET_LOAD 0x03U
23 #define TIME_OFFSET_TIMER 0x08U
24
25 #define MAIN_OFFSET_RESET 0x01U
26 #define MAIN_OFFSET_SET 0x00U
27 #define MAIN_OFFSET_CLR 0x01U
28 #define MAIN_OFFSET_INTENSET 0x02U
29 #define MAIN_OFFSET_INTENCLR 0x03U
30
31 #define SHIP_OFFSET_HIBERNATE 0x00U
32 #define SHIP_OFFSET_CFGSTROBE 0x01U
33 #define SHIP_OFFSET_CONFIG 0x04U
34 #define SHIP_OFFSET_LPCONFIG 0x06U
35
36 #define GPIO_OFFSET_MODE 0x00U
37
38 #define TIMER_PRESCALER_MS 16U
39 #define TIMER_MAX 0xFFFFFFU
40
41 #define MAIN_SIZE 0x26U
42
43 #define GPIO_MODE_GPOIRQ 5
44
45 struct mfd_npm1300_config {
46 struct i2c_dt_spec i2c;
47 struct gpio_dt_spec host_int_gpios;
48 uint8_t pmic_int_pin;
49 uint8_t active_time;
50 uint8_t lp_reset;
51 };
52
53 struct mfd_npm1300_data {
54 struct k_mutex mutex;
55 const struct device *dev;
56 struct gpio_callback gpio_cb;
57 struct k_work work;
58 sys_slist_t callbacks;
59 };
60
61 struct event_reg_t {
62 uint8_t offset;
63 uint8_t mask;
64 };
65
66 static const struct event_reg_t event_reg[NPM1300_EVENT_MAX] = {
67 [NPM1300_EVENT_CHG_COMPLETED] = {0x0AU, 0x10U},
68 [NPM1300_EVENT_CHG_ERROR] = {0x0AU, 0x20U},
69 [NPM1300_EVENT_BATTERY_DETECTED] = {0x0EU, 0x01U},
70 [NPM1300_EVENT_BATTERY_REMOVED] = {0x0EU, 0x02U},
71 [NPM1300_EVENT_SHIPHOLD_PRESS] = {0x12U, 0x01U},
72 [NPM1300_EVENT_SHIPHOLD_RELEASE] = {0x12U, 0x02U},
73 [NPM1300_EVENT_WATCHDOG_WARN] = {0x12U, 0x08U},
74 [NPM1300_EVENT_VBUS_DETECTED] = {0x16U, 0x01U},
75 [NPM1300_EVENT_VBUS_REMOVED] = {0x16U, 0x02U},
76 [NPM1300_EVENT_GPIO0_EDGE] = {0x22U, 0x01U},
77 [NPM1300_EVENT_GPIO1_EDGE] = {0x22U, 0x02U},
78 [NPM1300_EVENT_GPIO2_EDGE] = {0x22U, 0x04U},
79 [NPM1300_EVENT_GPIO3_EDGE] = {0x22U, 0x08U},
80 [NPM1300_EVENT_GPIO4_EDGE] = {0x22U, 0x10U},
81 };
82
gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)83 static void gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
84 {
85 struct mfd_npm1300_data *data = CONTAINER_OF(cb, struct mfd_npm1300_data, gpio_cb);
86
87 k_work_submit(&data->work);
88 }
89
work_callback(struct k_work * work)90 static void work_callback(struct k_work *work)
91 {
92 struct mfd_npm1300_data *data = CONTAINER_OF(work, struct mfd_npm1300_data, work);
93 const struct mfd_npm1300_config *config = data->dev->config;
94 uint8_t buf[MAIN_SIZE];
95 int ret;
96
97 /* Read all MAIN registers into temporary buffer */
98 ret = mfd_npm1300_reg_read_burst(data->dev, MAIN_BASE, 0U, buf, sizeof(buf));
99 if (ret < 0) {
100 k_work_submit(&data->work);
101 return;
102 }
103
104 for (int i = 0; i < NPM1300_EVENT_MAX; i++) {
105 int offset = event_reg[i].offset + MAIN_OFFSET_CLR;
106
107 if ((buf[offset] & event_reg[i].mask) != 0U) {
108 gpio_fire_callbacks(&data->callbacks, data->dev, BIT(i));
109
110 ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE, offset,
111 event_reg[i].mask);
112 if (ret < 0) {
113 k_work_submit(&data->work);
114 return;
115 }
116 }
117 }
118
119 /* Resubmit handler to queue if interrupt is still active */
120 if (gpio_pin_get_dt(&config->host_int_gpios) != 0) {
121 k_work_submit(&data->work);
122 }
123 }
124
mfd_npm1300_init(const struct device * dev)125 static int mfd_npm1300_init(const struct device *dev)
126 {
127 const struct mfd_npm1300_config *config = dev->config;
128 struct mfd_npm1300_data *mfd_data = dev->data;
129 int ret;
130
131 if (!i2c_is_ready_dt(&config->i2c)) {
132 return -ENODEV;
133 }
134
135 k_mutex_init(&mfd_data->mutex);
136
137 mfd_data->dev = dev;
138
139 if (config->host_int_gpios.port != NULL) {
140 /* Set specified PMIC pin to be interrupt output */
141 ret = mfd_npm1300_reg_write(dev, GPIO_BASE, GPIO_OFFSET_MODE + config->pmic_int_pin,
142 GPIO_MODE_GPOIRQ);
143 if (ret < 0) {
144 return ret;
145 }
146
147 /* Configure host interrupt GPIO */
148 if (!gpio_is_ready_dt(&config->host_int_gpios)) {
149 return -ENODEV;
150 }
151
152 ret = gpio_pin_configure_dt(&config->host_int_gpios, GPIO_INPUT);
153 if (ret < 0) {
154 return ret;
155 }
156
157 gpio_init_callback(&mfd_data->gpio_cb, gpio_callback,
158 BIT(config->host_int_gpios.pin));
159
160 ret = gpio_add_callback(config->host_int_gpios.port, &mfd_data->gpio_cb);
161 if (ret < 0) {
162 return ret;
163 }
164
165 mfd_data->work.handler = work_callback;
166
167 ret = gpio_pin_interrupt_configure_dt(&config->host_int_gpios,
168 GPIO_INT_EDGE_TO_ACTIVE);
169 if (ret < 0) {
170 return ret;
171 }
172 }
173
174 ret = mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_CONFIG, config->active_time);
175 if (ret < 0) {
176 return ret;
177 }
178
179 ret = mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_LPCONFIG, config->lp_reset);
180 if (ret < 0) {
181 return ret;
182 }
183
184 return mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_CFGSTROBE, 1U);
185 }
186
mfd_npm1300_reg_read_burst(const struct device * dev,uint8_t base,uint8_t offset,void * data,size_t len)187 int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, void *data,
188 size_t len)
189 {
190 const struct mfd_npm1300_config *config = dev->config;
191 uint8_t buff[] = {base, offset};
192
193 return i2c_write_read_dt(&config->i2c, buff, sizeof(buff), data, len);
194 }
195
mfd_npm1300_reg_read(const struct device * dev,uint8_t base,uint8_t offset,uint8_t * data)196 int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data)
197 {
198 return mfd_npm1300_reg_read_burst(dev, base, offset, data, 1U);
199 }
200
mfd_npm1300_reg_write(const struct device * dev,uint8_t base,uint8_t offset,uint8_t data)201 int mfd_npm1300_reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data)
202 {
203 const struct mfd_npm1300_config *config = dev->config;
204 uint8_t buff[] = {base, offset, data};
205
206 return i2c_write_dt(&config->i2c, buff, sizeof(buff));
207 }
208
mfd_npm1300_reg_write2(const struct device * dev,uint8_t base,uint8_t offset,uint8_t data1,uint8_t data2)209 int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1,
210 uint8_t data2)
211 {
212 const struct mfd_npm1300_config *config = dev->config;
213 uint8_t buff[] = {base, offset, data1, data2};
214
215 return i2c_write_dt(&config->i2c, buff, sizeof(buff));
216 }
217
mfd_npm1300_reg_update(const struct device * dev,uint8_t base,uint8_t offset,uint8_t data,uint8_t mask)218 int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data,
219 uint8_t mask)
220 {
221 struct mfd_npm1300_data *mfd_data = dev->data;
222 uint8_t reg;
223 int ret;
224
225 k_mutex_lock(&mfd_data->mutex, K_FOREVER);
226
227 ret = mfd_npm1300_reg_read(dev, base, offset, ®);
228
229 if (ret == 0) {
230 reg = (reg & ~mask) | (data & mask);
231 ret = mfd_npm1300_reg_write(dev, base, offset, reg);
232 }
233
234 k_mutex_unlock(&mfd_data->mutex);
235
236 return ret;
237 }
238
mfd_npm1300_set_timer(const struct device * dev,uint32_t time_ms)239 int mfd_npm1300_set_timer(const struct device *dev, uint32_t time_ms)
240 {
241 const struct mfd_npm1300_config *config = dev->config;
242 uint8_t buff[5] = {TIME_BASE, TIME_OFFSET_TIMER};
243 uint32_t ticks = time_ms / TIMER_PRESCALER_MS;
244
245 if (ticks > TIMER_MAX) {
246 return -EINVAL;
247 }
248
249 sys_put_be24(ticks, &buff[2]);
250
251 int ret = i2c_write_dt(&config->i2c, buff, sizeof(buff));
252
253 if (ret != 0) {
254 return ret;
255 }
256
257 return mfd_npm1300_reg_write(dev, TIME_BASE, TIME_OFFSET_LOAD, 1U);
258 }
259
mfd_npm1300_reset(const struct device * dev)260 int mfd_npm1300_reset(const struct device *dev)
261 {
262 return mfd_npm1300_reg_write(dev, MAIN_BASE, MAIN_OFFSET_RESET, 1U);
263 }
264
mfd_npm1300_hibernate(const struct device * dev,uint32_t time_ms)265 int mfd_npm1300_hibernate(const struct device *dev, uint32_t time_ms)
266 {
267 int ret = mfd_npm1300_set_timer(dev, time_ms);
268
269 if (ret != 0) {
270 return ret;
271 }
272
273 return mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_HIBERNATE, 1U);
274 }
275
mfd_npm1300_add_callback(const struct device * dev,struct gpio_callback * callback)276 int mfd_npm1300_add_callback(const struct device *dev, struct gpio_callback *callback)
277 {
278 struct mfd_npm1300_data *data = dev->data;
279
280 /* Enable interrupts for specified events */
281 for (int i = 0; i < NPM1300_EVENT_MAX; i++) {
282 if ((callback->pin_mask & BIT(i)) != 0U) {
283 /* Clear pending interrupt */
284 int ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE,
285 event_reg[i].offset + MAIN_OFFSET_CLR,
286 event_reg[i].mask);
287
288 if (ret < 0) {
289 return ret;
290 }
291
292 ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE,
293 event_reg[i].offset + MAIN_OFFSET_INTENSET,
294 event_reg[i].mask);
295 if (ret < 0) {
296 return ret;
297 }
298 }
299 }
300
301 return gpio_manage_callback(&data->callbacks, callback, true);
302 }
303
mfd_npm1300_remove_callback(const struct device * dev,struct gpio_callback * callback)304 int mfd_npm1300_remove_callback(const struct device *dev, struct gpio_callback *callback)
305 {
306 struct mfd_npm1300_data *data = dev->data;
307
308 return gpio_manage_callback(&data->callbacks, callback, false);
309 }
310
311 #define MFD_NPM1300_DEFINE(inst) \
312 static struct mfd_npm1300_data data_##inst; \
313 \
314 static const struct mfd_npm1300_config config##inst = { \
315 .i2c = I2C_DT_SPEC_INST_GET(inst), \
316 .host_int_gpios = GPIO_DT_SPEC_INST_GET_OR(inst, host_int_gpios, {0}), \
317 .pmic_int_pin = DT_INST_PROP_OR(inst, pmic_int_pin, 0), \
318 .active_time = DT_INST_ENUM_IDX(inst, ship_to_active_time_ms), \
319 .lp_reset = DT_INST_ENUM_IDX_OR(inst, long_press_reset, 0), \
320 }; \
321 \
322 DEVICE_DT_INST_DEFINE(inst, mfd_npm1300_init, NULL, &data_##inst, &config##inst, \
323 POST_KERNEL, CONFIG_MFD_NPM1300_INIT_PRIORITY, NULL);
324
325 DT_INST_FOREACH_STATUS_OKAY(MFD_NPM1300_DEFINE)
326