Skip to content

Commit fec345c

Browse files
committed
drivers: gpio: Introduce SC18IS606 GPIO Controller
Added a driver implementation for the GPIO Controller on the sc18is606 Signed-off-by: Zacck Osiemo <[email protected]>
1 parent 286cefb commit fec345c

File tree

6 files changed

+298
-0
lines changed

6 files changed

+298
-0
lines changed

drivers/gpio/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,8 @@ if(CONFIG_GPIO_SC18IM704)
143143
zephyr_library_include_directories(${ZEPHYR_BASE}/drivers)
144144
zephyr_library_sources(gpio_sc18im704.c)
145145
endif()
146+
147+
if(CONFIG_GPIO_SC18IS606)
148+
zephyr_library_include_directories(${ZEPHYR_BASE}/drivers)
149+
zephyr_library_sources(gpio_sc18is606.c)
150+
endif()

drivers/gpio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ source "drivers/gpio/Kconfig.rzt2m"
183183
source "drivers/gpio/Kconfig.sam"
184184
source "drivers/gpio/Kconfig.sam0"
185185
source "drivers/gpio/Kconfig.sc18im704"
186+
source "drivers/gpio/Kconfig.sc18is606"
186187
source "drivers/gpio/Kconfig.sedi"
187188
source "drivers/gpio/Kconfig.sf32lb"
188189
source "drivers/gpio/Kconfig.si32"

drivers/gpio/Kconfig.sc18is606

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2025 tinyvision.ai
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config GPIO_SC18IS606
5+
bool "NXP SC18IS606 GPIO Controller driver"
6+
default y
7+
depends on SPI_SC18IS606
8+
depends on DT_HAS_NXP_SC18IS606_GPIO_ENABLED
9+
help
10+
Enables NXP SC18IS606 gpio controller driver
11+
12+
config GPIO_SC18IS606_INIT_PRIORITY
13+
int "SC18IS606 GPIO Init Priority"
14+
default 66
15+
depends on GPIO_SC18IS606
16+
help
17+
SC18IS606 GPIO Controller Init priority
18+
19+
Note: Has to be greater than the parent SC18IS606 bridge init priority
20+

