1 /*
2  * Copyright 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/gpio/gpio_utils.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/byteorder.h>
13 
14 #include <zephyr/drivers/mfd/adp5585.h>
15 
16 #define DT_DRV_COMPAT adi_adp5585_gpio
17 
18 LOG_MODULE_REGISTER(adp5585_gpio, CONFIG_GPIO_LOG_LEVEL);
19 
20 #define ADP5585_BANK(offs) (offs >> 3)
21 #define ADP5585_BIT(offs)  (offs & GENMASK(2, 0))
22 
23 enum adp5585_gpio_pin_direction {
24 	adp5585_pin_input = 0U,
25 	adp5585_pin_output,
26 };
27 
28 enum adp5585_gpio_pin_drive_mode {
29 	adp5585_pin_drive_pp = 0U,
30 	adp5585_pin_drive_od,
31 };
32 
33 enum adp5585_gpio_pull_config {
34 	adp5585_pull_up_300k = 0U,
35 	adp5585_pull_dn_300k,
36 	adp5585_pull_up_100k, /* not used */
37 	adp5585_pull_disable,
38 };
39 
40 enum adp5585_gpio_int_en {
41 	adp5585_int_disable = 0U,
42 	adp5585_int_enable,
43 };
44 
45 enum adp5585_gpio_int_level {
46 	adp5585_int_active_low = 0U,
47 	adp5585_int_active_high,
48 };
49 
50 /** Configuration data */
51 struct adp5585_gpio_config {
52 	/* gpio_driver_config needs to be first */
53 	struct gpio_driver_config common;
54 	const struct device *mfd_dev;
55 	const struct gpio_dt_spec gpio_int;
56 };
57 
58 /** Runtime driver data */
59 struct adp5585_gpio_data {
60 	/* gpio_driver_data needs to be first */
61 	struct gpio_driver_data common;
62 	uint16_t output;
63 
64 	sys_slist_t callbacks;
65 };
66 
gpio_adp5585_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)67 static int gpio_adp5585_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
68 {
69 	const struct adp5585_gpio_config *cfg = dev->config;
70 	struct adp5585_gpio_data *data = dev->data;
71 	const struct mfd_adp5585_config *parent_cfg =
72 		(struct mfd_adp5585_config *)(cfg->mfd_dev->config);
73 	struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data);
74 
75 	int ret = 0;
76 	uint8_t reg_value;
77 
78 	/* ADP5585 has non-contiguous gpio pin layouts, account for this */
79 	if ((pin & cfg->common.port_pin_mask) == 0) {
80 		LOG_ERR("pin %d is invalid for this device", pin);
81 		return -ENOTSUP;
82 	}
83 
84 	uint8_t bank = ADP5585_BANK(pin);
85 	uint8_t bank_pin = ADP5585_BIT(pin);
86 
87 	/* Can't do I2C bus operations from an ISR */
88 	if (k_is_in_isr()) {
89 		return -EWOULDBLOCK;
90 	}
91 
92 	/* Simultaneous PU & PD mode not supported */
93 	if (((flags & GPIO_PULL_UP) != 0) && ((flags & GPIO_PULL_DOWN) != 0)) {
94 		return -ENOTSUP;
95 	}
96 
97 	/* Simultaneous input & output mode not supported */
98 	if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
99 		return -ENOTSUP;
100 	}
101 
102 	k_sem_take(&parent_data->lock, K_FOREVER);
103 
104 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
105 		reg_value = adp5585_pin_drive_od << bank_pin;
106 	} else {
107 		reg_value = adp5585_pin_drive_pp << bank_pin;
108 	}
109 	ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, ADP5585_GPO_OUT_MODE_A + bank,
110 				BIT(bank_pin), reg_value);
111 	if (ret != 0) {
112 		goto out;
113 	}
114 
115 	uint8_t regaddr = ADP5585_RPULL_CONFIG_A + (bank << 1);
116 	uint8_t shift = bank_pin << 1;
117 
118 	if (bank_pin > 3U) {
119 		regaddr += 1U;
120 		shift = (bank_pin - 3U) << 1;
121 	}
122 	if ((flags & GPIO_PULL_UP) != 0) {
123 		reg_value = adp5585_pull_up_300k << shift;
124 	} else if ((flags & GPIO_PULL_DOWN) != 0) {
125 		reg_value = adp5585_pull_dn_300k << shift;
126 	} else {
127 		reg_value = adp5585_pull_disable << shift;
128 	}
129 
130 	ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, regaddr,
131 			0b11U << shift, reg_value);
132 	if (ret != 0) {
133 		goto out;
134 	}
135 
136 	/* Ensure either Output or Input is specified */
137 	if ((flags & GPIO_OUTPUT) != 0) {
138 
139 		/* Set Low or High if specified */
140 		if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
141 			data->output &= ~BIT(pin);
142 		} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
143 			data->output |= BIT(pin);
144 		}
145 		if (bank == 0) {
146 			/* reg_value for ADP5585_GPO_OUT_MODE */
147 			reg_value = (uint8_t)data->output;
148 		} else {
149 			/* reg_value for ADP5585_GPO_OUT_MODE */
150 			reg_value = (uint8_t)(data->output >> 8);
151 		}
152 		ret = i2c_reg_write_byte_dt(&parent_cfg->i2c_bus,
153 					ADP5585_GPO_OUT_MODE_A + bank,
154 					reg_value);
155 		if (ret != 0) {
156 			goto out;
157 		}
158 		/* reg_value for ADP5585_GPIO_DIRECTION */
159 		reg_value = adp5585_pin_output << bank_pin;
160 	} else if ((flags & GPIO_INPUT) != 0) {
161 		/* reg_value for ADP5585_GPIO_DIRECTION */
162 		reg_value = adp5585_pin_output << bank_pin;
163 	}
164 
165 	ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus,
166 				ADP5585_GPIO_DIRECTION_A + bank,
167 				BIT(bank_pin), reg_value);
168 
169 out:
170 	k_sem_give(&parent_data->lock);
171 	if (ret != 0) {
172 		LOG_ERR("pin configure error: %d", ret);
173 	}
174 	return ret;
175 }
176 
gpio_adp5585_port_read(const struct device * dev,gpio_port_value_t * value)177 static int gpio_adp5585_port_read(const struct device *dev, gpio_port_value_t *value)
178 {
179 	const struct adp5585_gpio_config *cfg = dev->config;
180 	/* struct adp5585_gpio_data *data = dev->data; */
181 	const struct mfd_adp5585_config *parent_cfg =
182 		(struct mfd_adp5585_config *)(cfg->mfd_dev->config);
183 	struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data);
184 
185 	uint16_t input_data = 0;
186 	int ret = 0;
187 
188 	/* Can't do I2C bus operations from an ISR */
189 	if (k_is_in_isr()) {
190 		return -EWOULDBLOCK;
191 	}
192 
193 	k_sem_take(&parent_data->lock, K_FOREVER);
194 
195 	/** Read Input Register */
196 
197 	uint8_t gpi_status_reg;
198 	uint8_t gpi_status_buf[2];
199 
200 	ret = i2c_write_read_dt(&parent_cfg->i2c_bus, &gpi_status_reg, 1U,
201 			gpi_status_buf, 2U);
202 	if (ret) {
203 		goto out;
204 	}
205 	input_data = sys_le16_to_cpu(*((uint16_t *)gpi_status_buf));
206 	*value = input_data;
207 
208 out:
209 	k_sem_give(&parent_data->lock);
210 	LOG_DBG("read %x got %d", input_data, ret);
211 	return ret;
212 }
213 
gpio_adp5585_port_write(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value,gpio_port_value_t toggle)214 static int gpio_adp5585_port_write(const struct device *dev, gpio_port_pins_t mask,
215 				   gpio_port_value_t value, gpio_port_value_t toggle)
216 {
217 	const struct adp5585_gpio_config *cfg = dev->config;
218 	struct adp5585_gpio_data *data = dev->data;
219 	const struct mfd_adp5585_config *parent_cfg =
220 		(struct mfd_adp5585_config *)(cfg->mfd_dev->config);
221 	struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data);
222 
223 	uint16_t orig_out;
224 	uint16_t out;
225 	uint8_t reg_value;
226 	int ret;
227 
228 	/* Can't do I2C bus operations from an ISR */
229 	if (k_is_in_isr()) {
230 		return -EWOULDBLOCK;
231 	}
232 
233 	k_sem_take(&parent_data->lock, K_FOREVER);
234 
235 	orig_out = data->output;
236 	out = ((orig_out & ~mask) | (value & mask)) ^ toggle;
237 
238 	reg_value = (uint8_t)out;
239 	uint8_t gpo_data_out_buf[] = { ADP5585_GPO_DATA_OUT_A,
240 			(uint8_t)out, (uint8_t)(out >> 8) };
241 
242 	ret = i2c_write_dt(&parent_cfg->i2c_bus, gpo_data_out_buf, sizeof(gpo_data_out_buf));
243 	if (ret) {
244 		goto out;
245 	}
246 
247 	data->output = out;
248 
249 out:
250 	k_sem_give(&parent_data->lock);
251 	LOG_DBG("write %x msk %08x val %08x => %x: %d", orig_out, mask, value, out, ret);
252 	return ret;
253 }
254 
gpio_adp5585_port_set_masked(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)255 static int gpio_adp5585_port_set_masked(const struct device *dev, gpio_port_pins_t mask,
256 					gpio_port_value_t value)
257 {
258 	return gpio_adp5585_port_write(dev, mask, value, 0);
259 }
260 
gpio_adp5585_port_set_bits(const struct device * dev,gpio_port_pins_t pins)261 static int gpio_adp5585_port_set_bits(const struct device *dev, gpio_port_pins_t pins)
262 {
263 	return gpio_adp5585_port_write(dev, pins, pins, 0);
264 }
265 
gpio_adp5585_port_clear_bits(const struct device * dev,gpio_port_pins_t pins)266 static int gpio_adp5585_port_clear_bits(const struct device *dev, gpio_port_pins_t pins)
267 {
268 	return gpio_adp5585_port_write(dev, pins, 0, 0);
269 }
270 
gpio_adp5585_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)271 static int gpio_adp5585_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
272 {
273 	return gpio_adp5585_port_write(dev, 0, 0, pins);
274 }
275 
gpio_adp5585_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)276 static int gpio_adp5585_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
277 						enum gpio_int_mode mode, enum gpio_int_trig trig)
278 {
279 	const struct adp5585_gpio_config *cfg = dev->config;
280 	/* struct adp5585_gpio_data *data = dev->data; */
281 	const struct mfd_adp5585_config *parent_cfg =
282 		(struct mfd_adp5585_config *)(cfg->mfd_dev->config);
283 	struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data);
284 	int ret = 0;
285 
286 	if (parent_cfg->nint_gpio.port == NULL) {
287 		return -ENOTSUP;
288 	}
289 
290 	/* ADP5585 has non-contiguous gpio pin layouts, account for this */
291 	if ((pin & cfg->common.port_pin_mask) == 0) {
292 		LOG_ERR("pin %d is invalid for this device", pin);
293 		return -ENOTSUP;
294 	}
295 
296 	/* This device supports only level-triggered interrupts. */
297 	/* This device does NOT support either-level interrupt. */
298 	if (mode == GPIO_INT_MODE_EDGE || trig == GPIO_INT_TRIG_BOTH) {
299 		return -ENOTSUP;
300 	}
301 	if (k_is_in_isr()) {
302 		return -EWOULDBLOCK;
303 	}
304 
305 	uint8_t bank = ADP5585_BANK(pin);
306 	uint8_t bank_pin = ADP5585_BIT(pin);
307 
308 	k_sem_take(&parent_data->lock, K_FOREVER);
309 
310 	if (mode == GPIO_INT_MODE_DISABLED) {
311 		ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus,
312 					     ADP5585_GPI_INTERRUPT_EN_A + bank, BIT(bank_pin),
313 					     (adp5585_int_disable << bank_pin));
314 	} else if ((trig & GPIO_INT_TRIG_BOTH) != 0) {
315 		if (trig == GPIO_INT_TRIG_LOW) {
316 			ret = i2c_reg_update_byte_dt(
317 				&parent_cfg->i2c_bus, ADP5585_GPI_INT_LEVEL_A + bank,
318 				BIT(bank_pin), (adp5585_int_active_low << bank_pin));
319 		} else {
320 			ret = i2c_reg_update_byte_dt(
321 				&parent_cfg->i2c_bus, ADP5585_GPI_INT_LEVEL_A + bank,
322 				BIT(bank_pin), (adp5585_int_active_high << bank_pin));
323 		}
324 
325 		/* make sure GPI_n_EVENT_EN is disabled, otherwise it will generate FIFO event */
326 		ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus,
327 				ADP5585_GPI_EVENT_EN_A + bank, BIT(bank_pin), 0U);
328 		ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus,
329 				ADP5585_GPI_INTERRUPT_EN_A + bank,
330 				BIT(bank_pin), (adp5585_int_enable << bank_pin));
331 	}
332 
333 	k_sem_give(&parent_data->lock);
334 	return ret;
335 }
336 
gpio_adp5585_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)337 static int gpio_adp5585_manage_callback(const struct device *dev, struct gpio_callback *callback,
338 					bool set)
339 {
340 	struct adp5585_gpio_data *data = dev->data;
341 
342 	return gpio_manage_callback(&data->callbacks, callback, set);
343 }
344 
gpio_adp5585_irq_handler(const struct device * dev)345 void gpio_adp5585_irq_handler(const struct device *dev)
346 {
347 	const struct adp5585_gpio_config *cfg = dev->config;
348 	struct adp5585_gpio_data *data = dev->data;
349 	const struct mfd_adp5585_config *parent_cfg =
350 		(struct mfd_adp5585_config *)(cfg->mfd_dev->config);
351 	struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data);
352 
353 	uint16_t reg_int_status;
354 	int ret = 0;
355 
356 	k_sem_take(&parent_data->lock, K_FOREVER);
357 
358 	/* Read Input Register */
359 	ret = i2c_burst_read_dt(&parent_cfg->i2c_bus, ADP5585_GPI_INT_STAT_A,
360 				(uint8_t *)&reg_int_status, 2U);
361 	if (ret != 0) {
362 		LOG_WRN("%s failed to read interrupt status %d", dev->name, ret);
363 		goto out;
364 	}
365 
366 out:
367 	k_sem_give(&parent_data->lock);
368 
369 	if (ret == 0 && reg_int_status != 0) {
370 		gpio_fire_callbacks(&data->callbacks, dev, reg_int_status);
371 	}
372 }
373 
374 /**
375  * @brief Initialization function of ADP5585_GPIO
376  *
377  * This sets initial input/ output configuration and output states.
378  * The interrupt is configured if this is enabled.
379  *
380  * @param dev Device struct
381  * @return 0 if successful, failed otherwise.
382  */
gpio_adp5585_init(const struct device * dev)383 static int gpio_adp5585_init(const struct device *dev)
384 {
385 	const struct adp5585_gpio_config *cfg = dev->config;
386 	struct adp5585_gpio_data *data = dev->data;
387 	const struct mfd_adp5585_config *parent_cfg =
388 		(struct mfd_adp5585_config *)(cfg->mfd_dev->config);
389 	struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data);
390 	int ret = 0;
391 
392 	if (!device_is_ready(cfg->mfd_dev)) {
393 		LOG_ERR("%s: parent dev not ready", dev->name);
394 		ret = -ENODEV;
395 		goto out;
396 	}
397 
398 	if (!device_is_ready(parent_cfg->i2c_bus.bus)) {
399 		LOG_ERR("I2C bus device not found");
400 		ret = -EIO;
401 		goto out;
402 	}
403 
404 	k_sem_take(&parent_data->lock, K_FOREVER);
405 
406 	/** Read output register */
407 	uint8_t gpo_data_out_buf[] = { ADP5585_GPO_DATA_OUT_A,
408 			0x00, 0x00 };
409 
410 	ret = i2c_write_read_dt(&parent_cfg->i2c_bus, gpo_data_out_buf, 1U,
411 			gpo_data_out_buf + 1, 2U);
412 	if (ret) {
413 		goto out;
414 	}
415 	data->output = sys_le16_to_cpu(*((uint16_t *)(gpo_data_out_buf + 1)));
416 
417 	/** Set RPULL to high-z by default */
418 	uint8_t rpull_config_buf[] = { ADP5585_RPULL_CONFIG_A,
419 			0xffU, 0x03U, 0xffU, 0x03U };
420 
421 	ret = i2c_write_dt(&parent_cfg->i2c_bus, rpull_config_buf, sizeof(rpull_config_buf));
422 	if (ret) {
423 		goto out;
424 	}
425 
426 	parent_data->child.gpio_dev = dev;
427 
428 	/** Enable GPI interrupt */
429 	if ((ret == 0) && gpio_is_ready_dt(&parent_cfg->nint_gpio)) {
430 		ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, ADP5585_INT_EN, (1U << 1),
431 					     (1U << 1));
432 	}
433 
434 out:
435 	k_sem_give(&parent_data->lock);
436 	if (ret) {
437 		LOG_ERR("%s init failed: %d", dev->name, ret);
438 	} else {
439 		LOG_INF("%s init ok", dev->name);
440 	}
441 	return ret;
442 }
443 
444 static DEVICE_API(gpio, api_table) = {
445 	.pin_configure = gpio_adp5585_config,
446 	.port_get_raw = gpio_adp5585_port_read,
447 	.port_set_masked_raw = gpio_adp5585_port_set_masked,
448 	.port_set_bits_raw = gpio_adp5585_port_set_bits,
449 	.port_clear_bits_raw = gpio_adp5585_port_clear_bits,
450 	.port_toggle_bits = gpio_adp5585_port_toggle_bits,
451 	.pin_interrupt_configure = gpio_adp5585_pin_interrupt_configure,
452 	.manage_callback = gpio_adp5585_manage_callback,
453 };
454 
455 #define GPIO_ADP5585_INIT(inst)                                               \
456 	static const struct adp5585_gpio_config adp5585_gpio_cfg_##inst = {       \
457 		.common = {                                                           \
458 			.port_pin_mask = GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(           \
459 					inst, DT_INST_PROP(inst, ngpios))                         \
460 		},                                                                    \
461 		.mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                       \
462 	};                                                                        \
463 	static struct adp5585_gpio_data adp5585_gpio_drvdata_##inst;              \
464 	DEVICE_DT_INST_DEFINE(inst, gpio_adp5585_init, NULL,                      \
465 				&adp5585_gpio_drvdata_##inst,                                 \
466 				&adp5585_gpio_cfg_##inst, POST_KERNEL,                        \
467 			    CONFIG_GPIO_ADP5585_INIT_PRIORITY, &api_table);
468 
469 DT_INST_FOREACH_STATUS_OKAY(GPIO_ADP5585_INIT)
470