1 /*
2  * Copyright (c) 2023 Grinn
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT adi_ad5592_gpio
7 
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/gpio/gpio_utils.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/byteorder.h>
12 
13 #include <zephyr/drivers/mfd/ad5592.h>
14 
15 struct gpio_ad5592_config {
16 	/* gpio_driver_config needs to be first */
17 	struct gpio_driver_config common;
18 	const struct device *mfd_dev;
19 };
20 
21 struct gpio_ad5592_data {
22 	/* gpio_driver_data needs to be first */
23 	struct gpio_driver_data common;
24 	uint8_t gpio_val;
25 	uint8_t gpio_out;
26 	uint8_t gpio_in;
27 	uint8_t gpio_pull_down;
28 };
29 
gpio_ad5592_port_get_raw(const struct device * dev,uint32_t * value)30 static int gpio_ad5592_port_get_raw(const struct device *dev, uint32_t *value)
31 {
32 	const struct gpio_ad5592_config *config = dev->config;
33 	struct gpio_ad5592_data *drv_data = dev->data;
34 	uint16_t data;
35 	int ret;
36 
37 	if (k_is_in_isr()) {
38 		return -EWOULDBLOCK;
39 	}
40 
41 	ret = mfd_ad5592_read_reg(config->mfd_dev,
42 				  AD5592_REG_GPIO_INPUT_EN, drv_data->gpio_in, &data);
43 	if (ret < 0) {
44 		return ret;
45 	}
46 
47 	*value = (uint32_t)data;
48 
49 	return 0;
50 }
51 
gpio_ad5592_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)52 static int gpio_ad5592_port_set_bits_raw(const struct device *dev,
53 					  gpio_port_pins_t pins)
54 {
55 	struct gpio_ad5592_data *data = dev->data;
56 	const struct gpio_ad5592_config *config = dev->config;
57 
58 	if (k_is_in_isr()) {
59 		return -EWOULDBLOCK;
60 	}
61 
62 	data->gpio_val |= (uint8_t)pins;
63 
64 	return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val);
65 }
66 
gpio_ad5592_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)67 static int gpio_ad5592_port_clear_bits_raw(const struct device *dev,
68 					    gpio_port_pins_t pins)
69 {
70 	struct gpio_ad5592_data *data = dev->data;
71 	const struct gpio_ad5592_config *config = dev->config;
72 
73 	if (k_is_in_isr()) {
74 		return -EWOULDBLOCK;
75 	}
76 
77 	data->gpio_val &= ~(uint8_t)pins;
78 
79 	return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val);
80 }
81 
gpio_ad5592_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)82 static inline int gpio_ad5592_configure(const struct device *dev,
83 					 gpio_pin_t pin, gpio_flags_t flags)
84 {
85 	struct gpio_ad5592_data *data = dev->data;
86 	const struct gpio_ad5592_config *config = dev->config;
87 	uint8_t val;
88 	int ret;
89 
90 	if (k_is_in_isr()) {
91 		return -EWOULDBLOCK;
92 	}
93 
94 	if (pin >= AD5592_PIN_MAX) {
95 		return -EINVAL;
96 	}
97 
98 	val = BIT(pin);
99 	if ((flags & GPIO_OUTPUT) != 0U) {
100 		data->gpio_in &= ~val;
101 		data->gpio_out |= val;
102 
103 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
104 			ret = gpio_ad5592_port_set_bits_raw(
105 				dev, (gpio_port_pins_t)BIT(pin));
106 			if (ret < 0) {
107 				return ret;
108 			}
109 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
110 			ret = gpio_ad5592_port_clear_bits_raw(
111 				dev, (gpio_port_pins_t)BIT(pin));
112 			if (ret < 0) {
113 				return ret;
114 			}
115 		}
116 
117 		ret = mfd_ad5592_write_reg(config->mfd_dev,
118 					   AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out);
119 		if (ret < 0) {
120 			return ret;
121 		}
122 
123 		ret = mfd_ad5592_write_reg(config->mfd_dev,
124 					   AD5592_REG_GPIO_INPUT_EN, data->gpio_in);
125 	} else if ((flags & GPIO_INPUT) != 0U) {
126 		data->gpio_in |= val;
127 		data->gpio_out &= ~val;
128 
129 		if ((flags & GPIO_PULL_DOWN) != 0U) {
130 			data->gpio_pull_down |= val;
131 
132 			ret = mfd_ad5592_write_reg(config->mfd_dev,
133 						   AD5592_REG_GPIO_PULLDOWN,
134 						   data->gpio_pull_down);
135 			if (ret < 0) {
136 				return ret;
137 			}
138 		} else if ((flags & GPIO_PULL_UP) != 0U) {
139 			return -ENOTSUP;
140 		}
141 
142 		ret = mfd_ad5592_write_reg(config->mfd_dev,
143 					   AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out);
144 		if (ret < 0) {
145 			return ret;
146 		}
147 
148 		ret = mfd_ad5592_write_reg(config->mfd_dev,
149 					   AD5592_REG_GPIO_INPUT_EN, data->gpio_in);
150 	} else {
151 		return -ENOTSUP;
152 	}
153 
154 	return ret;
155 }
156 
gpio_ad5592_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)157 static int gpio_ad5592_port_set_masked_raw(const struct device *dev,
158 					    gpio_port_pins_t mask,
159 					    gpio_port_value_t value)
160 {
161 	ARG_UNUSED(dev);
162 	ARG_UNUSED(mask);
163 	ARG_UNUSED(value);
164 
165 	return -ENOTSUP;
166 }
167 
gpio_ad5592_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)168 static int gpio_ad5592_port_toggle_bits(const struct device *dev,
169 					 gpio_port_pins_t pins)
170 {
171 	ARG_UNUSED(dev);
172 	ARG_UNUSED(pins);
173 
174 	return -ENOTSUP;
175 }
176 
gpio_ad5592_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)177 static int gpio_ad5592_pin_interrupt_configure(const struct device *dev,
178 						gpio_pin_t pin,
179 						enum gpio_int_mode mode,
180 						enum gpio_int_trig trig)
181 {
182 	ARG_UNUSED(dev);
183 	ARG_UNUSED(pin);
184 	ARG_UNUSED(mode);
185 	ARG_UNUSED(trig);
186 
187 	return -ENOTSUP;
188 }
189 
190 static const struct gpio_driver_api gpio_ad5592_api = {
191 	.pin_configure = gpio_ad5592_configure,
192 	.port_get_raw = gpio_ad5592_port_get_raw,
193 	.port_set_masked_raw = gpio_ad5592_port_set_masked_raw,
194 	.port_set_bits_raw = gpio_ad5592_port_set_bits_raw,
195 	.port_clear_bits_raw = gpio_ad5592_port_clear_bits_raw,
196 	.port_toggle_bits = gpio_ad5592_port_toggle_bits,
197 	.pin_interrupt_configure = gpio_ad5592_pin_interrupt_configure,
198 };
199 
gpio_ad5592_init(const struct device * dev)200 static int gpio_ad5592_init(const struct device *dev)
201 {
202 	const struct gpio_ad5592_config *config = dev->config;
203 
204 	if (!device_is_ready(config->mfd_dev)) {
205 		return -ENODEV;
206 	}
207 
208 	return 0;
209 }
210 
211 #define GPIO_AD5592_DEFINE(inst)							\
212 	static const struct gpio_ad5592_config gpio_ad5592_config##inst = {		\
213 		.common = {								\
214 			.port_pin_mask =						\
215 			GPIO_PORT_PIN_MASK_FROM_DT_INST(inst),				\
216 		},									\
217 		.mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),				\
218 	};										\
219 											\
220 	static struct gpio_ad5592_data gpio_ad5592_data##inst;				\
221 											\
222 	DEVICE_DT_INST_DEFINE(inst, gpio_ad5592_init, NULL,				\
223 			      &gpio_ad5592_data##inst, &gpio_ad5592_config##inst,	\
224 			      POST_KERNEL, CONFIG_MFD_INIT_PRIORITY,			\
225 			      &gpio_ad5592_api);
226 
227 DT_INST_FOREACH_STATUS_OKAY(GPIO_AD5592_DEFINE)
228