drivers: gpio: implement driver for TLE9104
Implement a driver for the powertrain switch TLE9104. Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
This commit is contained in:
parent
4d554dd30c
commit
bfb8eda025
4 changed files with 557 additions and 0 deletions
|
|
@ -84,6 +84,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_RA gpio_ra.c)
|
||||
|
|
|
|||
|
|
@ -226,6 +226,8 @@ source "drivers/gpio/Kconfig.efinix_sapphire"
|
|||
source "drivers/gpio/Kconfig.davinci"
|
||||
source "drivers/gpio/Kconfig.sedi"
|
||||
|
||||
source "drivers/gpio/Kconfig.tle9104"
|
||||
|
||||
source "drivers/gpio/Kconfig.altera"
|
||||
|
||||
source "drivers/gpio/Kconfig.bcm2711"
|
||||
|
|
|
|||
19
drivers/gpio/Kconfig.tle9104
Normal file
19
drivers/gpio/Kconfig.tle9104
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# TLE9104 GPIO configuration options
|
||||
|
||||
# Copyright (c) 2023 SILA Embedded Solutions GmbH
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig GPIO_TLE9104
|
||||
bool "TLE9104 SPI-based powertrain switch"
|
||||
default y
|
||||
depends on DT_HAS_INFINEON_TLE9104_ENABLED
|
||||
depends on SPI
|
||||
help
|
||||
Enable driver for TLE9104 SPI-based powertrain switch.
|
||||
|
||||
config GPIO_TLE9104_INIT_PRIORITY
|
||||
int "Init priority"
|
||||
default 75
|
||||
depends on GPIO_TLE9104
|
||||
help
|
||||
Device driver initialization priority.
|
||||
535
drivers/gpio/gpio_tle9104.c
Normal file
535
drivers/gpio/gpio_tle9104.c
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
* Copyright (c) 2023 SILA Embedded Solutions GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT infineon_tle9104
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#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/logging/log.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
LOG_MODULE_REGISTER(gpio_tle9104, CONFIG_GPIO_LOG_LEVEL);
|
||||
|
||||
/*
|
||||
* The values for the defines below as well as the register definitions were
|
||||
* taken from the datasheet, which can be found at:
|
||||
* https://www.infineon.com/dgdl/Infineon-TLE9104SH-DataSheet-v01_31-EN.pdf?fileId=5546d462766cbe86017676144d76581b
|
||||
*/
|
||||
#define TLE9104_RESET_DURATION_TIME_US 10
|
||||
#define TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US 200
|
||||
#define TLE9104_RESET_DURATION_WAIT_TIME_US 10
|
||||
#define TLE9104_GPIO_COUNT 4
|
||||
#define TLE9104_INITIALIZATION_TIMEOUT_MS 1
|
||||
#define TLE9104_ICVERSIONID 0xB1
|
||||
|
||||
#define TLE9104_FRAME_RW_POS 15
|
||||
#define TLE9104_FRAME_PARITY_POS 14
|
||||
#define TLE9104_FRAME_FAULTCOMMUNICATION_POS 13
|
||||
#define TLE9104_FRAME_FAULTGLOBAL_POS 12
|
||||
#define TLE9104_FRAME_ADDRESS_POS 8
|
||||
#define TLE9104_FRAME_DATA_POS 0
|
||||
|
||||
#define TLE9104_CFG_CWDTIME_LENGTH 2
|
||||
#define TLE9104_CFG_CWDTIME_POS 6
|
||||
|
||||
#define TLE9104_CTRL_OUT1ONS_BIT BIT(1)
|
||||
#define TLE9104_CTRL_OUT1ONC_BIT BIT(0)
|
||||
#define TLE9104_CFG_OUT1DD_BIT BIT(0)
|
||||
#define TLE9104_GLOBALSTATUS_OUTEN_BIT BIT(7)
|
||||
#define TLE9104_GLOBALSTATUS_POR_LATCH_BIT BIT(0)
|
||||
#define TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT BIT(13)
|
||||
|
||||
enum tle9104_register {
|
||||
TLE9104REGISTER_CTRL = 0x00,
|
||||
TLE9104REGISTER_CFG = 0x01,
|
||||
TLE9104REGISTER_GLOBALSTATUS = 0x07,
|
||||
TLE9104REGISTER_ICVID = 0x08,
|
||||
};
|
||||
|
||||
struct tle9104_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 gpio_dt_spec gpio_enable;
|
||||
const struct gpio_dt_spec gpio_control[TLE9104_GPIO_COUNT];
|
||||
};
|
||||
|
||||
struct tle9104_data {
|
||||
/* gpio_driver_data needs to be first */
|
||||
struct gpio_driver_data common;
|
||||
/* each bit is one output channel, bit 0 = OUT1, ... */
|
||||
uint8_t state;
|
||||
/* same as state, just kept for checking what has to be updated */
|
||||
uint8_t previous_state;
|
||||
/* each bit defines if the output channel is configured, see state */
|
||||
uint8_t configured;
|
||||
struct k_mutex lock;
|
||||
};
|
||||
|
||||
static void tle9104_set_cfg_cwdtime(uint8_t *destination, uint8_t value)
|
||||
{
|
||||
uint8_t length = TLE9104_CFG_CWDTIME_LENGTH;
|
||||
uint8_t pos = TLE9104_CFG_CWDTIME_POS;
|
||||
|
||||
*destination &= ~GENMASK(pos + length - 1, pos);
|
||||
*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
|
||||
}
|
||||
|
||||
static int tle9104_calculate_parity(uint16_t value)
|
||||
{
|
||||
int parity = 1 + POPCOUNT(value);
|
||||
|
||||
if ((value & BIT(TLE9104_FRAME_PARITY_POS)) != 0) {
|
||||
parity--;
|
||||
}
|
||||
|
||||
return parity % 2;
|
||||
}
|
||||
|
||||
static void tle9104_apply_parity(uint16_t *value)
|
||||
{
|
||||
int parity = tle9104_calculate_parity(*value);
|
||||
|
||||
WRITE_BIT(*value, TLE9104_FRAME_PARITY_POS, parity);
|
||||
}
|
||||
|
||||
static bool tle9104_check_parity(uint16_t value)
|
||||
{
|
||||
int parity = tle9104_calculate_parity(value);
|
||||
|
||||
return ((value & BIT(TLE9104_FRAME_PARITY_POS)) >> TLE9104_FRAME_PARITY_POS) == parity;
|
||||
}
|
||||
|
||||
static int tle9104_transceive_frame(const struct device *dev, bool write,
|
||||
enum tle9104_register write_reg, uint8_t write_data,
|
||||
enum tle9104_register *read_reg, uint8_t *read_data)
|
||||
{
|
||||
const struct tle9104_config *config = dev->config;
|
||||
uint16_t write_frame;
|
||||
uint16_t read_frame;
|
||||
int result;
|
||||
uint8_t buffer_tx[2];
|
||||
uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)];
|
||||
const struct spi_buf tx_buf[] = {{
|
||||
.buf = buffer_tx,
|
||||
.len = ARRAY_SIZE(buffer_tx),
|
||||
}};
|
||||
const struct spi_buf rx_buf[] = {{
|
||||
.buf = buffer_rx,
|
||||
.len = ARRAY_SIZE(buffer_rx),
|
||||
}};
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = tx_buf,
|
||||
.count = ARRAY_SIZE(tx_buf),
|
||||
};
|
||||
const struct spi_buf_set rx = {
|
||||
.buffers = rx_buf,
|
||||
.count = ARRAY_SIZE(rx_buf),
|
||||
};
|
||||
|
||||
write_frame = write_data << TLE9104_FRAME_DATA_POS;
|
||||
write_frame |= write_reg << TLE9104_FRAME_ADDRESS_POS;
|
||||
WRITE_BIT(write_frame, TLE9104_FRAME_RW_POS, write);
|
||||
tle9104_apply_parity(&write_frame);
|
||||
sys_put_be16(write_frame, buffer_tx);
|
||||
LOG_DBG("writing in register 0x%02X of TLE9104 value 0x%02X, complete frame 0x%04X",
|
||||
write_reg, write_data, write_frame);
|
||||
|
||||
result = spi_transceive_dt(&config->bus, &tx, &rx);
|
||||
if (result != 0) {
|
||||
LOG_ERR("spi_write failed with error %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
read_frame = sys_get_be16(buffer_rx);
|
||||
LOG_DBG("received complete frame 0x%04X", read_frame);
|
||||
|
||||
if (!tle9104_check_parity(read_frame)) {
|
||||
LOG_ERR("parity check for received frame of TLE9104 failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) {
|
||||
LOG_WRN("communication fault reported by TLE9104");
|
||||
}
|
||||
|
||||
*read_reg = FIELD_GET(GENMASK(TLE9104_FRAME_FAULTGLOBAL_POS - 1, TLE9104_FRAME_ADDRESS_POS),
|
||||
read_frame);
|
||||
*read_data = FIELD_GET(GENMASK(TLE9104_FRAME_ADDRESS_POS - 1, TLE9104_FRAME_DATA_POS),
|
||||
read_frame);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tle9104_write_register(const struct device *dev, enum tle9104_register reg,
|
||||
uint8_t value)
|
||||
{
|
||||
enum tle9104_register read_reg;
|
||||
uint8_t read_data;
|
||||
|
||||
return tle9104_transceive_frame(dev, true, reg, value, &read_reg, &read_data);
|
||||
}
|
||||
|
||||
static int tle9104_write_state(const struct device *dev)
|
||||
{
|
||||
const struct tle9104_config *config = dev->config;
|
||||
struct tle9104_data *data = dev->data;
|
||||
bool spi_update_required = false;
|
||||
uint8_t register_ctrl = 0x00;
|
||||
int result;
|
||||
|
||||
LOG_DBG("writing state 0x%02X to TLE9104", data->state);
|
||||
|
||||
for (size_t i = 0; i < TLE9104_GPIO_COUNT; ++i) {
|
||||
uint8_t mask = GENMASK(i, i);
|
||||
bool current_value = (data->state & mask) != 0;
|
||||
bool previous_value = (data->previous_state & mask) != 0;
|
||||
|
||||
/*
|
||||
* Setting the OUTx_ON bits results in a high impedance output,
|
||||
* clearing them pulls the output to ground. Therefore the
|
||||
* meaning here is intentionally inverted, as this will then turn
|
||||
* out for a low active open drain output to be pulled to ground
|
||||
* if set to off.
|
||||
*/
|
||||
if (current_value == 0) {
|
||||
register_ctrl |= TLE9104_CTRL_OUT1ONS_BIT << (2 * i);
|
||||
} else {
|
||||
register_ctrl |= TLE9104_CTRL_OUT1ONC_BIT << (2 * i);
|
||||
}
|
||||
|
||||
if (current_value == previous_value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config->gpio_control[i].port == NULL) {
|
||||
spi_update_required = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
result = gpio_pin_set_dt(&config->gpio_control[i], current_value);
|
||||
if (result != 0) {
|
||||
LOG_ERR("unable to set control GPIO");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (spi_update_required) {
|
||||
result = tle9104_write_register(dev, TLE9104REGISTER_CTRL, register_ctrl);
|
||||
if (result != 0) {
|
||||
LOG_ERR("unable to set control register");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
data->previous_state = data->state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tle9104_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
|
||||
{
|
||||
struct tle9104_data *data = dev->data;
|
||||
int result;
|
||||
|
||||
/* cannot execute a bus operation in an ISR context */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
if (pin >= TLE9104_GPIO_COUNT) {
|
||||
LOG_ERR("invalid pin nummber %i", pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_INPUT) != 0) {
|
||||
LOG_ERR("cannot configure pin as input");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_OUTPUT) == 0) {
|
||||
LOG_ERR("pin must be configured as an output");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_SINGLE_ENDED) == 0) {
|
||||
LOG_ERR("pin must be configured as single ended");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_LINE_OPEN_DRAIN) == 0) {
|
||||
LOG_ERR("pin must be configured as open drain");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_PULL_UP) != 0) {
|
||||
LOG_ERR("pin cannot have a pull up configured");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_PULL_DOWN) != 0) {
|
||||
LOG_ERR("pin cannot have a pull down configured");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
|
||||
if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
|
||||
WRITE_BIT(data->state, pin, 0);
|
||||
} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
|
||||
WRITE_BIT(data->state, pin, 1);
|
||||
}
|
||||
|
||||
WRITE_BIT(data->configured, pin, 1);
|
||||
result = tle9104_write_state(dev);
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tle9104_port_get_raw(const struct device *dev, uint32_t *value)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(value);
|
||||
|
||||
LOG_ERR("input pins are not available");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int tle9104_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
|
||||
{
|
||||
struct tle9104_data *data = dev->data;
|
||||
int result;
|
||||
|
||||
/* cannot execute a bus operation in an ISR context */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
data->state = (data->state & ~mask) | (mask & value);
|
||||
result = tle9104_write_state(dev);
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tle9104_port_set_bits_raw(const struct device *dev, uint32_t mask)
|
||||
{
|
||||
return tle9104_port_set_masked_raw(dev, mask, mask);
|
||||
}
|
||||
|
||||
static int tle9104_port_clear_bits_raw(const struct device *dev, uint32_t mask)
|
||||
{
|
||||
return tle9104_port_set_masked_raw(dev, mask, 0);
|
||||
}
|
||||
|
||||
static int tle9104_port_toggle_bits(const struct device *dev, uint32_t mask)
|
||||
{
|
||||
struct tle9104_data *data = dev->data;
|
||||
int result;
|
||||
|
||||
/* cannot execute a bus operation in an ISR context */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
data->state ^= mask;
|
||||
result = tle9104_write_state(dev);
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tle9104_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
|
||||
enum gpio_int_mode mode, enum gpio_int_trig trig)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(pin);
|
||||
ARG_UNUSED(mode);
|
||||
ARG_UNUSED(trig);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static const struct gpio_driver_api api_table = {
|
||||
.pin_configure = tle9104_pin_configure,
|
||||
.port_get_raw = tle9104_port_get_raw,
|
||||
.port_set_masked_raw = tle9104_port_set_masked_raw,
|
||||
.port_set_bits_raw = tle9104_port_set_bits_raw,
|
||||
.port_clear_bits_raw = tle9104_port_clear_bits_raw,
|
||||
.port_toggle_bits = tle9104_port_toggle_bits,
|
||||
.pin_interrupt_configure = tle9104_pin_interrupt_configure,
|
||||
};
|
||||
|
||||
static int tle9104_init(const struct device *dev)
|
||||
{
|
||||
const struct tle9104_config *config = dev->config;
|
||||
struct tle9104_data *data = dev->data;
|
||||
uint8_t register_cfg;
|
||||
uint8_t register_globalstatus;
|
||||
uint8_t register_icvid;
|
||||
enum tle9104_register read_reg;
|
||||
int result;
|
||||
|
||||
LOG_DBG("initialize TLE9104 instance %s", dev->name);
|
||||
|
||||
result = k_mutex_init(&data->lock);
|
||||
if (result != 0) {
|
||||
LOG_ERR("unable to initialize mutex");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!spi_is_ready_dt(&config->bus)) {
|
||||
LOG_ERR("SPI bus %s is not ready", config->bus.bus->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
register_cfg = 0x00;
|
||||
|
||||
for (int i = 0; i < TLE9104_GPIO_COUNT; ++i) {
|
||||
const struct gpio_dt_spec *current = config->gpio_control + i;
|
||||
|
||||
if (current->port == NULL) {
|
||||
LOG_DBG("got no control port for output %i, will control it via SPI", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
register_cfg |= TLE9104_CFG_OUT1DD_BIT << i;
|
||||
|
||||
if (!device_is_ready(current->port)) {
|
||||
LOG_ERR("control GPIO %s is not ready", current->port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = gpio_pin_configure_dt(current, GPIO_OUTPUT_INACTIVE);
|
||||
if (result != 0) {
|
||||
LOG_ERR("failed to initialize control GPIO %i", i);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->gpio_enable.port != NULL) {
|
||||
if (!device_is_ready(config->gpio_enable.port)) {
|
||||
LOG_ERR("enable GPIO %s is not ready", config->gpio_enable.port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = gpio_pin_configure_dt(&config->gpio_enable, GPIO_OUTPUT_ACTIVE);
|
||||
if (result != 0) {
|
||||
LOG_ERR("failed to enable TLE9104");
|
||||
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(TLE9104_RESET_DURATION_TIME_US);
|
||||
gpio_pin_set_dt(&config->gpio_reset, 0);
|
||||
k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US +
|
||||
TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US);
|
||||
|
||||
/*
|
||||
* The first read value should be the ICVID, this acts also as the setup of the
|
||||
* global status register address.
|
||||
*/
|
||||
result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg,
|
||||
®ister_icvid);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (read_reg != TLE9104REGISTER_ICVID) {
|
||||
LOG_ERR("expected to read register ICVID, got instead 0x%02X", read_reg);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (register_icvid != TLE9104_ICVERSIONID) {
|
||||
LOG_ERR("got unexpected IC version id 0x%02X", register_icvid);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg,
|
||||
®ister_globalstatus);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (read_reg != TLE9104REGISTER_GLOBALSTATUS) {
|
||||
LOG_ERR("expected to read register GLOBALSTATUS, got instead 0x%02X", read_reg);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((register_globalstatus & TLE9104_GLOBALSTATUS_POR_LATCH_BIT) == 0) {
|
||||
LOG_ERR("no power on reset detected");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result = tle9104_write_register(dev, TLE9104REGISTER_CFG, register_cfg);
|
||||
if (result != 0) {
|
||||
LOG_ERR("unable to write configuration");
|
||||
return result;
|
||||
}
|
||||
|
||||
register_globalstatus = 0x00;
|
||||
/* disable communication watchdog */
|
||||
tle9104_set_cfg_cwdtime(®ister_cfg, 0);
|
||||
/* enable outputs */
|
||||
register_globalstatus |= TLE9104_GLOBALSTATUS_OUTEN_BIT;
|
||||
|
||||
result = tle9104_write_register(dev, TLE9104REGISTER_GLOBALSTATUS, register_globalstatus);
|
||||
if (result != 0) {
|
||||
LOG_ERR("unable to write global status");
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILD_ASSERT(CONFIG_GPIO_TLE9104_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY,
|
||||
"TLE9104 must be initialized after SPI");
|
||||
|
||||
#define TLE9104_INIT_GPIO_FIELDS(inst, gpio) \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, gpio), \
|
||||
(GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), gpio, 0)), ({0}))
|
||||
|
||||
#define TLE9104_INIT(inst) \
|
||||
static const struct tle9104_config tle9104_##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_enable = TLE9104_INIT_GPIO_FIELDS(inst, en_gpios), \
|
||||
.gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), resn_gpios, 0), \
|
||||
.gpio_control = { \
|
||||
TLE9104_INIT_GPIO_FIELDS(inst, in1_gpios), \
|
||||
TLE9104_INIT_GPIO_FIELDS(inst, in2_gpios), \
|
||||
TLE9104_INIT_GPIO_FIELDS(inst, in3_gpios), \
|
||||
TLE9104_INIT_GPIO_FIELDS(inst, in4_gpios), \
|
||||
}, \
|
||||
}; \
|
||||
\
|
||||
static struct tle9104_data tle9104_##inst##_drvdata; \
|
||||
\
|
||||
/* This has to be initialized after the SPI peripheral. */ \
|
||||
DEVICE_DT_INST_DEFINE(inst, tle9104_init, NULL, &tle9104_##inst##_drvdata, \
|
||||
&tle9104_##inst##_config, POST_KERNEL, \
|
||||
CONFIG_GPIO_TLE9104_INIT_PRIORITY, &api_table);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(TLE9104_INIT)
|
||||
Loading…
Reference in a new issue