Skip to content

Commit 74db02b

Browse files
Martin Kiepfercarlescufi
Martin Kiepfer
authored andcommitted
drivers: gpio: AXP192 GPIO driver
AXP192 is a small power management IC, that also features 5 GPIOS. Besides GPIO driver this commit also includes needed modifications in axp192 regulator and mfd driver as LDOIO0 functioanlity is multiplexed with GPIO0 pin. Signed-off-by: Martin Kiepfer <[email protected]>
1 parent d4169c9 commit 74db02b

File tree

11 files changed

+1055
-6
lines changed

11 files changed

+1055
-6
lines changed

drivers/gpio/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h)
44

55
zephyr_library()
66

7+
zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c)
78
zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c)
89
zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c)
910
zephyr_library_sources_ifdef(CONFIG_GPIO_CC13XX_CC26XX gpio_cc13xx_cc26xx.c)

drivers/gpio/Kconfig

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ config GPIO_ENABLE_DISABLE_INTERRUPT
6969
pending register, etc. The driver must implement it to work.
7070

7171

72+
source "drivers/gpio/Kconfig.axp192"
73+
7274
source "drivers/gpio/Kconfig.b91"
7375

7476
source "drivers/gpio/Kconfig.dw"

drivers/gpio/Kconfig.axp192

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2023 Martin Kiepfer
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config GPIO_AXP192
5+
bool "AXP192 GPIO driver"
6+
default y
7+
depends on DT_HAS_X_POWERS_AXP192_GPIO_ENABLED
8+
depends on DT_HAS_X_POWERS_AXP192_ENABLED
9+
select I2C
10+
select MFD
11+
help
12+
Enable the AXP192 GPIO driver.
13+
14+
config GPIO_AXP192_INIT_PRIORITY
15+
int "AXP192 GPIO driver initialization priority"
16+
depends on GPIO_AXP192
17+
default 80
18+
help
19+
Initialization priority for the AXP192 GPIO driver. It must be
20+
greater than the I2C controller init priority and the mfd driver
21+
init priority.

drivers/gpio/gpio_axp192.c

