Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/gpio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SAM gpio_sam.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SAM0 gpio_sam0.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SEESAW gpio_seesaw.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SI32 gpio_si32.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SIFIVE gpio_sifive.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SILABS_SIWX91X gpio_silabs_siwx91x.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ source "drivers/gpio/Kconfig.sam"
source "drivers/gpio/Kconfig.sam0"
source "drivers/gpio/Kconfig.sc18im704"
source "drivers/gpio/Kconfig.sedi"
source "drivers/gpio/Kconfig.seesaw"
source "drivers/gpio/Kconfig.si32"
source "drivers/gpio/Kconfig.sifive"
source "drivers/gpio/Kconfig.siwx91x"
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpio/Kconfig.seesaw
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2025 Titouan Chrisotphe
# SPDX-License-Identifier: Apache-2.0

config GPIO_SEESAW
bool "Adafruit Seesaw GPIO over I2C"
default y
depends on MFD_SEESAW
depends on DT_HAS_ADAFRUIT_SEESAW_GPIO_ENABLED
help
Enable support for Adafruit Seesaw gpio
128 changes: 128 additions & 0 deletions drivers/gpio/gpio_seesaw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright (c) 2025 Titouan Christophe
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT adafruit_seesaw_gpio

#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/mfd/mfd_seesaw.h>

enum seesaw_mod_gpio {
GPIO_DIRSET = 0x02,
GPIO_DIRCLR = 0x03,
GPIO_GPIO = 0x04,
GPIO_SET = 0x05,
GPIO_CLR = 0x06,
GPIO_TOGGLE = 0x07,
GPIO_INTENSET = 0x08,
GPIO_INTENCLR = 0x09,
GPIO_INTFLAG = 0x0a,
GPIO_PULLENSET = 0x0b,
GPIO_PULLENCLR = 0x0c,
};

struct seesaw_gpio_config {
const struct device *seesaw;
};

static int seesaw_gpio_configure(const struct device *dev,
gpio_pin_t pin, gpio_flags_t flags)
{
const struct seesaw_gpio_config *const config = dev->config;

if (flags & GPIO_OUTPUT) {
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_DIRSET, BIT(pin));
} else if (flags & GPIO_INPUT) {
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_DIRCLR, BIT(pin));
} else {
return -ENOTSUP;
}

if (flags & GPIO_PULL_UP) {
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_SET, BIT(pin));
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_PULLENSET, BIT(pin));
} else if (flags & GPIO_PULL_DOWN) {
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_CLR, BIT(pin));
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_PULLENSET, BIT(pin));
}

return 0;
}

static int seesaw_gpio_port_get_raw(const struct device *dev, uint32_t *value)
{
uint32_t tmp;
const struct seesaw_gpio_config *const config = dev->config;
int ret = seesaw_read(config->seesaw, SEESAW_MOD_GPIO, GPIO_GPIO, (uint8_t *) &tmp, 4);

if (ret == 0) {
*value = sys_be32_to_cpu(ret);
}

return ret;
}

static int seesaw_gpio_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
{
const struct seesaw_gpio_config *const config = dev->config;

seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_SET, value & mask);
seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_CLR, ~value & mask);

return 0;
}

static int seesaw_gpio_port_set_bits_raw(const struct device *dev, uint32_t mask)
{
const struct seesaw_gpio_config *const config = dev->config;

seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_SET, mask);

return 0;
}

static int seesaw_gpio_port_clear_bits_raw(const struct device *dev, uint32_t mask)
{
const struct seesaw_gpio_config *const config = dev->config;

seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_CLR, mask);

return 0;
}

static int seesaw_gpio_port_toggle_bits(const struct device *dev, uint32_t mask)
{
const struct seesaw_gpio_config *const config = dev->config;

seesaw_write_uint32(config->seesaw, SEESAW_MOD_GPIO, GPIO_TOGGLE, mask);

return 0;
}


