Browse Source

drivers: gpio: split up driver for BD8LB600FS into a GPIO and MFD

Split up the driver for the low side switch BD8LB600FS into a GPIO
and MFD part.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
pull/70276/head
Benedikt Schmidt 2 years ago committed by Alberto Escolar
parent
commit
31450fcb12
  1. 5
      drivers/gpio/Kconfig.bd8lb600fs
  2. 212
      drivers/gpio/gpio_bd8lb600fs.c
  3. 1
      drivers/mfd/CMakeLists.txt
  4. 1
      drivers/mfd/Kconfig
  5. 11
      drivers/mfd/Kconfig.bd8lb600fs
  6. 242
      drivers/mfd/mfd_bd8lb600fs.c
  7. 17
      dts/bindings/gpio/rohm,bd8lb600fs-gpio.yaml
  8. 31
      dts/bindings/mfd/rohm,bd8lb600fs.yaml
  9. 60
      include/zephyr/drivers/mfd/bd8lb600fs.h
  10. 3
      tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.conf
  11. 13
      tests/drivers/build_all/gpio/app.overlay
  12. 1
      tests/drivers/build_all/gpio/prj.conf

5
drivers/gpio/Kconfig.bd8lb600fs

@ -1,13 +1,14 @@ @@ -1,13 +1,14 @@
# BD8LB600FS GPIO configuration options
# Copyright (c) 2022 SILA Embedded Solutions GmbH
# Copyright (c) 2024 SILA Embedded Solutions GmbH
# SPDX-License-Identifier: Apache-2.0
menuconfig GPIO_BD8LB600FS
bool "BD8LB600FS SPI-based GPIO chip"
default y
depends on DT_HAS_ROHM_BD8LB600FS_ENABLED
depends on SPI
depends on DT_HAS_ROHM_BD8LB600FS_GPIO_ENABLED
select MFD
help
Enable driver for BD8LB600FS SPI-based GPIO chip.

212
drivers/gpio/gpio_bd8lb600fs.c

