1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nordic_npm2100_gpio
7 
8 #include <errno.h>
9 
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/gpio/gpio_utils.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/dt-bindings/gpio/nordic-npm2100-gpio.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/sys/util_macro.h>
16 
17 #define NPM2100_GPIO_CONFIG 0x80U
18 #define NPM2100_GPIO_USAGE  0x83U
19 #define NPM2100_GPIO_OUTPUT 0x86U
20 #define NPM2100_GPIO_READ   0x89U
21 
22 #define NPM2100_GPIO_PINS 2U
23 
24 #define NPM2100_GPIO_CONFIG_INPUT     0x01U
25 #define NPM2100_GPIO_CONFIG_OUTPUT    0x02U
26 #define NPM2100_GPIO_CONFIG_OPENDRAIN 0x04U
27 #define NPM2100_GPIO_CONFIG_PULLDOWN  0x08U
28 #define NPM2100_GPIO_CONFIG_PULLUP    0x10U
29 #define NPM2100_GPIO_CONFIG_DRIVE     0x20U
30 #define NPM2100_GPIO_CONFIG_DEBOUNCE  0x40U
31 
32 struct gpio_npm2100_config {
33 	struct gpio_driver_config common;
34 	struct i2c_dt_spec i2c;
35 };
36 
37 struct gpio_npm2100_data {
38 	struct gpio_driver_data common;
39 };
40 
gpio_npm2100_port_get_raw(const struct device * dev,uint32_t * value)41 static int gpio_npm2100_port_get_raw(const struct device *dev, uint32_t *value)
42 {
43 	const struct gpio_npm2100_config *config = dev->config;
44 	uint8_t data;
45 	int ret;
46 
47 	ret = i2c_reg_read_byte_dt(&config->i2c, NPM2100_GPIO_READ, &data);
48 	if (ret < 0) {
49 		return ret;
50 	}
51 
52 	*value = data;
53 
54 	return 0;
55 }
56 
gpio_npm2100_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)57 static int gpio_npm2100_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
58 					    gpio_port_value_t value)
59 {
60 	const struct gpio_npm2100_config *config = dev->config;
61 	int ret = 0;
62 
63 	for (size_t idx = 0; idx < NPM2100_GPIO_PINS; idx++) {
64 		if ((mask & BIT(idx)) != 0U) {
65 			i2c_reg_write_byte_dt(&config->i2c, NPM2100_GPIO_OUTPUT + idx,
66 					      !!(value & BIT(idx)));
67 			if (ret != 0U) {
68 				return ret;
69 			}
70 		}
71 	}
72 
73 	return ret;
74 }
75 
gpio_npm2100_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)76 static int gpio_npm2100_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
77 {
78 	return gpio_npm2100_port_set_masked_raw(dev, pins, pins);
79 }
80 
gpio_npm2100_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)81 static int gpio_npm2100_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
82 {
83 	return gpio_npm2100_port_set_masked_raw(dev, pins, 0U);
84 }
85 
gpio_npm2100_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)86 static inline int gpio_npm2100_configure(const struct device *dev, gpio_pin_t pin,
87 					 gpio_flags_t flags)
88 {
89 	const struct gpio_npm2100_config *config = dev->config;
90 	uint8_t reg = 0U;
91 
92 	if (k_is_in_isr()) {
93 		return -EWOULDBLOCK;
94 	}
95 
96 	if (pin >= NPM2100_GPIO_PINS) {
97 		return -EINVAL;
98 	}
99 
100 	/* Set initial state if defined */
101 	if ((flags & (GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH)) != 0U) {
102 		int ret = i2c_reg_write_byte_dt(&config->i2c, NPM2100_GPIO_OUTPUT + pin,
103 						!!(flags & GPIO_OUTPUT_INIT_HIGH));
104 		if (ret < 0) {
105 			return ret;
106 		}
107 	}
108 
109 	/* Set pin configuration */
110 	if ((flags & GPIO_INPUT) != 0U) {
111 		reg |= NPM2100_GPIO_CONFIG_INPUT;
112 	}
113 	if ((flags & GPIO_OUTPUT) != 0U) {
114 		reg |= NPM2100_GPIO_CONFIG_OUTPUT;
115 	}
116 	if ((flags & GPIO_SINGLE_ENDED) != 0U) {
117 		reg |= NPM2100_GPIO_CONFIG_OPENDRAIN;
118 	}
119 	if ((flags & GPIO_PULL_UP) != 0U) {
120 		reg |= NPM2100_GPIO_CONFIG_PULLUP;
121 	}
122 	if ((flags & GPIO_PULL_DOWN) != 0U) {
123 		reg |= NPM2100_GPIO_CONFIG_PULLDOWN;
124 	}
125 	if ((flags & NPM2100_GPIO_DRIVE_HIGH) != 0U) {
126 		reg |= NPM2100_GPIO_CONFIG_DRIVE;
127 	}
128 	if ((flags & NPM2100_GPIO_DEBOUNCE_ON) != 0U) {
129 		reg |= NPM2100_GPIO_CONFIG_DEBOUNCE;
130 	}
131 
132 	return i2c_reg_write_byte_dt(&config->i2c, NPM2100_GPIO_CONFIG + pin, reg);
133 }
134 
gpio_npm2100_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)135 static int gpio_npm2100_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
136 {
137 	int ret;
138 	uint32_t value;
139 
140 	ret = gpio_npm2100_port_get_raw(dev, &value);
141 	if (ret < 0) {
142 		return ret;
143 	}
144 
145 	return gpio_npm2100_port_set_masked_raw(dev, pins, ~value);
146 }
147 
148 static DEVICE_API(gpio, gpio_npm2100_api) = {
149 	.pin_configure = gpio_npm2100_configure,
150 	.port_get_raw = gpio_npm2100_port_get_raw,
151 	.port_set_masked_raw = gpio_npm2100_port_set_masked_raw,
152 	.port_set_bits_raw = gpio_npm2100_port_set_bits_raw,
153 	.port_clear_bits_raw = gpio_npm2100_port_clear_bits_raw,
154 	.port_toggle_bits = gpio_npm2100_port_toggle_bits,
155 };
156 
gpio_npm2100_init(const struct device * dev)157 static int gpio_npm2100_init(const struct device *dev)
158 {
159 	const struct gpio_npm2100_config *config = dev->config;
160 
161 	if (!i2c_is_ready_dt(&config->i2c)) {
162 		return -ENODEV;
163 	}
164 
165 	return 0;
166 }
167 
168 #define GPIO_NPM2100_DEFINE(n)                                                                     \
169 	static const struct gpio_npm2100_config gpio_npm2100_config##n = {                         \
170 		.common =                                                                          \
171 			{                                                                          \
172 				.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),               \
173 			},                                                                         \
174 		.i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(n))};                                        \
175                                                                                                    \
176 	static struct gpio_npm2100_data gpio_npm2100_data##n;                                      \
177                                                                                                    \
178 	DEVICE_DT_INST_DEFINE(n, &gpio_npm2100_init, NULL, &gpio_npm2100_data##n,                  \
179 			      &gpio_npm2100_config##n, POST_KERNEL,                                \
180 			      CONFIG_GPIO_NPM2100_INIT_PRIORITY, &gpio_npm2100_api);
181 
182 DT_INST_FOREACH_STATUS_OKAY(GPIO_NPM2100_DEFINE)
183