1 /*
2 * Copyright (C) 2023 BeagleBoard.org Foundation
3 * Copyright (C) 2023 S Prashanth
4 * Copyright (C) 2025 Siemens Mobility GmbH
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define DT_DRV_COMPAT ti_davinci_gpio
10
11 #include <errno.h>
12
13 #include <zephyr/arch/common/sys_bitops.h>
14 #include <zephyr/device.h>
15 #include <zephyr/devicetree.h>
16 #include <zephyr/drivers/gpio.h>
17 #include <zephyr/drivers/gpio/gpio_utils.h>
18 #include <zephyr/init.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/sys/sys_io.h>
21 #include <zephyr/logging/log.h>
22 #include <zephyr/drivers/pinctrl.h>
23
24 LOG_MODULE_REGISTER(gpio_davinci, CONFIG_GPIO_LOG_LEVEL);
25
26 /* Helper Macros for GPIO */
27 #define DEV_CFG(dev) \
28 ((const struct gpio_davinci_config *)((dev)->config))
29 #define DEV_DATA(dev) ((struct gpio_davinci_data *)(dev)->data)
30
31 #define GPIO_DAVINCI_DIR_RESET_VAL (0xFFFFFFFF)
32
33 struct gpio_davinci_regs {
34 uint32_t dir;
35 uint32_t out_data;
36 uint32_t set_data;
37 uint32_t clr_data;
38 uint32_t in_data;
39 uint32_t set_ris_trig;
40 uint32_t clr_ris_trig;
41 uint32_t set_fal_trig;
42 uint32_t clr_fal_trig;
43 uint32_t intstat;
44 };
45
46 struct gpio_davinci_data {
47 struct gpio_driver_data common;
48
49 DEVICE_MMIO_NAMED_RAM(port_base);
50
51 sys_slist_t cb;
52 };
53
54 struct gpio_davinci_config {
55 struct gpio_driver_config common;
56 void (*bank_config)(const struct device *dev);
57
58 DEVICE_MMIO_NAMED_ROM(port_base);
59
60 uint32_t port_num;
61 const struct pinctrl_dev_config *pcfg;
62 };
63
64 const unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0};
65 #define MAX_REGS_BANK ARRAY_SIZE(offset_array)
66
67 #define BANK0 0
68
gpio_davinci_get_regs(const struct device * dev,uint8_t bank)69 static struct gpio_davinci_regs *gpio_davinci_get_regs(const struct device *dev, uint8_t bank)
70 {
71 __ASSERT(bank < MAX_REGS_BANK, "Invalid bank");
72 return (struct gpio_davinci_regs *)((uint8_t *)DEVICE_MMIO_NAMED_GET(dev, port_base) +
73 offset_array[bank]);
74 }
75
gpio_davinci_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)76 static int gpio_davinci_configure(const struct device *dev, gpio_pin_t pin,
77 gpio_flags_t flags)
78 {
79 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0);
80
81 if ((flags & GPIO_SINGLE_ENDED) != 0) {
82 return -ENOTSUP;
83 }
84
85 if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
86 return -ENOTSUP;
87 }
88
89 if ((flags & GPIO_OUTPUT) != 0) {
90 if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
91 regs->set_data = BIT(pin);
92 } else {
93 regs->clr_data = BIT(pin);
94 }
95 regs->dir &= ~(BIT(pin));
96 } else {
97 regs->dir |= BIT(pin);
98 }
99
100 return 0;
101 }
102
gpio_davinci_port_get_raw(const struct device * dev,gpio_port_value_t * value)103 static int gpio_davinci_port_get_raw(const struct device *dev,
104 gpio_port_value_t *value)
105 {
106 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0);
107
108 *value = regs->in_data;
109
110 return 0;
111 }
112
gpio_davinci_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)113 static int gpio_davinci_port_set_masked_raw(const struct device *dev,
114 gpio_port_pins_t mask, gpio_port_value_t value)
115 {
116 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0);
117
118 regs->out_data = (regs->out_data & (~mask)) | (mask & value);
119
120 return 0;
121 }
122
gpio_davinci_port_set_bits_raw(const struct device * dev,gpio_port_pins_t mask)123 static int gpio_davinci_port_set_bits_raw(const struct device *dev,
124 gpio_port_pins_t mask)
125 {
126 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0);
127
128 regs->set_data = mask;
129
130 return 0;
131 }
132
gpio_davinci_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t mask)133 static int gpio_davinci_port_clear_bits_raw(const struct device *dev,
134 gpio_port_pins_t mask)
135 {
136 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0);
137
138 regs->clr_data = mask;
139
140 return 0;
141 }
142
gpio_davinci_port_toggle_bits(const struct device * dev,gpio_port_pins_t mask)143 static int gpio_davinci_port_toggle_bits(const struct device *dev,
144 gpio_port_pins_t mask)
145 {
146 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0);
147
148 regs->out_data ^= mask;
149
150 return 0;
151 }
152
153 static DEVICE_API(gpio, gpio_davinci_driver_api) = {
154 .pin_configure = gpio_davinci_configure,
155 .port_get_raw = gpio_davinci_port_get_raw,
156 .port_set_masked_raw = gpio_davinci_port_set_masked_raw,
157 .port_set_bits_raw = gpio_davinci_port_set_bits_raw,
158 .port_clear_bits_raw = gpio_davinci_port_clear_bits_raw,
159 .port_toggle_bits = gpio_davinci_port_toggle_bits
160 };
161
gpio_davinci_init(const struct device * dev)162 static int gpio_davinci_init(const struct device *dev)
163 {
164 const struct gpio_davinci_config *config = DEV_CFG(dev);
165 int ret;
166
167 DEVICE_MMIO_NAMED_MAP(dev, port_base, K_MEM_CACHE_NONE);
168
169 config->bank_config(dev);
170
171 ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
172 if (ret < 0 && ret != -ENOENT) {
173 LOG_ERR("failed to apply pinctrl");
174 return ret;
175 }
176 return 0;
177 }
178
179 #define GPIO_DAVINCI_INIT_FUNC(n) \
180 static void gpio_davinci_bank_##n##_config(const struct device *dev) \
181 { \
182 volatile struct gpio_davinci_regs *regs = gpio_davinci_get_regs(dev, BANK0); \
183 regs->dir = GPIO_DAVINCI_DIR_RESET_VAL; \
184 }
185
186 #define GPIO_DAVINCI_INIT(n) \
187 PINCTRL_DT_INST_DEFINE(n); \
188 GPIO_DAVINCI_INIT_FUNC(n); \
189 static const struct gpio_davinci_config gpio_davinci_##n##_config = { \
190 .bank_config = gpio_davinci_bank_##n##_config, \
191 .common = { \
192 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
193 }, \
194 DEVICE_MMIO_NAMED_ROM_INIT(port_base, DT_DRV_INST(n)), \
195 .port_num = n, \
196 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
197 }; \
198 \
199 static struct gpio_davinci_data gpio_davinci_##n##_data; \
200 \
201 DEVICE_DT_INST_DEFINE(n, \
202 gpio_davinci_init, \
203 NULL, \
204 &gpio_davinci_##n##_data, \
205 &gpio_davinci_##n##_config, \
206 PRE_KERNEL_2, \
207 CONFIG_GPIO_INIT_PRIORITY, \
208 &gpio_davinci_driver_api);
209
210 DT_INST_FOREACH_STATUS_OKAY(GPIO_DAVINCI_INIT)
211