@ -1,111 +1,51 @@ @@ -1,111 +1,51 @@
/*
* Copyright (c) 2022 SILA Embedded Solutions GmbH
* Copyright (c) 2024 SILA Embedded Solutions GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT rohm_bd8lb600fs
#include <errno.h>
#define DT_DRV_COMPAT rohm_bd8lb600fs_gpio
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/mfd/bd8lb600fs.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
LOG_MODULE_REGISTER(gpio_bd8lb600fs, CONFIG_GPIO_LOG_LEVEL);
#define OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION 0b11
#define OUTPUT_ON 0b10
#define WAIT_TIME_RESET_ACTIVE_IN_US 1000
#define WAIT_TIME_RESET_INACTIVE_TO_CS_IN_US 10
struct bd8lb600fs_config {
struct bd8lb600fs_gpio_config {
/* gpio_driver_config needs to be first */
struct gpio_driver_config common;
struct spi_dt_spec bus;
const struct gpio_dt_spec gpio_reset;
const struct device *parent_dev;
int gpios_count;
};
struct bd8lb600fs_drv_data {
struct bd8lb600fs_gpio_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data data;
uint32_t state; /* each bit is one output channel, bit 0 = channel 1, ... */
uint32_t configured; /* each bit defines if the output channel is configured, see state */
/* each bit is one output channel, bit 0 = channel 1, ... */
uint32_t state;
/* each bit defines if the output channel is configured, see state */
uint32_t configured;
struct k_mutex lock;
int instance_count_actual;
int gpios_count_actual;
};
static int write_state(const struct device *dev, uint32_t state)
{
const struct bd8lb600fs_config *config = dev->config;
struct bd8lb600fs_drv_data *drv_data = dev->data;
LOG_DBG("%s: writing state 0x%08X to BD8LB600FS", dev->name, state);
uint16_t state_converted = 0;
uint8_t buffer_tx[8];
const struct spi_buf tx_buf = {
.buf = buffer_tx,
.len = drv_data->instance_count_actual * sizeof(state_converted),
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1,
};
memset(buffer_tx, 0x00, sizeof(buffer_tx));
for (size_t j = 0; j < drv_data->instance_count_actual; ++j) {
int instance_position = (drv_data->instance_count_actual - j - 1) * 2;
state_converted = 0;
for (size_t i = 0; i < 8; ++i) {
if ((state & BIT(i + j*8)) == 0) {
state_converted |= OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION << (i * 2);
} else {
state_converted |= OUTPUT_ON << (i * 2);
}
}
LOG_DBG("%s: configuration for instance %zu: %04X (position %i)",
dev->name,
j,
state_converted,
instance_position);
sys_put_be16(state_converted, buffer_tx + instance_position);
}
LOG_HEXDUMP_DBG(buffer_tx, ARRAY_SIZE(buffer_tx), "configuration written out");
int result = spi_write_dt(&config->bus, &tx);
if (result != 0) {
LOG_ERR("spi_write failed with error %i", result);
return result;
}
return 0;
}
static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
static int bd8lb600fs_gpio_pin_configure(const struct device *dev, gpio_pin_t pin,
gpio_flags_t flags)
{
struct bd8lb600fs_drv_data *drv_data = dev->data;
const struct bd8lb600fs_gpio_config *config = dev->config;
struct bd8lb600fs_gpio_data *data = dev->data;
/* cannot execute a bus operation in an ISR context */
if (k_is_in_isr()) {
return -EWOULDBLOCK;
}
if (pin >= drv_data->gpios_count_actual) {
if (pin >= config->gpios_count) {
LOG_ERR("invalid pin number %i", pin);
return -EINVAL;
}
@ -140,158 +80,126 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp @@ -140,158 +80,126 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp
return -ENOTSUP;
}
k_mutex_lock(&drv_data->lock, K_FOREVER);
k_mutex_lock(&data->lock, K_FOREVER);
if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
WRITE_BIT(drv_data->state, pin, 0);
WRITE_BIT(data->state, pin, 0);
} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
WRITE_BIT(drv_data->state, pin, 1);
WRITE_BIT(data->state, pin, 1);
}
WRITE_BIT(drv_data->configured, pin, 1);
WRITE_BIT(data->configured, pin, 1);
int result = write_state(dev, drv_data->state);
int result = mfd_bd8lb600fs_set_outputs(config->parent_dev, data->state);
k_mutex_unlock(&drv_data->lock);
k_mutex_unlock(&data->lock);
return result;
}
static int bd8lb600fs_port_get_raw(const struct device *dev, uint32_t *value)
static int bd8lb600fs_gpio_port_get_raw(const struct device *dev, uint32_t *value)
{
LOG_ERR("input pins are not available");
return -ENOTSUP;
}
static int bd8lb600fs_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
static int bd8lb600fs_gpio_port_set_masked_raw(const struct device *dev, uint32_t mask,
uint32_t value)
{
struct bd8lb600fs_drv_data *drv_data = dev->data;
const struct bd8lb600fs_gpio_config *config = dev->config;
struct bd8lb600fs_gpio_data *data = dev->data;
/* cannot execute a bus operation in an ISR context */
if (k_is_in_isr()) {
return -EWOULDBLOCK;
}
k_mutex_lock(&drv_data->lock, K_FOREVER);
drv_data->state = (drv_data->state & ~mask) | (mask & value);
k_mutex_lock(&data->lock, K_FOREVER);
data->state = (data->state & ~mask) | (mask & value);
int result = write_state(dev, drv_data->state);
int result = mfd_bd8lb600fs_set_outputs(config->parent_dev, data->state);
k_mutex_unlock(&drv_data->lock);
k_mutex_unlock(&data->lock);
return result;
}
static int bd8lb600fs_port_set_bits_raw(const struct device *dev, uint32_t mask)
static int bd8lb600fs_gpio_port_set_bits_raw(const struct device *dev, uint32_t mask)
{
return bd8lb600fs_port_set_masked_raw(dev, mask, mask);
return bd8lb600fs_gpio_port_set_masked_raw(dev, mask, mask);
}
static int bd8lb600fs_port_clear_bits_raw(const struct device *dev, uint32_t mask)
static int bd8lb600fs_gpio_port_clear_bits_raw(const struct device *dev, uint32_t mask)
{
return bd8lb600fs_port_set_masked_raw(dev, mask, 0);
return bd8lb600fs_gpio_port_set_masked_raw(dev, mask, 0);
}
static int bd8lb600fs_port_toggle_bits(const struct device *dev, uint32_t mask)
static int bd8lb600fs_gpio_port_toggle_bits(const struct device *dev, uint32_t mask)
{
struct bd8lb600fs_drv_data *drv_data = dev->data;
const struct bd8lb600fs_gpio_config *config = dev->config;
struct bd8lb600fs_gpio_data *data = dev->data;
/* cannot execute a bus operation in an ISR context */
if (k_is_in_isr()) {
return -EWOULDBLOCK;
}
k_mutex_lock(&drv_data->lock, K_FOREVER);
drv_data->state ^= mask;
k_mutex_lock(&data->lock, K_FOREVER);
data->state ^= mask;
int result = write_state(dev, drv_data->state);
int result = mfd_bd8lb600fs_set_outputs(config->parent_dev, data->state);
k_mutex_unlock(&drv_data->lock);
k_mutex_unlock(&data->lock);
return result;
}
static const struct gpio_driver_api api_table = {
.pin_configure = bd8lb600fs_pin_configure,
.port_get_raw = bd8lb600fs_port_get_raw,
.port_set_masked_raw = bd8lb600fs_port_set_masked_raw,
.port_set_bits_raw = bd8lb600fs_port_set_bits_raw,
.port_clear_bits_raw = bd8lb600fs_port_clear_bits_raw,
.port_toggle_bits = bd8lb600fs_port_toggle_bits,
.pin_configure = bd8lb600fs_gpio_pin_configure,
.port_get_raw = bd8lb600fs_gpio_port_get_raw,
.port_set_masked_raw = bd8lb600fs_gpio_port_set_masked_raw,
.port_set_bits_raw = bd8lb600fs_gpio_port_set_bits_raw,
.port_clear_bits_raw = bd8lb600fs_gpio_port_clear_bits_raw,
.port_toggle_bits = bd8lb600fs_gpio_port_toggle_bits,
};
static int bd8lb600fs_init(const struct device *dev)
static int bd8lb600fs_gpio_init(const struct device *dev)
{
const struct bd8lb600fs_config *config = dev->config;
struct bd8lb600fs_drv_data *drv_data = dev->data;
if (!spi_is_ready_dt(&config->bus)) {
LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
return -ENODEV;
}
const struct bd8lb600fs_gpio_config *config = dev->config;
struct bd8lb600fs_gpio_data *data = dev->data;
if (!gpio_is_ready_dt(&config->gpio_reset)) {
LOG_ERR("%s: reset GPIO is not ready", dev->name);
if (!device_is_ready(config->parent_dev)) {
LOG_ERR("MFD parent is not ready");
return -ENODEV;
}
int result = k_mutex_init(&drv_data->lock);
int result = k_mutex_init(&data->lock);
if (result != 0) {
LOG_ERR("unable to initialize mutex");
return result;
}
drv_data->instance_count_actual = config->gpios_count / 8;
if (config->gpios_count % 8 != 0) {
LOG_ERR("%s: number of GPIOs %i is not a multiple of 8",
dev->name, config->gpios_count);
return -EINVAL;
}
if (drv_data->instance_count_actual > 4) {
LOG_ERR("%s: only a maximum of 4 devices are supported for the daisy chaining",
dev->name);
return -EINVAL;
}
drv_data->gpios_count_actual = drv_data->instance_count_actual * 8;
result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE);
if (result != 0) {
LOG_ERR("failed to initialize GPIO for reset");
return result;
}
k_busy_wait(WAIT_TIME_RESET_ACTIVE_IN_US);
gpio_pin_set_dt(&config->gpio_reset, 0);
k_busy_wait(WAIT_TIME_RESET_INACTIVE_TO_CS_IN_US);
return 0;
}
#define BD8LB600FS_INIT(inst) \
static const struct bd8lb600fs_config bd8lb600fs_##inst##_config = { \
#define BD8LB600FS_GPIO_INIT(inst) \
static const struct bd8lb600fs_gpio_config bd8lb600fs_##inst##_config = { \
.common = \
{ \
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \
}, \
.bus = SPI_DT_SPEC_INST_GET( \
inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \
.gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), reset_gpios, 0), \
.gpios_count = DT_INST_PROP(inst, ngpios), \
.parent_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
.gpios_count = DT_INST_PROP(inst, ngpios), \
}; \
\
static struct bd8lb600fs_drv_data bd8lb600fs_##inst##_drvdata = { \
static struct bd8lb600fs_gpio_data bd8lb600fs_##inst##_data = { \
.state = 0x00, \
.configured = 0x00, \
}; \
\
/* This has to be initialized after the SPI peripheral. */ \
DEVICE_DT_INST_DEFINE(inst, bd8lb600fs_init, NULL, &bd8lb600fs_##inst##_drvdata, \
DEVICE_DT_INST_DEFINE(inst, bd8lb600fs_gpio_init, NULL, &bd8lb600fs_##inst##_data, \
&bd8lb600fs_##inst##_config, POST_KERNEL, \
CONFIG_GPIO_BD8LB600FS_INIT_PRIORITY, &api_table);
DT_INST_FOREACH_STATUS_OKAY(BD8LB600FS_INIT)
DT_INST_FOREACH_STATUS_OKAY(BD8LB600FS_GPIO_INIT)

1
drivers/mfd/CMakeLists.txt

@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c)
zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c)
zephyr_library_sources_ifdef(CONFIG_MFD_AD5592 mfd_ad5592.c)
zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c)
zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c)

