Files
loramodem/drivers/lora/lr11xx/lr11xx_hal.c
2026-03-25 18:14:45 +01:00

130 lines
3.1 KiB
C

/*
* SPDX-License-Identifier: Apache-2.0
*
* LR11xx Zephyr HAL — SPI and GPIO low-level operations.
*
* The LR11xx SPI protocol:
* WRITE: Assert NSS → send 2-byte opcode + param bytes → deassert NSS
* READ: Assert NSS → send 2-byte opcode → deassert NSS
* Wait for BUSY low
* Assert NSS → read STAT1 + STAT2 + N response bytes → deassert NSS
*
* All transactions must wait for BUSY=low before asserting NSS.
*/
#include "lr11xx.h"
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(lr11xx, LOG_LEVEL_DBG);
#define BUSY_POLL_INTERVAL_US 100
#define BUSY_TIMEOUT_MS 1000
int lr11xx_hal_reset(const struct device *dev)
{
const struct lr11xx_config *cfg = dev->config;
int ret;
ret = gpio_pin_set_dt(&cfg->reset, 1);
if (ret < 0) {
return ret;
}
k_sleep(K_USEC(200));
ret = gpio_pin_set_dt(&cfg->reset, 0);
if (ret < 0) {
return ret;
}
k_sleep(K_MSEC(10));
return lr11xx_hal_wait_busy(dev, K_MSEC(BUSY_TIMEOUT_MS));
}
int lr11xx_hal_wait_busy(const struct device *dev, k_timeout_t timeout)
{
const struct lr11xx_config *cfg = dev->config;
uint32_t start = k_uptime_get_32();
uint32_t timeout_ms = k_ticks_to_ms_floor32(timeout.ticks);
while (gpio_pin_get_dt(&cfg->busy)) {
if (timeout_ms > 0 &&
(k_uptime_get_32() - start) > timeout_ms) {
return -ETIMEDOUT;
}
k_busy_wait(BUSY_POLL_INTERVAL_US);
}
return 0;
}
int lr11xx_hal_write_cmd(const struct device *dev,
uint16_t opcode,
const uint8_t *params, size_t params_len)
{
const struct lr11xx_config *cfg = dev->config;
int ret;
ret = lr11xx_hal_wait_busy(dev, K_MSEC(BUSY_TIMEOUT_MS));
if (ret < 0) {
return ret;
}
uint8_t opcode_buf[2] = {
(uint8_t)(opcode >> 8),
(uint8_t)(opcode & 0xFF),
};
const struct spi_buf tx_bufs[] = {
{ .buf = opcode_buf, .len = sizeof(opcode_buf) },
{ .buf = (void *)params, .len = params_len },
};
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = (params_len > 0) ? 2 : 1,
};
return spi_write_dt(&cfg->spi, &tx);
}
int lr11xx_hal_read_resp(const struct device *dev,
uint8_t *buf, size_t len)
{
const struct lr11xx_config *cfg = dev->config;
int ret;
ret = lr11xx_hal_wait_busy(dev, K_MSEC(BUSY_TIMEOUT_MS));
if (ret < 0) {
return ret;
}
/* First two bytes are STAT1 and STAT2 — discard for now */
uint8_t status[2];
uint8_t dummy_opcode[2] = {0x00, 0x00};
const struct spi_buf tx_bufs[] = {
{ .buf = dummy_opcode, .len = sizeof(dummy_opcode) },
};
struct spi_buf rx_bufs[] = {
{ .buf = status, .len = sizeof(status) },
{ .buf = buf, .len = len },
};
const struct spi_buf_set tx = { .buffers = tx_bufs, .count = 1 };
const struct spi_buf_set rx = { .buffers = rx_bufs, .count = (len > 0) ? 2 : 1 };
return spi_transceive_dt(&cfg->spi, &tx, &rx);
}
void lr11xx_hal_event_handler(const struct device *port,
struct gpio_callback *cb, uint32_t pins)
{
ARG_UNUSED(port);
ARG_UNUSED(pins);
struct lr11xx_data *data =
CONTAINER_OF(cb, struct lr11xx_data, event_cb);
k_sem_give(&data->event_sem);
}