+321
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
/*
2+
* Copyright (c) 2023 Martin Kiepfer
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT x_powers_axp192_gpio
8+
9+
#include <errno.h>
10+
11+
#include <zephyr/drivers/gpio.h>
12+
#include <zephyr/drivers/gpio/gpio_utils.h>
13+
#include <zephyr/drivers/i2c.h>
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/sys/util_macro.h>
16+
#include <zephyr/toolchain.h>
17+
#include <zephyr/logging/log.h>
18+
#include <zephyr/drivers/mfd/axp192.h>
19+
20+
LOG_MODULE_REGISTER(gpio_axp192, CONFIG_GPIO_LOG_LEVEL);
21+
22+
struct gpio_axp192_config {
23+
struct gpio_driver_config common;
24+
struct i2c_dt_spec i2c;
25+
const struct device *mfd;
26+
uint32_t ngpios;
27+
};
28+
29+
struct gpio_axp192_data {
30+
struct gpio_driver_data common;
31+
struct k_mutex mutex;
32+
sys_slist_t cb_list_gpio;
33+
};
34+
35+
static int gpio_axp192_port_get_raw(const struct device *dev, uint32_t *value)
36+
{
37+
int ret;
38+
uint8_t port_val;
39+
const struct gpio_axp192_config *config = dev->config;
40+
41+
if (k_is_in_isr()) {
42+
return -EWOULDBLOCK;
43+
}
44+
45+
ret = mfd_axp192_gpio_read_port(config->mfd, &port_val);
46+
if (ret == 0) {
47+
*value = port_val;
48+
}
49+
50+
return ret;
51+
}
52+
53+
static int gpio_axp192_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
54+
gpio_port_value_t value)
55+
{
56+
int ret;
57+
const struct gpio_axp192_config *config = dev->config;
58+
59+
if (k_is_in_isr()) {
60+
return -EWOULDBLOCK;
61+
}
62+
63+
ret = mfd_axp192_gpio_write_port(config->mfd, value, mask);
64+
65+
return ret;
66+
}
67+
68+
static int gpio_axp192_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
69+
{
70+
return gpio_axp192_port_set_masked_raw(dev, pins, pins);
71+
}
72+
73+
static int gpio_axp192_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
74+
{
75+
return gpio_axp192_port_set_masked_raw(dev, pins, 0);
76+
}
77+
78+
static int gpio_axp192_configure(const struct device *dev, gpio_pin_t pin,
79+
gpio_flags_t flags)
80+
{
81+
const struct gpio_axp192_config *config = dev->config;
82+
int ret;
83+
enum axp192_gpio_func func;
84+
85+
if (pin >= config->ngpios) {
86+
LOG_ERR("Invalid gpio pin (%d)", pin);
87+
return -EINVAL;
88+
}
89+
90+
if (k_is_in_isr()) {
91+
return -EWOULDBLOCK;
92+
}
93+
94+
/* Configure pin */
95+
LOG_DBG("Pin: %d / flags=0x%x", pin, flags);
96+
if ((flags & GPIO_OUTPUT) != 0) {
97+
98+
/* Initialize output function */
99+
func = AXP192_GPIO_FUNC_OUTPUT_LOW;
100+
if ((flags & GPIO_OPEN_DRAIN) != 0) {
101+
func = AXP192_GPIO_FUNC_OUTPUT_OD;
102+
}
103+
ret = mfd_axp192_gpio_func_ctrl(config->mfd, dev, pin, func);
104+
if (ret != 0) {
105+
return ret;
106+
}
107+
108+
/* Set init value */
109+
if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
110+
ret = mfd_axp192_gpio_write_port(config->mfd, BIT(pin), 0);
111+
} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
112+
ret = mfd_axp192_gpio_write_port(config->mfd, BIT(pin), BIT(pin));
113+
}
114+
} else if ((flags & GPIO_INPUT) != 0) {
115+
116+
/* Initialize input function */
117+
func = AXP192_GPIO_FUNC_INPUT;
118+
119+
ret = mfd_axp192_gpio_func_ctrl(config->mfd, dev, pin, func);
120+
if (ret != 0) {
121+
return ret;
122+
}
123+
124+
/* Configure pull-down */
125+
if ((flags & GPIO_PULL_UP) != 0) {
126+
/* not supported */
127+
LOG_ERR("Pull-Up not supported");
128+
ret = -ENOTSUP;
129+
} else if ((flags & GPIO_PULL_DOWN) != 0) {
130+
/* out = 0 means pull-down*/
131+
ret = mfd_axp192_gpio_pd_ctrl(config->mfd, pin, true);
132+
} else {
133+
ret = mfd_axp192_gpio_pd_ctrl(config->mfd, pin, false);
134+
}
135+
} else {
136+
/* Neither input nor output mode is selected */
137+
LOG_INF("No valid gpio mode selected");
138+
ret = -ENOTSUP;
139+
}
140+
141+
return ret;
142+
}
143+
144+
static int gpio_axp192_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
145+
{
146+
struct gpio_axp192_data *data = dev->data;
147+
int ret;
148+
uint32_t value;
149+
150+
k_mutex_lock(&data->mutex, K_FOREVER);
151+
152+
ret = gpio_axp192_port_get_raw(dev, &value);
153+
if (ret == 0) {
154+
ret = gpio_axp192_port_set_masked_raw(dev, pins, ~value);
155+
}
156+
157+
k_mutex_unlock(&data->mutex);
158+
159+
return ret;
160+
}
161+
162+
static int gpio_axp192_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
163+
enum gpio_int_mode mode, enum gpio_int_trig trig)
164+
{
165+
ARG_UNUSED(dev);
166+
ARG_UNUSED(pin);
167+
ARG_UNUSED(mode);
168+
ARG_UNUSED(trig);
169+
170+
return -ENOTSUP;
171+
}
172+
173+
#ifdef CONFIG_GPIO_GET_CONFIG
174+
static int gpio_axp192_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *out_flags)
175+
{
176+
const struct gpio_axp192_config *config = dev->config;
177+
enum axp192_gpio_func func;
178+
bool pd_enabled;
179+
int ret;
180+
181+
if (k_is_in_isr()) {
182+
return -EWOULDBLOCK;
183+
}
184+
185+
ret = mfd_axp192_gpio_func_get(config->mfd, pin, &func);
186+
if (ret != 0) {
187+
return ret;
188+
}
189+
190+
/* Set OUTPUT/INPUT flags */
191+
*out_flags = 0;
192+
switch (func) {
193+
case AXP192_GPIO_FUNC_INPUT:
194+
*out_flags |= GPIO_INPUT;
195+
break;
196+
case AXP192_GPIO_FUNC_OUTPUT_OD:
197+
*out_flags |= GPIO_OUTPUT | GPIO_OPEN_DRAIN;
198+
break;
199+
case AXP192_GPIO_FUNC_OUTPUT_LOW:
200+
*out_flags |= GPIO_OUTPUT;
201+
break;
202+
203+
case AXP192_GPIO_FUNC_LDO:
204+
__fallthrough;
205+
case AXP192_GPIO_FUNC_ADC:
206+
__fallthrough;
207+
case AXP192_GPIO_FUNC_FLOAT:
208+
__fallthrough;
209+
default:
210+
LOG_DBG("Pin %d not configured as GPIO", pin);
211+
break;
212+
}
213+
214+
/* Query pull-down config status  */
215+
ret = mfd_axp192_gpio_pd_get(config->mfd, pin, &pd_enabled);
216+
if (ret != 0) {
217+
return ret;
218+
}
219+
220+
if (pd_enabled) {
221+
*out_flags |= GPIO_PULL_DOWN;
222+
}
223+
224+
return 0;
225+
}
226+
#endif /* CONFIG_GPIO_GET_CONFIG */
227+
228+
#ifdef CONFIG_GPIO_GET_DIRECTION
229+
static int gpio_axp192_port_get_direction(const struct device *dev, gpio_port_pins_t map,
230+
gpio_port_pins_t *inputs, gpio_port_pins_t *outputs)
231+
{
232+
const struct gpio_axp192_config *config = dev->config;
233+
gpio_flags_t flags;
234+
int ret;
235+
236+
/* reset output variables */
237+
*inputs = 0;
238+
*outputs = 0;
239+
240+
/* loop through all */
241+
for (gpio_pin_t gpio = 0; gpio < config->ngpios; gpio++) {
242+
243+
if ((map & (1u << gpio)) != 0) {
244+
245+
/* use internal get_config method to get gpio flags */
246+
ret = gpio_axp192_get_config(dev, gpio, &flags);
247+
if (ret != 0) {
248+
return ret;
249+
}
250+
251+
/* Set output and input flags */
252+
if ((flags & GPIO_OUTPUT) != 0) {
253+
*outputs |= (1u << gpio);
254+
} else if (0 != (flags & GPIO_INPUT)) {
255+
*inputs |= (1u << gpio);
256+
}
257+
}
258+
}
259+
260+
return 0;
261+
}
262+
#endif /* CONFIG_GPIO_GET_DIRECTION */
263+
264+
static int gpio_axp192_manage_callback(const struct device *dev, struct gpio_callback *callback,
265+
bool set)
266+
{
267+
struct gpio_axp192_data *const data = dev->data;
268+
269+
return gpio_manage_callback(&data->cb_list_gpio, callback, set);
270+
}
271+
272+
static const struct gpio_driver_api gpio_axp192_api = {
273+
.pin_configure = gpio_axp192_configure,
274+
.port_get_raw = gpio_axp192_port_get_raw,
275+
.port_set_masked_raw = gpio_axp192_port_set_masked_raw,
276+
.port_set_bits_raw = gpio_axp192_port_set_bits_raw,
277+
.port_clear_bits_raw = gpio_axp192_port_clear_bits_raw,
278+
.port_toggle_bits = gpio_axp192_port_toggle_bits,
279+
.pin_interrupt_configure = gpio_axp192_pin_interrupt_configure,
280+
.manage_callback = gpio_axp192_manage_callback,
281+
#ifdef CONFIG_GPIO_GET_DIRECTION
282+
.port_get_direction = gpio_axp192_port_get_direction,
283+
#endif /* CONFIG_GPIO_GET_DIRECTION */
284+
#ifdef CONFIG_GPIO_GET_CONFIG
285+
.pin_get_config = gpio_axp192_get_config,
286+
#endif
287+
};
288+
289+
static int gpio_axp192_init(const struct device *dev)
290+
{
291+
const struct gpio_axp192_config *config = dev->config;
292+
struct gpio_axp192_data *data = dev->data;
293+
294+
LOG_DBG("Initializing");
295+
296+
if (!i2c_is_ready_dt(&config->i2c)) {
297+
LOG_ERR("device not ready");
298+
return -ENODEV;
299+
}
300+
301+
return k_mutex_init(&data->mutex);
302+
}
303+
304+
#define GPIO_AXP192_DEFINE(inst) \
305+
static const struct gpio_axp192_config gpio_axp192_config##inst = { \
306+
.common = \
307+
{ \
308+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \
309+
}, \
310+
.i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \
311+
.mfd = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
312+
.ngpios = DT_INST_PROP(inst, ngpios), \
313+
}; \
314+
\
315+
static struct gpio_axp192_data gpio_axp192_data##inst; \
316+
\
317+
DEVICE_DT_INST_DEFINE(inst, &gpio_axp192_init, NULL, &gpio_axp192_data##inst, \
318+
&gpio_axp192_config##inst, POST_KERNEL, \
319+
CONFIG_GPIO_AXP192_INIT_PRIORITY, &gpio_axp192_api);
320+
321+
DT_INST_FOREACH_STATUS_OKAY(GPIO_AXP192_DEFINE)

0 commit comments

Comments
 (0)