1
drivers/mfd/Kconfig

@ -20,6 +20,7 @@ config MFD_INIT_PRIORITY @@ -20,6 +20,7 @@ config MFD_INIT_PRIORITY
source "drivers/mfd/Kconfig.ad5592"
source "drivers/mfd/Kconfig.axp192"
source "drivers/mfd/Kconfig.bd8lb600fs"
source "drivers/mfd/Kconfig.max20335"
source "drivers/mfd/Kconfig.nct38xx"
source "drivers/mfd/Kconfig.npm1300"

11
drivers/mfd/Kconfig.bd8lb600fs

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
# Copyright (c) 2024 SILA Embedded Solutions GmbH
# SPDX -License-Identifier: Apache-2.0
config MFD_BD8LB600FS
bool "BD8LB600FS low side switch multi-function device driver"
default y
depends on DT_HAS_ROHM_BD8LB600FS_ENABLED
# using select SPI at this point introduces a cyclic dependency
depends on SPI
help
Enable the Rohm BD8LB600FS low side switch multi-function device driver

242
drivers/mfd/mfd_bd8lb600fs.c

@ -0,0 +1,242 @@ @@ -0,0 +1,242 @@
/*
* Copyright (c) 2024 SILA Embedded Solutions GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT rohm_bd8lb600fs
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/drivers/mfd/bd8lb600fs.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
LOG_MODULE_REGISTER(rohm_bd8lb600fs, CONFIG_MFD_LOG_LEVEL);
#define OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION 0b11
#define OUTPUT_ON 0b10
#define WAIT_TIME_RESET_ACTIVE_IN_US 1000
#define WAIT_TIME_RESET_INACTIVE_TO_CS_IN_US 10
struct bd8lb600fs_config {
struct spi_dt_spec bus;
const struct gpio_dt_spec gpio_reset;
size_t instance_count;
};
struct bd8lb600fs_data {
/* each bit is one output channel, bit 0 = channel 1, ... */
uint32_t state;
/* each bit defines if an open load was detected, see state */
uint32_t old;
/* each bit defines if an over current or over temperature was detected, see state */
uint32_t ocp_or_tsd;
struct k_mutex lock;
};
static void bd8lb600fs_fill_tx_buffer(const struct device *dev, uint8_t *buffer, size_t buffer_size)
{
const struct bd8lb600fs_config *config = dev->config;
struct bd8lb600fs_data *data = dev->data;
uint16_t state_converted = 0;
LOG_DBG("%s: writing state 0x%08X to BD8LB600FS", dev->name, data->state);
memset(buffer, 0x00, buffer_size);
for (size_t j = 0; j < config->instance_count; ++j) {
int instance_position = (config->instance_count - j - 1) * 2;
state_converted = 0;
for (size_t i = 0; i < 8; ++i) {
if ((data->state & BIT(i + j * 8)) == 0) {
state_converted |= OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION << (i * 2);
} else {
state_converted |= OUTPUT_ON << (i * 2);
}
}
LOG_DBG("%s: configuration for instance %zu: %04X (position %i)", dev->name, j,
state_converted, instance_position);
sys_put_be16(state_converted, buffer + instance_position);
}
}
static void bd8lb600fs_parse_rx_buffer(const struct device *dev, uint8_t *buffer)
{
const struct bd8lb600fs_config *config = dev->config;
struct bd8lb600fs_data *data = dev->data;
data->old = 0;
data->ocp_or_tsd = 0;
for (size_t j = 0; j < config->instance_count; ++j) {
int instance_position = (config->instance_count - j - 1) * 2;
uint16_t current = sys_get_be16(buffer + instance_position);
for (size_t i = 0; i < 8; ++i) {
if ((BIT(2 * i + 1) & current) != 0) {
WRITE_BIT(data->old, i + j * 8, 1);
}
if ((BIT(2 * i) & current) != 0) {
WRITE_BIT(data->ocp_or_tsd, i + j * 8, 1);
}
}
}
LOG_DBG("%s: received 0x%08X open load state from BD8LB600FS", dev->name, data->old);
LOG_DBG("%s: received 0x%08X OCP or TSD state from BD8LB600FS", dev->name,
data->ocp_or_tsd);
}
static int bd8lb600fs_transceive_state(const struct device *dev)
{
const struct bd8lb600fs_config *config = dev->config;
uint8_t buffer_tx[8];
const struct spi_buf tx_buf = {
.buf = buffer_tx,
.len = config->instance_count * sizeof(uint16_t),
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1,
};
uint8_t buffer_rx[8];
const struct spi_buf rx_buf = {
.buf = buffer_rx,
.len = config->instance_count * sizeof(uint16_t),
};
const struct spi_buf_set rx = {
.buffers = &rx_buf,
.count = 1,
};
bd8lb600fs_fill_tx_buffer(dev, buffer_tx, ARRAY_SIZE(buffer_tx));
int result = spi_transceive_dt(&config->bus, &tx, &rx);
if (result != 0) {
LOG_ERR("spi_transceive failed with error %i", result);
return result;
}
bd8lb600fs_parse_rx_buffer(dev, buffer_rx);
return 0;
}
static int bd8lb600fs_write_state(const struct device *dev)
{
const struct bd8lb600fs_config *config = dev->config;
uint8_t buffer_tx[8];
const struct spi_buf tx_buf = {
.buf = buffer_tx,
.len = config->instance_count * sizeof(uint16_t),
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1,
};
bd8lb600fs_fill_tx_buffer(dev, buffer_tx, ARRAY_SIZE(buffer_tx));
int result = spi_write_dt(&config->bus, &tx);
if (result != 0) {
LOG_ERR("spi_transceive failed with error %i", result);
return result;
}
return 0;
}
int mfd_bd8lb600fs_set_outputs(const struct device *dev, uint32_t values)
{
struct bd8lb600fs_data *data = dev->data;
int result;
k_mutex_lock(&data->lock, K_FOREVER);
data->state = values;
result = bd8lb600fs_write_state(dev);
k_mutex_unlock(&data->lock);
return result;
}
int mfd_bd8lb600fs_get_output_diagnostics(const struct device *dev, uint32_t *old,
uint32_t *ocp_or_tsd)
{
struct bd8lb600fs_data *data = dev->data;
int result;
k_mutex_lock(&data->lock, K_FOREVER);
result = bd8lb600fs_transceive_state(dev);
*old = data->old;
*ocp_or_tsd = data->ocp_or_tsd;
k_mutex_unlock(&data->lock);
return result;
}
static int bd8lb600fs_init(const struct device *dev)
{
const struct bd8lb600fs_config *config = dev->config;
struct bd8lb600fs_data *data = dev->data;
if (!spi_is_ready_dt(&config->bus)) {
LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
return -ENODEV;
}
if (!gpio_is_ready_dt(&config->gpio_reset)) {
LOG_ERR("%s: reset GPIO is not ready", dev->name);
return -ENODEV;
}
int result = k_mutex_init(&data->lock);
if (result != 0) {
LOG_ERR("unable to initialize mutex");
return result;
}
result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE);
if (result != 0) {
LOG_ERR("failed to initialize GPIO for reset");
return result;
}
k_busy_wait(WAIT_TIME_RESET_ACTIVE_IN_US);
gpio_pin_set_dt(&config->gpio_reset, 0);
k_busy_wait(WAIT_TIME_RESET_INACTIVE_TO_CS_IN_US);
return 0;
}
#define BD8LB600FS_INIT(inst) \
static const struct bd8lb600fs_config bd8lb600fs_##inst##_config = { \
.bus = SPI_DT_SPEC_INST_GET( \
inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \
.gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), reset_gpios, 0), \
.instance_count = DT_INST_PROP(inst, instance_count), \
}; \
\
static struct bd8lb600fs_data bd8lb600fs_##inst##_data = { \
.state = 0x00, \
}; \
\
/* This has to be initialized after the SPI peripheral. */ \
DEVICE_DT_INST_DEFINE(inst, bd8lb600fs_init, NULL, &bd8lb600fs_##inst##_data, \
&bd8lb600fs_##inst##_config, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \
NULL);
DT_INST_FOREACH_STATUS_OKAY(BD8LB600FS_INIT)

