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