drivers/gpio/gpio_sc18is606.c

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/*
2+
* Copyright (c), 2025 tinyvision.io
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT nxp_sc18is606_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+
16+
#include <zephyr/logging/log.h>
17+
LOG_MODULE_REGISTER(nxp_sc18is606_gpio, CONFIG_GPIO_LOG_LEVEL);
18+
19+
#include "spi/spi_sc18is606.h"
20+
21+
#define SC18IS606_GPIO_MAX_PINS 3
22+
23+
#define SC18IS606_GPIO_WRITE 0xF4
24+
#define SC18IS606_GPIO_READ 0xF5
25+
#define SC18IS606_GPIO_ENABLE 0xF6
26+
#define SC18IS606_GPIO_CONF 0xF7
27+
28+
29+
#define SC18IS606_GPIO_CONF_INPUT 0x00
30+
#define SC18IS606_GPIO_CONF_PUSH_PULL 0x01
31+
#define SC18IS606_GPIO_CONF_OPEN_DRAIN 0x03
32+
#define SC18IS606_GPIO_CONF_MASK 0x03
33+
34+
struct gpio_sc18is606_config {
35+
struct gpio_driver_config common;
36+
37+
const struct device *bridge;
38+
};
39+
40+
struct gpio_sc18is606_data {
41+
struct gpio_driver_data sc18is606_data;
42+
43+
/*current port state*/
44+
uint8_t output_state;
45+
46+
/*current port pin config*/
47+
uint8_t conf;
48+
};
49+
50+
51+
static int gpio_sc18is606_port_set_raw(const struct device *port,
52+
uint8_t mask, uint8_t value, uint8_t toggle) {
53+
const struct gpio_sc18is606_config *cfg = port->config;
54+
struct gpio_sc18is606_data *data = port->data;
55+
56+
uint8_t buf[] = {
57+
SC18IS606_GPIO_WRITE,
58+
data->output_state,
59+
};
60+
int ret;
61+
62+
if(k_is_in_isr()) {
63+
return -EWOULDBLOCK;
64+
}
65+
66+
buf[1] &= ~mask;
67+
buf[1] |= (value & mask);
68+
buf[1] ^= toggle;
69+
70+
ret = nxp_sc18is606_transfer(cfg->bridge, buf, sizeof(buf), NULL, 0, NULL);
71+
72+
if(ret < 0) {
73+
LOG_ERR("Failed to write to GPIO (%d)", ret);
74+
return ret;
75+
}
76+
77+
data->output_state = buf[1];
78+
79+
return 0;
80+
}
81+
82+
static int gpio_sc18is606_pin_configure(const struct device *port, gpio_pin_t pin,
83+
gpio_flags_t flags)
84+
{
85+
const struct gpio_sc18is606_config *cfg = port->config;
86+
struct gpio_sc18is606_data *data = port->data;
87+
uint8_t pin_conf;
88+
int ret;
89+
90+
uint8_t buf[] = {
91+
SC18IS606_GPIO_CONF,
92+
0x00,
93+
};
94+
95+
if(pin >= SC18IS606_GPIO_MAX_PINS) {
96+
return -EINVAL;
97+
}
98+
99+
if(flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) {
100+
return -ENOTSUP;
101+
}
102+
103+
if(flags & GPIO_INPUT) {
104+
pin_conf = SC18IS606_GPIO_CONF_INPUT;
105+
} else if (flags & GPIO_OUTPUT) {
106+
if (flags & GPIO_SINGLE_ENDED) {
107+
if(flags & GPIO_LINE_OPEN_DRAIN) {
108+
pin_conf = SC18IS606_GPIO_CONF_OPEN_DRAIN;
109+
} else {
110+
return -ENOTSUP;
111+
}
112+
} else {
113+
pin_conf = SC18IS606_GPIO_CONF_PUSH_PULL;
114+
}
115+
} else {
116+
/*Impossible option*/
117+
return -ENOTSUP;
118+
}
119+
120+
ret = nxp_sc18is606_claim(cfg->bridge);
121+
if(ret < 0) {
122+
LOG_ERR("Failed to claim the bridge (%d)", ret);
123+
return ret;
124+
}
125+
126+
data->conf |= pin_conf << (pin * 2);
127+
buf[1] = data->conf;
128+
129+
ret = nxp_sc18is606_transfer(cfg->bridge, buf, sizeof(buf), NULL, 0, NULL);
130+
if(ret < 0) {
131+
LOG_ERR("Failed to configure GPIO (%d)", ret);
132+
}
133+
134+
if(ret == 0 && flags & GPIO_OUTPUT) {
135+
if(flags & GPIO_OUTPUT_INIT_HIGH) {
136+
gpio_sc18is606_port_set_raw(port, BIT(pin), BIT(pin), 0);
137+
}
138+
if(flags & GPIO_OUTPUT_INIT_LOW) {
139+
gpio_sc18is606_port_set_raw(port, BIT(pin), 0, 0);
140+
}
141+
}
142+
143+
nxp_sc18is606_release(cfg->bridge);
144+
145+
146+
return ret;
147+
}
148+
149+
static int gpio_sc18is606_port_get_raw(const struct device *port, gpio_port_value_t *value)
150+
{
151+
const struct gpio_sc18is606_config *cfg = port->config;
152+
153+
uint8_t buf[] = {
154+
SC18IS606_GPIO_READ,
155+
};
156+
uint8_t data;
157+
int ret;
158+
159+
if(k_is_in_isr()) {
160+
return -EWOULDBLOCK;
161+
}
162+
163+
ret = nxp_sc18is606_transfer(cfg->bridge, buf, sizeof(buf), &data, 1, NULL);
164+
if(ret < 0) {
165+
LOG_ERR("Failed to read GPIO state(%d)", ret);
166+
return ret;
167+
}
168+
169+
*value = data;
170+
171+
return 0;
172+
}
173+
174+
static int gpio_sc18is606_port_set_masked_raw(const struct device *port,
175+
gpio_port_pins_t mask,
176+
gpio_port_value_t value)
177+
{
178+
return gpio_sc18is606_port_set_raw(port, (uint8_t)mask, (uint8_t)value, 0);
179+
}
180+
181+
static int gpio_sc18is606_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins)
182+
{
183+
return gpio_sc18is606_port_set_raw(port, (uint8_t)pins, (uint8_t)pins, 0);
184+
}
185+
186+
static int gpio_sc18is606_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins)
187+
{
188+
return gpio_sc18is606_port_set_raw(port, (uint8_t)pins, 0, 0);
189+
}
190+
static int gpio_sc18is606_port_toggle_bits(const struct device *port, gpio_port_pins_t pins)
191+
{
192+
return gpio_sc18is606_port_set_raw(port, 0, 0, (uint8_t)pins);
193+
}
194+
195+
static int gpio_sc18is606_init(const struct device *dev)
196+
{
197+
const struct gpio_sc18is606_config *cfg = dev->config;
198+
199+
if(!device_is_ready(cfg->bridge)) {
200+
LOG_ERR("Parent device not ready");
201+
return -ENODEV;
202+
}
203+
204+
return 0;
205+
}
206+
207+
208+
static DEVICE_API(gpio, gpio_sc18is606_driver_api) = {
209+
.pin_configure = gpio_sc18is606_pin_configure,
210+
.port_get_raw = gpio_sc18is606_port_get_raw,
211+
.port_set_masked_raw = gpio_sc18is606_port_set_masked_raw,
212+
.port_set_bits_raw = gpio_sc18is606_port_set_bits_raw,
213+
.port_clear_bits_raw = gpio_sc18is606_port_clear_bits_raw,
214+
.port_toggle_bits = gpio_sc18is606_port_toggle_bits,
215+
};
216+
217+
218+
#define CHECK_COMPAT(node) \
219+
COND_CODE_1(DT_NODE_HAS_COMPAT(node, nxp_sc18is606_spi), (DEVICE_DT_GET(node)), ())
220+
221+
#define GPIO_SC18IS606_SPI_SIBLING(n) \ DT_FOREACH_CHILD_STATUS_OKAY(DT_INST_PARENT(n), CHECK_COMPAT)
222+
223+
#define GPIO_SC18IS606_DEFINE(inst) \ static const struct gpio_sc18is606_config gpio_sc18is606_config##inst = { \
224+
.common = { \
225+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \
226+
}, \
227+
.bridge = GPIO_SC18IS606_SPI_SIBLING(inst), \
228+
}; \
229+
static struct gpio_sc18is606_data gpio_sc18is606_data##inst = { \
230+
.conf = 0x00, \
231+
}; \
232+
\
233+
DEVICE_DT_INST_DEFINE(inst, gpio_sc18is606_init, NULL, \
234+
&gpio_sc18is606_data##inst, &gpio_sc18is606_config_##inst, \
235+
POST_KERNEL, CONFIG_GPIO_SC18IS606_INIT_PRIORITY, \
236+
&gpio_sc18is606_driver_api);
237+
238+
DT_INST_FOREACH_STATUS_OKAY(GPIO_SC18IS606_DEFINE);
239+
240+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c), 2025 tinyvision.ai
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
5+
description: GPIO Controller part for the SC18IS606 bridge
6+
7+
compatible: "nxp,sc18is606-gpio"
8+
9+
include: gpio-controller.yaml
10+
11+
properties:
12+
"#gpio-cells":
13+
required: true
14+
const: 2
15+
16+
ngpios:
17+
required: true
18+
const: 3
19+
20+
gpio-cells:
21+
- pin
22+
- flags
23+
24+
on-bus: nxp,sc18is606

dts/bindings/mfd/nxp,sc18is606.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ description: |
2424
#address-cells = <1>;
2525
#size-cells = <0>;
2626
};
27+
28+
gpio_ext: sc18is606_gpio {
29+
compatible = "nxp,sc18is606-gpio";
30+
status = "okay";
31+
gpio-controller;
32+
#gpio-cells = <2>;
33+
ngpios = <3>;
34+
};
2735
};
2836
};
2937

0 commit comments

Comments
 (0)