17
dts/bindings/gpio/rohm,bd8lb600fs.yaml → dts/bindings/gpio/rohm,bd8lb600fs-gpio.yaml

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
#
# Copyright (c) 2022 SILA Embedded Solutions GmbH
# Copyright (c) 2024 SILA Embedded Solutions GmbH
#
# SPDX-License-Identifier: Apache-2.0
#
@ -9,9 +10,11 @@ description: | @@ -9,9 +10,11 @@ description: |
Multiple instances may be daisy chained, which can be configured
via the number of supported GPIOs.
compatible: "rohm,bd8lb600fs"
compatible: "rohm,bd8lb600fs-gpio"
include: [gpio-controller.yaml, spi-device.yaml]
include: gpio-controller.yaml
on-bus: bd8lb600fs
properties:
"#gpio-cells":
@ -20,16 +23,16 @@ properties: @@ -20,16 +23,16 @@ properties:
ngpios:
type: int
required: true
enum:
- 8
- 16
- 24
- 32
description: |
Number of pins for the expander. This must be a multiple of 8.
The number of pins also defines how many devices are daisy chained.
Set to 8 for one instance without daisy chaining.
reset-gpios:
type: phandle-array
required: true
description: GPIO for reset
gpio-cells:
- pin
- flags

31
dts/bindings/mfd/rohm,bd8lb600fs.yaml

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
#
# Copyright (c) 2024 SILA Embedded Solutions GmbH
#
# SPDX-License-Identifier: Apache-2.0
#
description: Rohm BD8LB600FS SPI Gpio Expander MFD
compatible: "rohm,bd8lb600fs"
include: spi-device.yaml
bus: bd8lb600fs
properties:
reset-gpios:
type: phandle-array
required: true
description: GPIO for reset
instance-count:
type: int
required: true
default: 1
enum:
- 1
- 2
- 3
- 4
description:
number of daisy chained instances, defaults to no daisy chaining

