efc6e17ed0
Add a module-local .gitignore entry for macOS .DS_Store artifacts so generated Finder metadata does not dirty the submodule. Declare the SPI chip-select delay binding properties as integers so Zephyr devicetree validation accepts the custom LLCC68 binding. Pass the configured setup delay into SPI_DT_SPEC_INST_GET using the Zephyr 4 three-argument API, converting the nanosecond devicetree value to the microsecond spi_cs_control delay field.
111 lines
5.5 KiB
C
111 lines
5.5 KiB
C
#include "llcc68_raw.h"
|
|
|
|
#include <errno.h>
|
|
#include <zephyr/devicetree.h>
|
|
#include <zephyr/sys_clock.h>
|
|
#include <zephyr/sys/util.h>
|
|
|
|
#define DT_DRV_COMPAT semtech_llcc68_weihua
|
|
|
|
#define LLCC68_AUTO_RF_SWITCH_MODE(inst) \
|
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios), \
|
|
(COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, rx_enable_gpios), \
|
|
(LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY), (LLCC68_RF_SWITCH_NONE))), \
|
|
(LLCC68_RF_SWITCH_NONE))
|
|
|
|
#if defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_GPIO_COMPLEMENTARY)
|
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY
|
|
#elif defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_DIO2_SINGLE)
|
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_DIO2_SINGLE
|
|
#elif defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_NONE)
|
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_NONE
|
|
#else
|
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_AUTO_RF_SWITCH_MODE(inst)
|
|
#endif
|
|
|
|
#define LLCC68_RF_SWITCH_MODE(inst) \
|
|
DT_ENUM_IDX_OR(DT_DRV_INST(inst), rf_switch_mode, LLCC68_DEFAULT_RF_SWITCH_MODE(inst))
|
|
|
|
#define LLCC68_SPI_CS_DELAY_US(inst) \
|
|
DIV_ROUND_UP(DT_INST_PROP(inst, spi_cs_setup_delay_ns), NSEC_PER_USEC)
|
|
|
|
static void dio1_irq_trampoline(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
|
|
ARG_UNUSED(port);
|
|
|
|
struct llcc68_data *data = CONTAINER_OF(cb, struct llcc68_data, dio1_irq_callback);
|
|
const struct llcc68_config *config = data->self->config;
|
|
|
|
if ((pins & BIT(config->dio1_gpio.pin)) != 0U && data->dio1_user_handler != NULL) {
|
|
data->dio1_user_handler(data->self, data->dio1_user_data);
|
|
}
|
|
}
|
|
|
|
int llcc68_init(const struct device *dev) {
|
|
const struct llcc68_config *config = dev->config;
|
|
struct llcc68_data *data = dev->data;
|
|
|
|
if (config->rf_switch_mode == LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY &&
|
|
config->tx_enable_gpio.port != NULL) {
|
|
gpio_pin_configure_dt(&config->tx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
|
}
|
|
|
|
if (config->rf_switch_mode == LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY &&
|
|
config->rx_enable_gpio.port != NULL) {
|
|
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
|
}
|
|
|
|
if (config->rf_switch_mode == LLCC68_RF_SWITCH_DIO2_SINGLE &&
|
|
config->rx_enable_gpio.port != NULL) {
|
|
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_ACTIVE);
|
|
}
|
|
|
|
gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
|
|
gpio_pin_configure_dt(&config->busy_gpio, GPIO_INPUT);
|
|
gpio_pin_configure_dt(&config->dio1_gpio, GPIO_INPUT);
|
|
|
|
data->self = dev;
|
|
gpio_init_callback(&data->dio1_irq_callback, dio1_irq_trampoline, BIT(config->dio1_gpio.pin));
|
|
if (gpio_add_callback(config->dio1_gpio.port, &data->dio1_irq_callback) < 0) {
|
|
return -EIO;
|
|
}
|
|
|
|
gpio_pin_interrupt_configure_dt(&config->dio1_gpio, GPIO_INT_DISABLE);
|
|
return 0;
|
|
}
|
|
|
|
#define LLCC68_DEFINE(inst) \
|
|
BUILD_ASSERT(LLCC68_RF_SWITCH_MODE(inst) != LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY || \
|
|
(DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios) && \
|
|
DT_INST_NODE_HAS_PROP(inst, rx_enable_gpios)), \
|
|
"LLCC68 gpio-complementary RF switch mode requires tx-enable-gpios " \
|
|
"and rx-enable-gpios"); \
|
|
BUILD_ASSERT(LLCC68_RF_SWITCH_MODE(inst) != LLCC68_RF_SWITCH_DIO2_SINGLE || \
|
|
!DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios), \
|
|
"LLCC68 dio2-single RF switch mode uses DIO2 for TXEN and must not " \
|
|
"define tx-enable-gpios"); \
|
|
static struct llcc68_data llcc68_data_##inst; \
|
|
static const struct llcc68_config llcc68_config_##inst = \
|
|
{ \
|
|
.spi = SPI_DT_SPEC_INST_GET( \
|
|
inst, SPI_WORD_SET(8) | SPI_TRANSFER_MSB, LLCC68_SPI_CS_DELAY_US(inst)), \
|
|
.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \
|
|
.busy_gpio = GPIO_DT_SPEC_INST_GET(inst, busy_gpios), \
|
|
.dio1_gpio = GPIO_DT_SPEC_INST_GET(inst, dio1_gpios), \
|
|
.tx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, tx_enable_gpios, {.port = NULL}), \
|
|
.rx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, {.port = NULL}), \
|
|
.rf_switch_mode = LLCC68_RF_SWITCH_MODE(inst), \
|
|
}; \
|
|
DEVICE_DT_INST_DEFINE(inst, \
|
|
llcc68_init, \
|
|
NULL, \
|
|
&llcc68_data_##inst, \
|
|
&llcc68_config_##inst, \
|
|
POST_KERNEL, \
|
|
CONFIG_LLCC68_INIT_PRIORITY, \
|
|
NULL)
|
|
|
|
BUILD_ASSERT(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT),
|
|
"No status=okay nodes for DT_DRV_COMPAT; check compatible/status");
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(LLCC68_DEFINE)
|