1 /*
2 * Copyright (c) 2024 SILA Embedded Solutions GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT infineon_tle9104_gpio
8
9 #include <errno.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/init.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/gpio/gpio_utils.h>
15 #include <zephyr/drivers/mfd/tle9104.h>
16 #include <zephyr/logging/log.h>
17
18 LOG_MODULE_REGISTER(gpio_tle9104, CONFIG_GPIO_LOG_LEVEL);
19
20 struct tle9104_gpio_config {
21 /* gpio_driver_config needs to be first */
22 struct gpio_driver_config common;
23 /* parent MFD */
24 const struct device *parent;
25 bool parallel_mode_out12;
26 bool parallel_mode_out34;
27 };
28
29 struct tle9104_gpio_data {
30 /* gpio_driver_data needs to be first */
31 struct gpio_driver_data common;
32 /* each bit is one output channel, bit 0 = OUT1, ... */
33 uint8_t state;
34 /* each bit defines if the output channel is configured, see state */
35 uint8_t configured;
36 struct k_mutex lock;
37 };
38
tle9104_gpio_pin_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)39 static int tle9104_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
40 {
41 const struct tle9104_gpio_config *config = dev->config;
42 struct tle9104_gpio_data *data = dev->data;
43 int result;
44
45 /* cannot execute a bus operation in an ISR context */
46 if (k_is_in_isr()) {
47 return -EWOULDBLOCK;
48 }
49
50 if (pin >= TLE9104_GPIO_COUNT) {
51 LOG_ERR("invalid pin number %i", pin);
52 return -EINVAL;
53 }
54
55 if ((flags & GPIO_INPUT) != 0) {
56 LOG_ERR("cannot configure pin as input");
57 return -ENOTSUP;
58 }
59
60 if ((flags & GPIO_OUTPUT) == 0) {
61 LOG_ERR("pin must be configured as an output");
62 return -ENOTSUP;
63 }
64
65 if ((flags & GPIO_SINGLE_ENDED) == 0) {
66 LOG_ERR("pin must be configured as single ended");
67 return -ENOTSUP;
68 }
69
70 if ((flags & GPIO_LINE_OPEN_DRAIN) == 0) {
71 LOG_ERR("pin must be configured as open drain");
72 return -ENOTSUP;
73 }
74
75 if ((flags & GPIO_PULL_UP) != 0) {
76 LOG_ERR("pin cannot have a pull up configured");
77 return -ENOTSUP;
78 }
79
80 if ((flags & GPIO_PULL_DOWN) != 0) {
81 LOG_ERR("pin cannot have a pull down configured");
82 return -ENOTSUP;
83 }
84
85 if (config->parallel_mode_out12 && pin == 1) {
86 LOG_ERR("cannot configure OUT2 if parallel mode is enabled for OUT1 and OUT2");
87 return -EINVAL;
88 }
89
90 if (config->parallel_mode_out34 && pin == 3) {
91 LOG_ERR("cannot configure OUT4 if parallel mode is enabled for OUT3 and OUT4");
92 return -EINVAL;
93 }
94
95 k_mutex_lock(&data->lock, K_FOREVER);
96
97 if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
98 WRITE_BIT(data->state, pin, 0);
99 } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
100 WRITE_BIT(data->state, pin, 1);
101 }
102
103 WRITE_BIT(data->configured, pin, 1);
104 result = tle9104_write_state(config->parent, data->state);
105 k_mutex_unlock(&data->lock);
106
107 return result;
108 }
109
tle9104_gpio_port_get_raw(const struct device * dev,uint32_t * value)110 static int tle9104_gpio_port_get_raw(const struct device *dev, uint32_t *value)
111 {
112 ARG_UNUSED(dev);
113 ARG_UNUSED(value);
114
115 LOG_ERR("input pins are not available");
116 return -ENOTSUP;
117 }
118
tle9104_gpio_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)119 static int tle9104_gpio_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
120 {
121 const struct tle9104_gpio_config *config = dev->config;
122 struct tle9104_gpio_data *data = dev->data;
123 int result;
124
125 if (config->parallel_mode_out12 && (BIT(1) & mask) != 0) {
126 LOG_ERR("cannot set OUT2 if parallel mode is enabled for OUT1 and OUT2");
127 return -EINVAL;
128 }
129
130 if (config->parallel_mode_out34 && (BIT(3) & mask) != 0) {
131 LOG_ERR("cannot set OUT4 if parallel mode is enabled for OUT3 and OUT4");
132 return -EINVAL;
133 }
134
135 /* cannot execute a bus operation in an ISR context */
136 if (k_is_in_isr()) {
137 return -EWOULDBLOCK;
138 }
139
140 k_mutex_lock(&data->lock, K_FOREVER);
141 data->state = (data->state & ~mask) | (mask & value);
142 result = tle9104_write_state(config->parent, data->state);
143 k_mutex_unlock(&data->lock);
144
145 return result;
146 }
147
tle9104_gpio_port_set_bits_raw(const struct device * dev,uint32_t mask)148 static int tle9104_gpio_port_set_bits_raw(const struct device *dev, uint32_t mask)
149 {
150 return tle9104_gpio_port_set_masked_raw(dev, mask, mask);
151 }
152
tle9104_gpio_port_clear_bits_raw(const struct device * dev,uint32_t mask)153 static int tle9104_gpio_port_clear_bits_raw(const struct device *dev, uint32_t mask)
154 {
155 return tle9104_gpio_port_set_masked_raw(dev, mask, 0);
156 }
157
tle9104_gpio_port_toggle_bits(const struct device * dev,uint32_t mask)158 static int tle9104_gpio_port_toggle_bits(const struct device *dev, uint32_t mask)
159 {
160 const struct tle9104_gpio_config *config = dev->config;
161 struct tle9104_gpio_data *data = dev->data;
162 int result;
163
164 if (config->parallel_mode_out12 && (BIT(1) & mask) != 0) {
165 LOG_ERR("cannot toggle OUT2 if parallel mode is enabled for OUT1 and OUT2");
166 return -EINVAL;
167 }
168
169 if (config->parallel_mode_out34 && (BIT(3) & mask) != 0) {
170 LOG_ERR("cannot toggle OUT4 if parallel mode is enabled for OUT3 and OUT4");
171 return -EINVAL;
172 }
173
174 /* cannot execute a bus operation in an ISR context */
175 if (k_is_in_isr()) {
176 return -EWOULDBLOCK;
177 }
178
179 k_mutex_lock(&data->lock, K_FOREVER);
180 data->state ^= mask;
181 result = tle9104_write_state(config->parent, data->state);
182 k_mutex_unlock(&data->lock);
183
184 return result;
185 }
186
tle9104_gpio_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)187 static int tle9104_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
188 enum gpio_int_mode mode, enum gpio_int_trig trig)
189 {
190 ARG_UNUSED(dev);
191 ARG_UNUSED(pin);
192 ARG_UNUSED(mode);
193 ARG_UNUSED(trig);
194 return -ENOTSUP;
195 }
196
197 static DEVICE_API(gpio, api_table) = {
198 .pin_configure = tle9104_gpio_pin_configure,
199 .port_get_raw = tle9104_gpio_port_get_raw,
200 .port_set_masked_raw = tle9104_gpio_port_set_masked_raw,
201 .port_set_bits_raw = tle9104_gpio_port_set_bits_raw,
202 .port_clear_bits_raw = tle9104_gpio_port_clear_bits_raw,
203 .port_toggle_bits = tle9104_gpio_port_toggle_bits,
204 .pin_interrupt_configure = tle9104_gpio_pin_interrupt_configure,
205 };
206
tle9104_gpio_init(const struct device * dev)207 static int tle9104_gpio_init(const struct device *dev)
208 {
209 const struct tle9104_gpio_config *config = dev->config;
210 struct tle9104_gpio_data *data = dev->data;
211 int result;
212
213 LOG_DBG("initialize TLE9104 GPIO instance %s", dev->name);
214
215 if (!device_is_ready(config->parent)) {
216 LOG_ERR("%s: parent MFD is not ready", dev->name);
217 return -EINVAL;
218 }
219
220 result = k_mutex_init(&data->lock);
221 if (result != 0) {
222 LOG_ERR("unable to initialize mutex");
223 return result;
224 }
225
226 return 0;
227 }
228
229 #define TLE9104_GPIO_INIT(inst) \
230 static const struct tle9104_gpio_config tle9104_gpio_##inst##_config = { \
231 .common = { \
232 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \
233 }, \
234 .parent = DEVICE_DT_GET(DT_PARENT(DT_DRV_INST(inst))), \
235 .parallel_mode_out12 = DT_PROP(DT_PARENT(DT_DRV_INST(inst)), parallel_out12), \
236 .parallel_mode_out34 = DT_PROP(DT_PARENT(DT_DRV_INST(inst)), parallel_out34), \
237 }; \
238 \
239 static struct tle9104_gpio_data tle9104_gpio_##inst##_drvdata; \
240 \
241 /* This has to be initialized after the SPI peripheral. */ \
242 DEVICE_DT_INST_DEFINE(inst, tle9104_gpio_init, NULL, &tle9104_gpio_##inst##_drvdata, \
243 &tle9104_gpio_##inst##_config, POST_KERNEL, \
244 CONFIG_GPIO_TLE9104_INIT_PRIORITY, &api_table);
245
246 DT_INST_FOREACH_STATUS_OKAY(TLE9104_GPIO_INIT)
247