60
include/zephyr/drivers/mfd/bd8lb600fs.h

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
/*
* Copyright (c) 2024 SILA Embedded Solutions GmbH
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_BD8LB600FS_H_
#define ZEPHYR_INCLUDE_DRIVERS_MFD_BD8LB600FS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <zephyr/device.h>
/**
* @defgroup mdf_interface_bd8lb600fs MFD BD8LB600FS interface
* @ingroup mfd_interfaces
* @{
*/
/**
* @brief set outputs
*
* @param[in] dev instance of BD8LB600FS MFD
* @param[in] values values for outputs, one bit per output
*
* @retval 0 if successful
*/
int mfd_bd8lb600fs_set_outputs(const struct device *dev, uint32_t values);
/**
* @brief get output diagnostics
*
* Fetch the current diagnostics from all instances, as multiple
* instances might be daisy chained together. Each bit in old
* and ocp_or_tsd corresponds to one output. A set bit means that the
* function is active, therefore either there is an open load, an over
* current or a too high temperature.
*
* OLD - open load
* OCP - over current protection
* TSD - thermal shutdown
*
* @param[in] dev instance of BD8LB600FS MFD
* @param[out] old open load values
* @param[out] ocp_or_tsd over current protection or thermal shutdown values
*
* @retval 0 if successful
*/
int mfd_bd8lb600fs_get_output_diagnostics(const struct device *dev, uint32_t *old,
uint32_t *ocp_or_tsd);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_BD8LB600FS_H_ */

