|  | /* ieee802154_rf2xx_iface.c - ATMEL RF2XX IEEE 802.15.4 Interface */ | 
|  |  | 
|  | /* | 
|  | * Copyright (c) 2019-2020 Gerson Fernando Budke | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #define LOG_MODULE_NAME ieee802154_rf2xx_iface | 
|  | #define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL | 
|  |  | 
|  | #include <zephyr/logging/log.h> | 
|  | LOG_MODULE_REGISTER(LOG_MODULE_NAME); | 
|  |  | 
|  | #include <errno.h> | 
|  |  | 
|  | #include <zephyr/device.h> | 
|  | #include <zephyr/drivers/spi.h> | 
|  | #include <zephyr/drivers/gpio.h> | 
|  |  | 
|  | #include <zephyr/net/ieee802154_radio.h> | 
|  |  | 
|  | #include "ieee802154_rf2xx.h" | 
|  | #include "ieee802154_rf2xx_regs.h" | 
|  | #include "ieee802154_rf2xx_iface.h" | 
|  |  | 
|  | void rf2xx_iface_phy_rst(const struct device *dev) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  |  | 
|  | /* Ensure control lines have correct levels. */ | 
|  | gpio_pin_set_dt(&conf->reset_gpio, 0); | 
|  | gpio_pin_set_dt(&conf->slptr_gpio, 0); | 
|  |  | 
|  | /* Wait typical time of timer TR1. */ | 
|  | k_busy_wait(330); | 
|  |  | 
|  | gpio_pin_set_dt(&conf->reset_gpio, 1); | 
|  | k_busy_wait(10); | 
|  | gpio_pin_set_dt(&conf->reset_gpio, 0); | 
|  | } | 
|  | void rf2xx_iface_phy_tx_start(const struct device *dev) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  |  | 
|  | /* Start TX transmission at rise edge */ | 
|  | gpio_pin_set_dt(&conf->slptr_gpio, 1); | 
|  | /* 16.125[μs] delay to detect signal */ | 
|  | k_busy_wait(20); | 
|  | /* restore initial pin state */ | 
|  | gpio_pin_set_dt(&conf->slptr_gpio, 0); | 
|  | } | 
|  |  | 
|  | uint8_t rf2xx_iface_reg_read(const struct device *dev, | 
|  | uint8_t addr) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  | uint8_t status; | 
|  | uint8_t regval = 0; | 
|  |  | 
|  | addr |= RF2XX_RF_CMD_REG_R; | 
|  |  | 
|  | const struct spi_buf tx_buf = { | 
|  | .buf = &addr, | 
|  | .len = 1 | 
|  | }; | 
|  | const struct spi_buf_set tx = { | 
|  | .buffers = &tx_buf, | 
|  | .count = 1 | 
|  | }; | 
|  | const struct spi_buf rx_buf[2] = { | 
|  | { | 
|  | .buf = &status, | 
|  | .len = 1 | 
|  | }, | 
|  | { | 
|  | .buf = ®val, | 
|  | .len = 1 | 
|  | }, | 
|  | }; | 
|  | const struct spi_buf_set rx = { | 
|  | .buffers = rx_buf, | 
|  | .count = 2 | 
|  | }; | 
|  |  | 
|  | if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { | 
|  | LOG_ERR("Failed to exec rf2xx_reg_read CMD at address %d", | 
|  | addr); | 
|  | } | 
|  |  | 
|  | LOG_DBG("Read Address: %02X, PhyStatus: %02X, RegVal: %02X", | 
|  | (addr & ~(RF2XX_RF_CMD_REG_R)), status, regval); | 
|  |  | 
|  | return regval; | 
|  | } | 
|  |  | 
|  | void rf2xx_iface_reg_write(const struct device *dev, | 
|  | uint8_t addr, | 
|  | uint8_t data) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  | uint8_t status; | 
|  |  | 
|  | addr |= RF2XX_RF_CMD_REG_W; | 
|  |  | 
|  | const struct spi_buf tx_buf[2] = { | 
|  | { | 
|  | .buf = &addr, | 
|  | .len = 1 | 
|  | }, | 
|  | { | 
|  | .buf = &data, | 
|  | .len = 1 | 
|  | } | 
|  | }; | 
|  | const struct spi_buf_set tx = { | 
|  | .buffers = tx_buf, | 
|  | .count = 2 | 
|  | }; | 
|  | const struct spi_buf rx_buf = { | 
|  | .buf = &status, | 
|  | .len = 1 | 
|  | }; | 
|  | const struct spi_buf_set rx = { | 
|  | .buffers = &rx_buf, | 
|  | .count = 1 | 
|  | }; | 
|  |  | 
|  | if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { | 
|  | LOG_ERR("Failed to exec rf2xx_reg_write at address %d", | 
|  | addr); | 
|  | } | 
|  |  | 
|  | LOG_DBG("Write Address: %02X, PhyStatus: %02X, RegVal: %02X", | 
|  | (addr & ~(RF2XX_RF_CMD_REG_W)), status, data); | 
|  | } | 
|  |  | 
|  | uint8_t rf2xx_iface_bit_read(const struct device *dev, | 
|  | uint8_t addr, | 
|  | uint8_t mask, | 
|  | uint8_t pos) | 
|  | { | 
|  | uint8_t ret; | 
|  |  | 
|  | ret = rf2xx_iface_reg_read(dev, addr); | 
|  | ret &= mask; | 
|  | ret >>= pos; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void rf2xx_iface_bit_write(const struct device *dev, | 
|  | uint8_t reg_addr, | 
|  | uint8_t mask, | 
|  | uint8_t pos, | 
|  | uint8_t new_value) | 
|  | { | 
|  | uint8_t current_reg_value; | 
|  |  | 
|  | current_reg_value = rf2xx_iface_reg_read(dev, reg_addr); | 
|  | current_reg_value &= ~mask; | 
|  | new_value <<= pos; | 
|  | new_value &= mask; | 
|  | new_value |= current_reg_value; | 
|  | rf2xx_iface_reg_write(dev, reg_addr, new_value); | 
|  | } | 
|  |  | 
|  | void rf2xx_iface_frame_read(const struct device *dev, | 
|  | uint8_t *data, | 
|  | uint8_t length) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  | uint8_t cmd = RF2XX_RF_CMD_FRAME_R; | 
|  |  | 
|  | const struct spi_buf tx_buf = { | 
|  | .buf = &cmd, | 
|  | .len = 1 | 
|  | }; | 
|  | const struct spi_buf_set tx = { | 
|  | .buffers = &tx_buf, | 
|  | .count = 1 | 
|  | }; | 
|  | const struct spi_buf rx_buf = { | 
|  | .buf = data, | 
|  | .len = length | 
|  | }; | 
|  | const struct spi_buf_set rx = { | 
|  | .buffers = &rx_buf, | 
|  | .count = 1 | 
|  | }; | 
|  |  | 
|  | if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { | 
|  | LOG_ERR("Failed to exec rf2xx_frame_read PHR"); | 
|  | } | 
|  |  | 
|  | LOG_DBG("Frame R: PhyStatus: %02X. length: %02X", data[0], length); | 
|  | LOG_HEXDUMP_DBG(data + RX2XX_FRAME_HEADER_SIZE, length, "payload"); | 
|  | } | 
|  |  | 
|  | void rf2xx_iface_frame_write(const struct device *dev, | 
|  | uint8_t *data, | 
|  | uint8_t length) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  | uint8_t cmd = RF2XX_RF_CMD_FRAME_W; | 
|  | uint8_t status; | 
|  | uint8_t phr; | 
|  |  | 
|  | /* Sanity check */ | 
|  | if (length > 125) { | 
|  | length = 125; | 
|  | } | 
|  |  | 
|  | phr = length + RX2XX_FRAME_FCS_LENGTH; | 
|  |  | 
|  | const struct spi_buf tx_buf[3] = { | 
|  | { | 
|  | .buf = &cmd, | 
|  | .len = 1 | 
|  | }, | 
|  | { | 
|  | .buf = &phr,    /* PHR */ | 
|  | .len = 1 | 
|  | }, | 
|  | { | 
|  | .buf = data,    /* PSDU */ | 
|  | .len = length | 
|  | }, | 
|  | }; | 
|  | const struct spi_buf_set tx = { | 
|  | .buffers = tx_buf, | 
|  | .count = 3 | 
|  | }; | 
|  | const struct spi_buf rx_buf = { | 
|  | .buf = &status, | 
|  | .len = 1 | 
|  | }; | 
|  | const struct spi_buf_set rx = { | 
|  | .buffers = &rx_buf, | 
|  | .count = 1 | 
|  | }; | 
|  |  | 
|  | if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { | 
|  | LOG_ERR("Failed to exec rf2xx_frame_write"); | 
|  | } | 
|  |  | 
|  | LOG_DBG("Frame W: PhyStatus: %02X. length: %02X", status, length); | 
|  | LOG_HEXDUMP_DBG(data, length, "payload"); | 
|  | } | 
|  |  | 
|  | void rf2xx_iface_sram_read(const struct device *dev, | 
|  | uint8_t address, | 
|  | uint8_t *data, | 
|  | uint8_t length) | 
|  | { | 
|  | const struct rf2xx_config *conf = dev->config; | 
|  | uint8_t cmd = RF2XX_RF_CMD_SRAM_R; | 
|  | uint8_t status[2]; | 
|  |  | 
|  | const struct spi_buf tx_buf[2] = { | 
|  | { | 
|  | .buf = &cmd, | 
|  | .len = 1 | 
|  | }, | 
|  | { | 
|  | .buf = &address, | 
|  | .len = 1 | 
|  | }, | 
|  | }; | 
|  | const struct spi_buf_set tx = { | 
|  | .buffers = tx_buf, | 
|  | .count = 2 | 
|  | }; | 
|  | const struct spi_buf rx_buf[2] = { | 
|  | { | 
|  | .buf = status, | 
|  | .len = 2 | 
|  | }, | 
|  | { | 
|  | .buf = data, | 
|  | .len = length | 
|  | }, | 
|  | }; | 
|  | const struct spi_buf_set rx = { | 
|  | .buffers = rx_buf, | 
|  | .count = 2 | 
|  | }; | 
|  |  | 
|  | if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { | 
|  | LOG_ERR("Failed to exec rf2xx_sram_read"); | 
|  | } | 
|  |  | 
|  | LOG_DBG("SRAM R: length: %02X, status: %02X", length, status[0]); | 
|  | LOG_HEXDUMP_DBG(data, length, "content"); | 
|  | } |