static DEVICE_API(gpio, seesaw_gpio_api) = {
.pin_configure = seesaw_gpio_configure,
.port_get_raw = seesaw_gpio_port_get_raw,
.port_set_masked_raw = seesaw_gpio_port_set_masked_raw,
.port_set_bits_raw = seesaw_gpio_port_set_bits_raw,
.port_clear_bits_raw = seesaw_gpio_port_clear_bits_raw,
.port_toggle_bits = seesaw_gpio_port_toggle_bits,
};

static int seesaw_gpio_init(const struct device *dev)
{
const struct seesaw_gpio_config *config = dev->config;

return seesaw_claim_module(config->seesaw, SEESAW_MOD_GPIO, dev);
}

#define SEESAW_GPIO_INIT(inst) \
static const struct seesaw_gpio_config config_##inst = { \
.seesaw = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
}; \
DEVICE_DT_INST_DEFINE(inst, seesaw_gpio_init, NULL, NULL, &config_##inst, \
POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, &seesaw_gpio_api);

DT_INST_FOREACH_STATUS_OKAY(SEESAW_GPIO_INIT)
1 change: 1 addition & 0 deletions drivers/input/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_PINNACLE input_pinnacle.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_PMW3610 input_pmw3610.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_REALTEK_RTS5912_KBD input_realtek_rts5912_kbd.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_SBUS input_sbus.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_SEESAW_KEYPAD input_seesaw_keypad.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_STM32_TSC_KEYS input_tsc_keys.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c)
zephyr_library_sources_ifdef(CONFIG_INPUT_TOUCH input_touch.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/input/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ source "drivers/input/Kconfig.pmw3610"
source "drivers/input/Kconfig.rts5912"
source "drivers/input/Kconfig.sbus"
source "drivers/input/Kconfig.sdl"
source "drivers/input/Kconfig.seesaw_keypad"
source "drivers/input/Kconfig.stmpe811"
source "drivers/input/Kconfig.touch"
source "drivers/input/Kconfig.tsc_keys"
Expand Down
18 changes: 18 additions & 0 deletions drivers/input/Kconfig.seesaw_keypad
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2025 Titouan Christophe
# SPDX-License-Identifier: Apache-2.0

config INPUT_SEESAW_KEYPAD
bool "Adafruit seesaw keypad over I2C"
default y
depends on DT_HAS_ADAFRUIT_SEESAW_KEYPAD_ENABLED
depends on MFD_SEESAW
help
Enable support for Adafruit Seesaw gpio

if INPUT_SEESAW_KEYPAD

config INPUT_SEESAW_KEYPAD_POLL_INTERVAL
int "Event poll interval (ms)"
default 25

endif
116 changes: 116 additions & 0 deletions drivers/input/input_seesaw_keypad.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2025 Titouan Christophe
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT adafruit_seesaw_keypad

#include <zephyr/input/input.h>
#include <zephyr/drivers/mfd/mfd_seesaw.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(seesaw_keypad, CONFIG_MFD_SEESAW_LOG_LEVEL);

enum {
KEYPAD_STATUS = 0x00,
KEYPAD_EVENT = 0x01,
KEYPAD_INTENSET = 0x02,
KEYPAD_INTENCLR = 0x03,
KEYPAD_COUNT = 0x04,
KEYPAD_FIFO = 0x10,
};

enum key_edge {
EDGE_HIGH = 0,
EDGE_LOW = 1,
EDGE_FALLING = 2,
EDGE_RISING = 3,
};

struct seesaw_keypad_config {
const struct device *seesaw;
};

struct seesaw_keypad_data {
const struct device *dev;
struct k_work_delayable work;
};

static int seesaw_keypad_get_event(const struct device *dev)
{
const struct seesaw_keypad_config *config = dev->config;
uint8_t keypad_event;
int ret = seesaw_read(config->seesaw, SEESAW_MOD_KEYPAD, KEYPAD_FIFO, &keypad_event, 1);

if (ret < 0) {
LOG_ERR("Error polling events FIFO: %d", ret);
return ret;
}

if (keypad_event == 0xff) {
/* Reached end of FIFO */
return 0;
}

input_report(dev, INPUT_EV_KEY, (keypad_event >> 2), (keypad_event & 1), true, K_NO_WAIT);
return 1;
}

static void seesaw_keypad_poll(struct k_work *work)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
struct seesaw_keypad_data *drv_data = CONTAINER_OF(dwork, struct seesaw_keypad_data, work);

while (seesaw_keypad_get_event(drv_data->dev) > 0) {
continue;
}

k_work_reschedule(dwork, K_MSEC(CONFIG_INPUT_SEESAW_KEYPAD_POLL_INTERVAL));
}