3
tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.conf

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
CONFIG_ADC=y
CONFIG_ADC_ADS114S0X_GPIO=y
CONFIG_ADC_INIT_PRIORITY=80
CONFIG_ADC_INIT_PRIORITY=81
CONFIG_GPIO_BD8LB600FS_INIT_PRIORITY=81

13
tests/drivers/build_all/gpio/app.overlay

@ -245,12 +245,19 @@ @@ -245,12 +245,19 @@
test_spi_bd8lb600fs: bd8lb600fs@2 {
compatible = "rohm,bd8lb600fs";
status = "okay";
spi-max-frequency = <0>;
reg = <0x02>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <8>;
reset-gpios = <&test_gpio 0 0>;
instance-count = <1>;
bd8lb600fs_gpio: bd8lb600fs_gpio {
compatible = "rohm,bd8lb600fs-gpio";
status = "okay";
gpio-controller;
#gpio-cells = <2>;
ngpios = <8>;
};
};
test_spi_ad5592: ad5592@3 {

1
tests/drivers/build_all/gpio/prj.conf

@ -4,3 +4,4 @@ CONFIG_TEST_USERSPACE=y @@ -4,3 +4,4 @@ CONFIG_TEST_USERSPACE=y
CONFIG_I2C=y
CONFIG_GPIO_PCA95XX_INTERRUPT=y
CONFIG_SPI=y
CONFIG_GPIO_BD8LB600FS_INIT_PRIORITY=81

Loading…
Cancel
Save