/* * 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 #include #include #include 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); }