static int seesaw_keypad_init(const struct device *dev)
{
int ret;
struct seesaw_keypad_data *drv_data = dev->data;
const struct seesaw_keypad_config *config = dev->config;
/* Enable RISE/FALL events on all keys */
uint8_t edges = BIT(EDGE_RISING) | BIT(EDGE_FALLING);

ret = seesaw_claim_module(config->seesaw, SEESAW_MOD_KEYPAD, dev);
if (ret) {
return ret;
}

drv_data->dev = dev;
k_work_init_delayable(&drv_data->work, seesaw_keypad_poll);

for (int i = 0; i < 16; i++) {
uint8_t buf[] = {
(i & 0xc) << 1 | (i & 0x03),
(edges << 1) | 1,
};

ret = seesaw_write(config->seesaw, SEESAW_MOD_KEYPAD, KEYPAD_EVENT,
buf, sizeof(buf));
if (ret) {
LOG_ERR("Unable to configure keypad event: %d", ret);
return ret;
}
}

k_work_reschedule(&drv_data->work, K_MSEC(CONFIG_INPUT_SEESAW_KEYPAD_POLL_INTERVAL));
LOG_DBG("%s initialized", dev->name);

return 0;
}

#define SEESAW_KEYPAD_INIT(inst) \
static struct seesaw_keypad_data data_##inst; \
static const struct seesaw_keypad_config config_##inst = { \
.seesaw = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
}; \
DEVICE_DT_INST_DEFINE(inst, seesaw_keypad_init, NULL, &data_##inst, &config_##inst, \
POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL);

DT_INST_FOREACH_STATUS_OKAY(SEESAW_KEYPAD_INIT)
1 change: 1 addition & 0 deletions drivers/led/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_LP5562 lp5562.c)
zephyr_library_sources_ifdef(CONFIG_LP5569 lp5569.c)
zephyr_library_sources_ifdef(CONFIG_NCP5623 ncp5623.c)
zephyr_library_sources_ifdef(CONFIG_PCA9633 pca9633.c)
zephyr_library_sources_ifdef(CONFIG_SEESAW_NEOPIXEL seesaw_neopixel.c)
zephyr_library_sources_ifdef(CONFIG_TLC59108 tlc59108.c)
# zephyr-keep-sorted-stop

Expand Down
1 change: 1 addition & 0 deletions drivers/led/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ source "drivers/led/Kconfig.ncp5623"
source "drivers/led/Kconfig.npm1300"
source "drivers/led/Kconfig.pca9633"
source "drivers/led/Kconfig.pwm"
source "drivers/led/Kconfig.seesaw_neopixel"
source "drivers/led/Kconfig.tlc59108"
source "drivers/led/Kconfig.xec"
# zephyr-keep-sorted-stop
Expand Down
10 changes: 10 additions & 0 deletions drivers/led/Kconfig.seesaw_neopixel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2025 Titouan Chrisotphe
# SPDX-License-Identifier: Apache-2.0

config SEESAW_NEOPIXEL
bool "Adafruit Seesaw neopixel leds over I2C"
default y
depends on MFD_SEESAW
depends on DT_HAS_ADAFRUIT_SEESAW_NEOPIXEL_ENABLED
help
Enable support for Adafruit Seesaw neopixel leds
Loading