diff options
author | Johann Fischer <j.fischer@phytec.de> | 2017-01-09 16:54:28 +0100 |
---|---|---|
committer | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2017-01-27 12:35:51 +0200 |
commit | fa8d9c9d1056e9d77ffa494ee4ab00bdcdfc7bc4 (patch) | |
tree | 1f9c3dee202d8bf5513eb5e051b1542eb4adbce5 /drivers | |
parent | d4e5113461ccc97044029ead9b7a014aa4cc943f (diff) |
drivers: ieee802154: add MCR20A driver
Add driver and configuration for the MCR20A 802.15.4
transceiver.
Jira: ZEP-1429
Change-Id: I0b17b688220a47c2f0e5cde269064bbd0dec824a
Signed-off-by: Johann Fischer <j.fischer@phytec.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ieee802154/Kconfig | 117 | ||||
-rw-r--r-- | drivers/ieee802154/Makefile | 2 | ||||
-rw-r--r-- | drivers/ieee802154/ieee802154_mcr20a.c | 1459 | ||||
-rw-r--r-- | drivers/ieee802154/ieee802154_mcr20a.h | 184 | ||||
-rw-r--r-- | drivers/ieee802154/ieee802154_mcr20a_regs.h | 590 |
5 files changed, 2352 insertions, 0 deletions
diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 8e6c9ea3a..5b91f7a78 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -139,4 +139,121 @@ config UPIPE_15_4_DRV_NAME default "upipe_15_4" depends on UPIPE_15_4 +config NXP_MCR20A + bool "NXP MCR20A Driver support" + depends on NETWORKING && SPI + select NET_L2_IEEE802154 + default n + +config NXP_MCR20A_RAW + bool "NXP MCR20A Driver RAW channel" + depends on SPI + select NET_L2_RAW_CHANNEL + default n + help + Enable NXP_MCR20A driver with RAW channel + + The MCR20A driver with RAW channel allows to export radio interface + over USB making an USB 802.15.4 dongle. + +if NXP_MCR20A || NXP_MCR20A_RAW + +config NXP_MCR20A_DRV_NAME + string "NXP MCR20A Driver's name" + default "mcr20a" + help + This option sets the driver name + +config NXP_MCR20A_SPI_DRV_NAME + string "SPI driver's name to use to access MCR20A" + default SPI_0_NAME + help + This option is mandatory to set which SPI controller to use in order + to actually control the MCR20A chip. + +config NXP_MCR20A_SPI_FREQ + int "SPI system frequency" + default 4000000 + help + This option sets the SPI controller's frequency. Beware this value + depends on the SPI controller being used and also on the system + clock. + +config NXP_MCR20A_SPI_SLAVE + int "SPI slave linked to MCR20A" + default 0 + help + This option sets the SPI slave number SPI controller has to switch + to when dealing with MCR20A chip. + +config MCR20A_GPIO_IRQ_B_NAME + string "GPIO device used for IRQ_B output of MCR20A" + default GPIO_MCUX_PORTB_NAME + +config MCR20A_GPIO_IRQ_B_PIN + int "GPIO pin connected to IRQ_B output of MCR20A" + default 9 + +config MCR20A_GPIO_RESET_NAME + string "GPIO device used for RESET input of MCR20A" + default GPIO_MCUX_PORTA_NAME + +config MCR20A_GPIO_RESET_PIN + int "GPIO pin connected to RESET input of MCR20A" + default 2 + +choice + prompt "CLK_OUT frequency" + default MCR20A_CLK_OUT_DISABLED + help + Configuration of the MCR20A clock output pin. + +config MCR20A_CLK_OUT_DISABLED + bool "Disabled" + +config MCR20A_CLK_OUT_32MHZ + bool "32 MHz" + +config MCR20A_CLK_OUT_16MHZ + bool "16 MHz" + +config MCR20A_CLK_OUT_8MHZ + bool "8 MHz" + +config MCR20A_CLK_OUT_4MHZ + bool "4 MHz" + +config MCR20A_CLK_OUT_1MHZ + bool "1 MHz" + +config MCR20A_CLK_OUT_250KHZ + bool "250 kHz" + +config MCR20A_CLK_OUT_62500HZ + bool "62500 Hz" + +config MCR20A_CLK_OUT_32768HZ + bool "32768 Hz" + +endchoice + +config NXP_MCR20A_RX_STACK_SIZE + int "Driver's internal rx thread stack size" + default 800 + help + This option sets the driver's stack size for its internal rx thread. + The default value should be sufficient, but in case it proves to be + a too little one, this option makes it easy to play with the size. + +config NXP_MCR20A_INIT_PRIO + int "MCR20A intialization priority" + default 80 + help + Set the initialization priority number. Do not mess with it unless + you know what you are doing. Beware mcr20a requires gpio and spi to + be ready first (and sometime gpio should be the very first as spi + might need it too). And of course it has to start before the net stack. + +endif + endmenu diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile index ed213ba63..801726e4c 100644 --- a/drivers/ieee802154/Makefile +++ b/drivers/ieee802154/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_TI_CC2520) += ieee802154_cc2520.o obj-$(CONFIG_TI_CC2520_RAW) += ieee802154_cc2520.o obj-$(CONFIG_UPIPE_15_4) += ieee802154_uart_pipe.o +obj-$(CONFIG_NXP_MCR20A) += ieee802154_mcr20a.o +obj-$(CONFIG_NXP_MCR20A_RAW) += ieee802154_mcr20a.o diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c new file mode 100644 index 000000000..a2b7b4cd6 --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -0,0 +1,1459 @@ +/* ieee802154_mcr20a.c - NXP MCR20A driver */ + +/* + * Copyright (c) 2017 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL +#define SYS_LOG_DOMAIN "dev/mcr20a" +#include <logging/sys_log.h> + +#include <errno.h> + +#include <kernel.h> +#include <arch/cpu.h> + +#include <board.h> +#include <device.h> +#include <init.h> +#include <net/net_if.h> +#include <net/nbuf.h> + +#include <misc/byteorder.h> +#include <string.h> +#include <rand32.h> + +#include <gpio.h> + +#include <net/ieee802154_radio.h> + +#include "ieee802154_mcr20a.h" +#include "MCR20Overwrites.h" + +#if (SYS_LOG_LEVEL == 4) +/* Prevent timer overflow during SYS_LOG_* output */ +#define _MACACKWAITDURATION (864 / 16 * 1000) +#else +#define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */ +#endif + +/* AUTOACK should be enabled by default, disable it only for testing */ +#define MCR20A_AUTOACK_ENABLED (true) + +#define MCR20A_FCS_LENGTH (2) +#define MCR20A_PSDU_LENGTH (125) + +/* Values for the clock output (CLK_OUT) configuration */ +#ifdef CONFIG_MCR20A_CLK_OUT_DISABLED +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_HIZ) + +#elif CONFIG_MCR20A_CLK_OUT_32MHZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(0) | MCR20A_CLK_OUT_DS |\ + MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_16MHZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(1) | MCR20A_CLK_OUT_DS |\ + MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_8MHZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(2) | MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_4MHZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(3) | MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_1MHZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(4) | MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_250KHZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(5) | MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_62500HZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(6) | MCR20A_CLK_OUT_EN) + +#elif CONFIG_MCR20A_CLK_OUT_32768HZ +#define MCR20A_CLK_OUT_CONFIG (MCR20A_CLK_OUT_DIV(7) | MCR20A_CLK_OUT_EN) + +#endif + +/* Values for the power mode (PM) configuration */ +#define MCR20A_PM_HIBERNATE 0 +#define MCR20A_PM_DOZE MCR20A_PWR_MODES_XTALEN +#define MCR20A_PM_IDLE (MCR20A_PWR_MODES_XTALEN |\ + MCR20A_PWR_MODES_PMC_MODE) +#define MCR20A_PM_AUTODOZE (MCR20A_PWR_MODES_XTALEN |\ + MCR20A_PWR_MODES_AUTODOZE) + +/* Default settings for the device initialization */ +#define MCR20A_DEFAULT_TX_POWER (0) +#define MCR20A_DEFAULT_CHANNEL (26) + +/* RF TX power max/min values (dBm) */ +#define MCR20A_OUTPUT_POWER_MAX (8) +#define MCR20A_OUTPUT_POWER_MIN (-35) + +/* Lookup table for the Power Control register */ +static const uint8_t pow_lt[44] = { + 3, 4, 5, 6, + 6, 7, 7, 8, + 8, 9, 9, 10, + 11, 11, 12, 13, + 13, 14, 14, 15, + 16, 16, 17, 18, + 18, 19, 20, 20, + 21, 21, 22, 23, + 23, 24, 25, 25, + 26, 27, 27, 28, + 28, 29, 30, 31 +}; + +/* PLL integer and fractional lookup tables + * + * Fc = 2405 + 5(k - 11) , k = 11,12,...,26 + * + * Equation for PLL frequency, MKW2xD Reference Manual, p.255 : + * F = ((PLL_INT0 + 64) + (PLL_FRAC0/65536))32MHz + * + */ +static const uint8_t pll_int_lt[16] = { + 11, 11, 11, 11, + 11, 11, 12, 12, + 12, 12, 12, 12, + 13, 13, 13, 13 +}; + +static const uint16_t pll_frac_lt[16] = { + 10240, 20480, 30720, 40960, + 51200, 61440, 6144, 16384, + 26624, 36864, 47104, 57344, + 2048, 12288, 22528, 32768 +}; + +#define _usleep(usec) k_busy_wait(usec) + +/* Read direct (dreg is true) or indirect register (dreg is false) */ +uint8_t _mcr20a_read_reg(struct mcr20a_spi *spi, bool dreg, uint8_t addr) +{ + uint8_t len = dreg ? 2 : 3; + + spi->cmd_buf[0] = dreg ? (MCR20A_REG_READ | addr) : + (MCR20A_IAR_INDEX | MCR20A_REG_WRITE); + spi->cmd_buf[1] = dreg ? 0 : (addr | MCR20A_REG_READ); + spi->cmd_buf[2] = 0; + + spi_slave_select(spi->dev, spi->slave); + + if (spi_transceive(spi->dev, spi->cmd_buf, len, + spi->cmd_buf, len) == 0) { + return spi->cmd_buf[len - 1]; + } + + return 0; +} + +/* Write direct (dreg is true) or indirect register (dreg is false) */ +bool _mcr20a_write_reg(struct mcr20a_spi *spi, bool dreg, uint8_t addr, + uint8_t value) +{ + uint8_t len = dreg ? 2 : 3; + + spi->cmd_buf[0] = dreg ? (MCR20A_REG_WRITE | addr) : + (MCR20A_IAR_INDEX | MCR20A_REG_WRITE); + spi->cmd_buf[1] = dreg ? value : (addr | MCR20A_REG_WRITE); + spi->cmd_buf[2] = dreg ? 0 : value; + + spi_slave_select(spi->dev, spi->slave); + + return (spi_write(spi->dev, spi->cmd_buf, len) == 0); +} + +/* Write multiple bytes to direct or indirect register */ +bool _mcr20a_write_burst(struct mcr20a_spi *spi, bool dreg, uint16_t addr, + uint8_t *data_buf, uint8_t len) +{ + if ((len + 2) > sizeof(spi->cmd_buf)) { + SYS_LOG_ERR("Buffer length too large"); + } + + if (dreg) { + spi->cmd_buf[0] = MCR20A_REG_WRITE | addr; + memcpy(&spi->cmd_buf[1], data_buf, len); + len += 1; + } else { + spi->cmd_buf[0] = MCR20A_IAR_INDEX | MCR20A_REG_WRITE; + spi->cmd_buf[1] = addr | MCR20A_REG_WRITE; + memcpy(&spi->cmd_buf[2], data_buf, len); + len += 2; + } + + spi_slave_select(spi->dev, spi->slave); + + return (spi_write(spi->dev, spi->cmd_buf, len) == 0); +} + +/* Read multiple bytes from direct or indirect register */ +bool _mcr20a_read_burst(struct mcr20a_spi *spi, bool dreg, uint16_t addr, + uint8_t *data_buf, uint8_t len) +{ + if ((len + 2) > sizeof(spi->cmd_buf)) { + SYS_LOG_ERR("Buffer length too large"); + } + + if (dreg) { + spi->cmd_buf[0] = MCR20A_REG_READ | addr; + len += 1; + } else { + spi->cmd_buf[0] = MCR20A_IAR_INDEX | MCR20A_REG_WRITE; + spi->cmd_buf[1] = addr | MCR20A_REG_READ; + len += 2; + } + + spi_slave_select(spi->dev, spi->slave); + + if (spi_transceive(spi->dev, spi->cmd_buf, len, + spi->cmd_buf, len) != 0) { + return 0; + } + + if (dreg) { + memcpy(data_buf, &spi->cmd_buf[1], len - 1); + } else { + memcpy(data_buf, &spi->cmd_buf[2], len - 2); + } + + return 1; +} + +/* Mask (msk is true) or unmask all interrupts from asserting IRQ_B */ +static bool mcr20a_mask_irqb(struct mcr20a_context *dev, bool msk) +{ + uint8_t ctrl4 = read_reg_phy_ctrl4(&dev->spi); + + if (msk) { + ctrl4 |= MCR20A_PHY_CTRL4_TRCV_MSK; + } else { + ctrl4 &= ~MCR20A_PHY_CTRL4_TRCV_MSK; + } + + return write_reg_phy_ctrl4(&dev->spi, ctrl4); +} + +/* Initiate a (new) Transceiver Sequence */ +static int mcr20a_set_sequence(struct mcr20a_context *mcr20a, uint8_t seq) +{ + uint8_t ctrl1; + uint8_t state; + + if (!mcr20a_mask_irqb(mcr20a, true)) { + goto error; + } + + ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_IDLE) { + goto set_new_seq; + } + + /* Abort any ongoing sequence */ + ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK; + if (!write_reg_phy_ctrl1(&mcr20a->spi, ctrl1)) { + goto error; + } + + do { + state = read_reg_seq_state(&mcr20a->spi); + } while ((state & 0x1f) != 0); + + /* Clear relevant interrupt flags */ + if (!write_reg_irqsts1(&mcr20a->spi, MCR20A_IRQSTS1_IRQ_MASK)) { + goto error; + } + +set_new_seq: + /* Set new sequence */ + ctrl1 |= set_bits_phy_ctrl1_xcvseq(seq); + if (!write_reg_phy_ctrl1(&mcr20a->spi, ctrl1)) { + goto error; + } + + if (!mcr20a_mask_irqb(mcr20a, false)) { + goto error; + } + + SYS_LOG_DBG("new SEQ: 0x%02x", set_bits_phy_ctrl1_xcvseq(seq)); + + return 0; + +error: + SYS_LOG_ERR("Failed"); + return -EIO; +} + +/** Set an timeout value for the given compare register */ +static int mcr20a_timer_set(struct mcr20a_context *mcr20a, + uint8_t cmp_reg, + uint32_t timeout) +{ + uint32_t now = 0; + uint32_t next; + bool retval; + + if (!read_burst_event_timer(&mcr20a->spi, (uint8_t *)&now)) { + goto error; + } + + now = sys_le32_to_cpu(now); + next = now + timeout; + SYS_LOG_DBG("now: 0x%x set 0x%x", now, next); + next = sys_cpu_to_le32(next); + + switch (cmp_reg) { + case 1: + retval = write_burst_t1cmp(&mcr20a->spi, (uint8_t *)&next); + break; + case 2: + retval = write_burst_t2cmp(&mcr20a->spi, (uint8_t *)&next); + break; + case 3: + retval = write_burst_t3cmp(&mcr20a->spi, (uint8_t *)&next); + break; + case 4: + retval = write_burst_t4cmp(&mcr20a->spi, (uint8_t *)&next); + break; + default: + goto error; + } + + if (!retval) { + goto error; + } + + return 0; + +error: + SYS_LOG_ERR("Failed"); + return -EIO; +} + +static int mcr20a_timer_init(struct device *dev, uint8_t tb) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t buf[3] = {0, 0, 0}; + uint8_t ctrl4; + + if (!write_reg_tmr_prescale(&mcr20a->spi, + set_bits_tmr_prescale(tb))) { + goto error; + } + + if (!write_burst_t1cmp(&mcr20a->spi, buf)) { + goto error; + } + + ctrl4 = read_reg_phy_ctrl4(&mcr20a->spi); + ctrl4 |= MCR20A_PHY_CTRL4_TMRLOAD; + if (!write_reg_phy_ctrl4(&mcr20a->spi, ctrl4)) { + goto error; + } + + SYS_LOG_DBG("done, timebase %d", tb); + return 0; + +error: + SYS_LOG_ERR("Failed"); + return -EIO; +} + +/* Set Timer Comparator 4 */ +static int mcr20a_t4cmp_set(struct mcr20a_context *mcr20a, + uint32_t timeout) +{ + uint8_t irqsts3; + uint8_t ctrl3; + + if (!mcr20a_mask_irqb(mcr20a, true)) { + goto error; + } + + if (mcr20a_timer_set(mcr20a, 4, timeout)) { + goto error; + } + + /* enable and clear irq for the timer 4 */ + irqsts3 = read_reg_irqsts3(&mcr20a->spi); + irqsts3 &= ~MCR20A_IRQSTS3_TMR4MSK; + irqsts3 |= MCR20A_IRQSTS3_TMR4IRQ; + if (!write_reg_irqsts3(&mcr20a->spi, irqsts3)) { + goto error; + } + + ctrl3 = read_reg_phy_ctrl3(&mcr20a->spi); + ctrl3 |= MCR20A_PHY_CTRL3_TMR4CMP_EN; + if (!write_reg_phy_ctrl3(&mcr20a->spi, ctrl3)) { + goto error; + } + + if (!mcr20a_mask_irqb(mcr20a, false)) { + goto error; + } + + return 0; + +error: + SYS_LOG_DBG("Failed"); + return -EIO; +} + +/* Clear Timer Comparator 4 */ +static int mcr20a_t4cmp_clear(struct mcr20a_context *mcr20a) +{ + uint8_t irqsts3; + uint8_t ctrl3; + + ctrl3 = read_reg_phy_ctrl3(&mcr20a->spi); + ctrl3 &= ~MCR20A_PHY_CTRL3_TMR4CMP_EN; + if (!write_reg_phy_ctrl3(&mcr20a->spi, ctrl3)) { + goto error; + } + + irqsts3 = read_reg_irqsts3(&mcr20a->spi); + irqsts3 |= MCR20A_IRQSTS3_TMR4IRQ; + if (!write_reg_irqsts3(&mcr20a->spi, irqsts3)) { + goto error; + } + + return 0; + +error: + SYS_LOG_DBG("Failed"); + return -EIO; +} + +static inline uint32_t mcr20a_get_rssi(uint32_t lqi) +{ + /* Get rssi (Received Signal Strength Indicator, unit is dBm) + * from lqi (Link Quality Indicator) value. + * There are two different equations for RSSI: + * RF = (LQI – 286.6) / 2.69333 (MKW2xD Reference Manual) + * RF = (LQI – 295.4) / 2.84 (MCR20A Reference Manual) + * The last appears more to match the graphic (Figure 3-10). + * Since RSSI value is always positive and we want to + * avoid the floating point computation: + * -RF * 65536 = (LQI / 2.84 - 295.4 / 2.84) * 65536 + * RF * 65536 = (295.4 * 65536 / 2.84) - (LQI * 65536 / 2.84) + */ + uint32_t a = (uint32_t)(295.4 * 65536 / 2.84); + uint32_t b = (uint32_t)(65536 / 2.84); + + return (a - (b * lqi)) >> 16; +} + +static inline uint8_t *get_mac(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint32_t *ptr = (uint32_t *)(mcr20a->mac_addr); + + UNALIGNED_PUT(sys_rand32_get(), ptr); + ptr = (uint32_t *)(mcr20a->mac_addr + 4); + UNALIGNED_PUT(sys_rand32_get(), ptr); + + mcr20a->mac_addr[0] = (mcr20a->mac_addr[0] & ~0x01) | 0x02; + + return mcr20a->mac_addr; +} + +static inline bool read_rxfifo_content(struct mcr20a_spi *spi, + struct net_buf *buf, uint8_t len) +{ + uint8_t data[1 + MCR20A_PSDU_LENGTH]; + + if (len > MCR20A_PSDU_LENGTH) { + SYS_LOG_ERR("Packet length too large"); + return false; + } + + data[0] = MCR20A_BUF_READ; + + spi_slave_select(spi->dev, spi->slave); + + if (spi_transceive(spi->dev, data, len+1, data, len+1) != 0) { + return false; + } + + memcpy(buf->data, &data[1], len); + net_buf_add(buf, len); + + return true; +} + +static inline void mcr20a_rx(struct mcr20a_context *mcr20a) +{ + struct net_buf *pkt_buf = NULL; + struct net_buf *buf; + uint8_t pkt_len; + + buf = NULL; + + pkt_len = read_reg_rx_frm_len(&mcr20a->spi); + pkt_len -= MCR20A_FCS_LENGTH; + + buf = net_nbuf_get_reserve_rx(0); + if (!buf) { + SYS_LOG_ERR("No buf available"); + goto out; + } + +#if defined(CONFIG_NXP_MCR20A_RAW) + /* TODO: Test raw mode */ + /** + * Reserve 1 byte for length + */ + pkt_buf = net_nbuf_get_reserve_data(1); +#else + pkt_buf = net_nbuf_get_reserve_data(0); +#endif + if (!pkt_buf) { + SYS_LOG_ERR("No pkt_buf available"); + goto out; + } + + net_buf_frag_insert(buf, pkt_buf); + + if (!read_rxfifo_content(&mcr20a->spi, pkt_buf, pkt_len)) { + SYS_LOG_ERR("No content read"); + goto out; + } + + if (ieee802154_radio_handle_ack(mcr20a->iface, buf) == NET_OK) { + SYS_LOG_DBG("ACK packet handled"); + goto out; + } + + mcr20a->lqi = read_reg_lqi_value(&mcr20a->spi); + SYS_LOG_DBG("Caught a packet (%u) (LQI: %u, RSSI: %u)", + pkt_len, mcr20a->lqi, + mcr20a_get_rssi(mcr20a->lqi)); + +#if defined(CONFIG_NXP_MCR20A_RAW) + net_buf_add_u8(pkt_buf, mcr20a->lqi); +#endif + + if (net_recv_data(mcr20a->iface, buf) < 0) { + SYS_LOG_DBG("Packet dropped by NET stack"); + goto out; + } + + net_analyze_stack("MCR20A Rx Fiber stack", + mcr20a->mcr20a_rx_stack, + CONFIG_NXP_MCR20A_RX_STACK_SIZE); + return; +out: + if (buf) { + net_buf_unref(buf); + } +} + +/* Interrupt processing for the sequence R (Receive) */ +static inline uint8_t _irq_event_seq_r(struct mcr20a_context *mcr20a, + uint8_t *dregs) +{ + uint8_t irqsts1 = 0; + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_RXWTRMRKIRQ) { + SYS_LOG_DBG("Got RXWTRMRKIRQ"); + irqsts1 |= MCR20A_IRQSTS1_RXWTRMRKIRQ; + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_RXIRQ) { + SYS_LOG_DBG("Finished RXSEQ"); + irqsts1 |= MCR20A_IRQSTS1_RXIRQ; + if (dregs[MCR20A_PHY_CTRL1] & MCR20A_PHY_CTRL1_AUTOACK) { + SYS_LOG_DBG("Perform TX ACK"); + } + mcr20a_rx(mcr20a); + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_TXIRQ) { + SYS_LOG_DBG("Finished (ACK) TXSEQ"); + irqsts1 |= MCR20A_IRQSTS1_TXIRQ; + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_SEQIRQ) { + SYS_LOG_DBG("SEQIRQ"); + irqsts1 |= MCR20A_IRQSTS1_SEQIRQ; + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_RECEIVE)) { + SYS_LOG_ERR("Failed to set XCV sequence"); + } + } + + return irqsts1; +} + +/* Interrupt processing for the sequence CCA and CCCA */ +static inline uint8_t _irq_event_seq_cca(struct mcr20a_context *mcr20a, + uint8_t *dregs, bool ccca) +{ + uint8_t irqsts1 = 0; + + if ((dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_CCAIRQ) && + (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_SEQIRQ)) { + irqsts1 |= MCR20A_IRQSTS1_CCAIRQ | MCR20A_IRQSTS1_SEQIRQ; + + if (dregs[MCR20A_IRQSTS2] & MCR20A_IRQSTS2_CCA) { + SYS_LOG_DBG("SEQIRQ, CCA CH busy"); + atomic_set(&mcr20a->seq_retval, -EBUSY); + } else { + SYS_LOG_DBG("SEQIRQ, CCA CH idle"); + atomic_set(&mcr20a->seq_retval, 0); + } + } else if (dregs[MCR20A_IRQSTS3] & MCR20A_IRQSTS3_TMR4IRQ) { + irqsts1 |= MCR20A_IRQSTS1_CCAIRQ | MCR20A_IRQSTS1_SEQIRQ; + SYS_LOG_DBG("CCCA timeout, CH busy"); + atomic_set(&mcr20a->seq_retval, -EBUSY); + } else { + SYS_LOG_DBG("Unsuitable interrupt"); + return irqsts1; + } + + if (ccca) { + mcr20a_t4cmp_clear(mcr20a); + } + + if (atomic_get(&mcr20a->busy) == 1) { + atomic_set(&mcr20a->busy, 0); + k_sem_give(&mcr20a->seq_sync); + } + + /** + * Assume that after the CCA, a transmit sequence follows + * and set here the sequence manager to Idle. + */ + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_IDLE)) { + SYS_LOG_ERR("Failed to set XCV sequence"); + } + + return irqsts1; +} + +/* Interrupt processing for the transmit sequences */ +static inline uint8_t _irq_event_seq_tr(struct mcr20a_context *mcr20a, + uint8_t *dregs, bool tr) +{ + uint8_t irqsts1 = 0; + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_TXIRQ) { + SYS_LOG_DBG("finished TXSEQ"); + irqsts1 |= MCR20A_IRQSTS1_TXIRQ; + + if (dregs[MCR20A_PHY_CTRL1] & MCR20A_PHY_CTRL1_RXACKRQD) { + SYS_LOG_DBG("wait for RX ACK"); + mcr20a_t4cmp_set(mcr20a, _MACACKWAITDURATION); + } + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_RXWTRMRKIRQ) { + SYS_LOG_DBG("got RXWTRMRKIRQ"); + irqsts1 |= MCR20A_IRQSTS1_RXWTRMRKIRQ; + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_FILTERFAIL_IRQ) { + SYS_LOG_DBG("got FILTERFAILIRQ"); + irqsts1 |= MCR20A_IRQSTS1_FILTERFAIL_IRQ; + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_RXIRQ) { + SYS_LOG_DBG("got RX ACK"); + irqsts1 |= MCR20A_IRQSTS1_RXIRQ; + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_SEQIRQ) { + SYS_LOG_DBG("SEQIRQ"); + irqsts1 |= MCR20A_IRQSTS1_SEQIRQ; + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_CCAIRQ) { + irqsts1 |= MCR20A_IRQSTS1_CCAIRQ; + + if (dregs[MCR20A_IRQSTS2] & MCR20A_IRQSTS2_CCA) { + SYS_LOG_DBG("CCA CH busy"); + atomic_set(&mcr20a->seq_retval, -EBUSY); + } + } + + atomic_set(&mcr20a->seq_retval, 0); + if (atomic_get(&mcr20a->busy) == 1) { + atomic_set(&mcr20a->busy, 0); + k_sem_give(&mcr20a->seq_sync); + } + + /* For TR, timer should be used to generate a timeout. */ + if (tr) { + mcr20a_t4cmp_clear(mcr20a); + } + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_RECEIVE)) { + SYS_LOG_ERR("Failed to set XCV sequence"); + } + + } else if (dregs[MCR20A_IRQSTS3] & MCR20A_IRQSTS3_TMR4IRQ) { + SYS_LOG_DBG("TC4TMOUT, no SEQIRQ, TR failed"); + + atomic_set(&mcr20a->seq_retval, -EBUSY); + if (atomic_get(&mcr20a->busy) == 1) { + atomic_set(&mcr20a->busy, 0); + k_sem_give(&mcr20a->seq_sync); + } + + mcr20a_t4cmp_clear(mcr20a); + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_RECEIVE)) { + SYS_LOG_ERR("Failed to set XCV sequence"); + } + } + + return irqsts1; +} + +static void _irq_event_check_irqsts(struct mcr20a_context *mcr20a, + uint8_t *dregs) +{ + if (!read_burst_irqsts1_ctrl4(&mcr20a->spi, dregs)) { + return; + } + + if (dregs[MCR20A_IRQSTS1] & MCR20A_IRQSTS1_IRQ_MASK) { + SYS_LOG_DBG("IRQSTS1 contains untreated IRQs: 0x%02x", + dregs[MCR20A_IRQSTS1]); + } + + if (dregs[MCR20A_IRQSTS2] & MCR20A_IRQSTS2_IRQ_MASK) { + SYS_LOG_DBG("IRQSTS2 contains untreated IRQs: 0x%02x", + dregs[MCR20A_IRQSTS2]); + } + + if (dregs[MCR20A_IRQSTS3] & MCR20A_IRQSTS3_IRQ_MASK) { + SYS_LOG_DBG("IRQSTS3 contains untreated IRQs: 0x%02x", + dregs[MCR20A_IRQSTS3]); + } +} + +static void irqb_handler(void *arg) +{ + struct mcr20a_context *mcr20a = (struct mcr20a_context *)arg; + uint8_t dregs[8]; + uint8_t irqsts1 = 0; + uint8_t irqsts2 = 0; + + if (!mcr20a_mask_irqb(mcr20a, true)) { + SYS_LOG_ERR("Failed to mask IRQ_B"); + goto unmask_irqb; + } + + /* Read the register from IRQSTS1 until CTRL4 */ + if (!read_burst_irqsts1_ctrl4(&mcr20a->spi, dregs)) { + SYS_LOG_ERR("Failed to read register"); + goto unmask_irqb; + } + + SYS_LOG_DBG("CTRL1 %0x, IRQSTS1 %0x, IRQSTS2 %0x, IRQSTS3 %0x", + dregs[MCR20A_PHY_CTRL1], + dregs[MCR20A_IRQSTS1], + dregs[MCR20A_IRQSTS2], + dregs[MCR20A_IRQSTS3]); + + switch (dregs[MCR20A_PHY_CTRL1] & MCR20A_PHY_CTRL1_XCVSEQ_MASK) { + case MCR20A_XCVSEQ_RECEIVE: + irqsts1 = _irq_event_seq_r(mcr20a, dregs); + break; + case MCR20A_XCVSEQ_TX: + irqsts1 = _irq_event_seq_tr(mcr20a, dregs, false); + break; + case MCR20A_XCVSEQ_CCA: + irqsts1 = _irq_event_seq_cca(mcr20a, dregs, false); + break; + case MCR20A_XCVSEQ_TX_RX: + irqsts1 = _irq_event_seq_tr(mcr20a, dregs, true); + break; + case MCR20A_XCVSEQ_CONTINUOUS_CCA: + irqsts1 = _irq_event_seq_cca(mcr20a, dregs, true); + break; + case MCR20A_XCVSEQ_IDLE: + default: + /* Clear all IRQSTST1 interrupt flags */ + irqsts1 = MCR20A_IRQSTS1_IRQ_MASK; + SYS_LOG_ERR("Undefined seq state"); + break; + } + + /* Clear relevant interrupt flags */ + if (!write_reg_irqsts1(&mcr20a->spi, irqsts1)) { + SYS_LOG_ERR("Failed to clear IRQSTS1"); + } + + dregs[MCR20A_IRQSTS1] &= ~irqsts1; + + if (dregs[MCR20A_IRQSTS2] & MCR20A_IRQSTS2_ASM_IRQ) { + SYS_LOG_ERR("Untreated ASM_IRQ"); + irqsts2 |= MCR20A_IRQSTS2_ASM_IRQ; + } + + if (dregs[MCR20A_IRQSTS2] & MCR20A_IRQSTS2_PB_ERR_IRQ) { + SYS_LOG_ERR("Untreated PB_ERR_IRQ"); + irqsts2 |= MCR20A_IRQSTS2_PB_ERR_IRQ; + } + + if (dregs[MCR20A_IRQSTS2] & MCR20A_IRQSTS2_WAKE_IRQ) { + SYS_LOG_ERR("Untreated WAKE_IRQ"); + irqsts2 |= MCR20A_IRQSTS2_WAKE_IRQ; + } + + if (!write_reg_irqsts2(&mcr20a->spi, irqsts2)) { + SYS_LOG_ERR("Failed to clear IRQSTS2"); + } + + if (SYS_LOG_LEVEL == 4) { + _irq_event_check_irqsts(mcr20a, dregs); + } + +unmask_irqb: + if (!mcr20a_mask_irqb(mcr20a, false)) { + SYS_LOG_ERR("Failed to unmask IRQ_B"); + } +} + +static void mcr20a_thread_main(void *arg1, void *unused1, void *unused2) +{ + struct device *dev = (struct device *)arg1; + struct mcr20a_context *mcr20a = dev->driver_data; + + while (true) { + k_sem_take(&mcr20a->trig_sem, K_FOREVER); + irqb_handler(mcr20a); + } +} + +static inline void irqb_int_handler(struct device *port, + struct gpio_callback *cb, uint32_t pins) +{ + struct mcr20a_context *mcr20a = CONTAINER_OF(cb, + struct mcr20a_context, + irqb_cb); + k_sem_give(&mcr20a->trig_sem); +} + +static inline void set_reset(struct device *dev, uint32_t value) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + gpio_pin_write(mcr20a->reset_gpio, + CONFIG_MCR20A_GPIO_RESET_PIN, value); +} + +static void enable_irqb_interrupt(struct mcr20a_context *mcr20a, + bool enable) +{ + if (enable) { + gpio_pin_enable_callback(mcr20a->irq_gpio, + CONFIG_MCR20A_GPIO_IRQ_B_PIN); + } else { + gpio_pin_disable_callback(mcr20a->irq_gpio, + CONFIG_MCR20A_GPIO_IRQ_B_PIN); + } +} + +static inline void setup_gpio_callbacks(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + gpio_init_callback(&mcr20a->irqb_cb, + irqb_int_handler, + BIT(CONFIG_MCR20A_GPIO_IRQ_B_PIN)); + gpio_add_callback(mcr20a->irq_gpio, &mcr20a->irqb_cb); +} + +static int mcr20a_set_cca_mode(struct device *dev, uint8_t mode) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t ctrl4; + + ctrl4 = read_reg_phy_ctrl4(&mcr20a->spi); + ctrl4 &= ~MCR20A_PHY_CTRL4_CCATYPE_MASK; + ctrl4 |= set_bits_phy_ctrl4_ccatype(mode); + + if (!write_reg_phy_ctrl4(&mcr20a->spi, ctrl4)) { + SYS_LOG_ERR("Failed"); + return -EIO; + } + + return 0; +} + +/* Note: CCA before TX is enabled by default */ +static int mcr20a_cca(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t ctrl1; + + if (atomic_get(&mcr20a->busy) == 1) { + SYS_LOG_ERR("Blocked due to TX or CCA operation"); + return -EBUSY; + } + + if (!mcr20a_mask_irqb(mcr20a, true)) { + goto error; + } + + ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX) { + SYS_LOG_ERR("Busy, TX sequence running"); + goto error; + } + + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX_RX) { + SYS_LOG_ERR("Busy, TX_RX sequence running"); + goto error; + } + + atomic_set(&mcr20a->busy, 1); + atomic_set(&mcr20a->seq_retval, 0); + k_sem_init(&mcr20a->seq_sync, 0, UINT_MAX); + + /** + * There is no write access to packet buffer, + * so set the new sequence immediately. + */ + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_CCA)) { + SYS_LOG_ERR("Failed to reset XCV sequence"); + goto error; + } + + if (!mcr20a_mask_irqb(mcr20a, false)) { + goto error; + } + + k_sem_take(&mcr20a->seq_sync, 10); + + return mcr20a->seq_retval; + +error: + atomic_set(&mcr20a->busy, 0); + return -EIO; +} + +static int mcr20a_set_channel(struct device *dev, uint16_t channel) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t buf[3]; + uint8_t ctrl1; + int retval = -EIO; + + if (channel < 11 || channel > 26) { + SYS_LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + if (!mcr20a_mask_irqb(mcr20a, true)) { + SYS_LOG_ERR("Failed to unmask IRQ_B"); + goto out; + } + + ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX) { + SYS_LOG_ERR("Busy, TX sequence running"); + goto out; + } + + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX_RX) { + SYS_LOG_ERR("Busy, TX_RX sequence running"); + goto out; + } + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_IDLE)) { + SYS_LOG_ERR("Failed to reset XCV sequence"); + goto out; + } + + SYS_LOG_DBG("%u", channel); + channel -= 11; + buf[0] = set_bits_pll_int0_val(pll_int_lt[channel]); + buf[1] = (uint8_t)pll_frac_lt[channel]; + buf[2] = (uint8_t)(pll_frac_lt[channel] >> 8); + + if (!write_burst_pll_int0(&mcr20a->spi, buf)) { + SYS_LOG_ERR("Failed to set PLL"); + goto out; + } + + if (mcr20a_set_sequence(mcr20a, ctrl1)) { + SYS_LOG_ERR("Failed to restore XCV sequence"); + goto out; + } + + retval = 0; + +out: + if (!mcr20a_mask_irqb(mcr20a, false)) { + SYS_LOG_ERR("Failed to unmask IRQ_B"); + retval = -EIO; + } + + return retval; +} + +static int mcr20a_set_pan_id(struct device *dev, uint16_t pan_id) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + pan_id = sys_le16_to_cpu(pan_id); + + if (!write_burst_pan_id(&mcr20a->spi, (uint8_t *) &pan_id)) { + SYS_LOG_ERR("FAILED"); + return -EIO; + } + + SYS_LOG_DBG("0x%x", pan_id); + + return 0; +} + +static int mcr20a_set_short_addr(struct device *dev, uint16_t short_addr) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + short_addr = sys_le16_to_cpu(short_addr); + + if (!write_burst_short_addr(&mcr20a->spi, (uint8_t *) &short_addr)) { + SYS_LOG_ERR("FAILED"); + return -EIO; + } + + SYS_LOG_DBG("0x%x", short_addr); + + return 0; +} + +static int mcr20a_set_ieee_addr(struct device *dev, const uint8_t *ieee_addr) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + if (!write_burst_ext_addr(&mcr20a->spi, (void *)ieee_addr)) { + SYS_LOG_ERR("Failed"); + return -EIO; + } + + SYS_LOG_DBG("IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + ieee_addr[7], ieee_addr[6], ieee_addr[5], ieee_addr[4], + ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]); + + return 0; +} + +static int mcr20a_set_txpower(struct device *dev, int16_t dbm) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t pwr; + + SYS_LOG_DBG("%d", dbm); + + if ((dbm > MCR20A_OUTPUT_POWER_MAX) || + (dbm < MCR20A_OUTPUT_POWER_MIN)) { + goto error; + } + + pwr = pow_lt[dbm - MCR20A_OUTPUT_POWER_MIN]; + if (!write_reg_pa_pwr(&mcr20a->spi, set_bits_pa_pwr_val(pwr))) { + goto error; + } + + return 0; +error: + SYS_LOG_DBG("Failed"); + return -EIO; +} + +static inline bool write_txfifo_content(struct mcr20a_spi *spi, + struct net_buf *buf) +{ + uint8_t cmd[2 + MCR20A_PSDU_LENGTH]; + uint8_t payload_len = net_nbuf_ll_reserve(buf) + + buf->frags->len; + + cmd[0] = MCR20A_BUF_WRITE; + /** + * The length of the packet (PSDU + FSC), + * is stored at index 0, followed by the PSDU. + * Note: maximum FRAME_LEN is 125 + MCR20A_FCS_LENGTH + */ + cmd[1] = payload_len + MCR20A_FCS_LENGTH; + + if (payload_len > MCR20A_PSDU_LENGTH) { + SYS_LOG_ERR("Payload too long"); + return 0; + } + memcpy(&cmd[2], net_nbuf_ll(buf), payload_len); + + spi_slave_select(spi->dev, spi->slave); + + return (spi_write(spi->dev, cmd, (2 + payload_len)) == 0); +} + +static int mcr20a_tx(struct device *dev, struct net_buf *buf) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t ctrl1; + uint8_t seq = MCR20A_AUTOACK_ENABLED ? MCR20A_XCVSEQ_TX_RX : + MCR20A_XCVSEQ_TX; + + SYS_LOG_DBG("%p (%u)", + buf, net_nbuf_ll_reserve(buf) + buf->frags->len); + + if (!mcr20a_mask_irqb(mcr20a, true)) { + goto error; + } + + ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX) { + SYS_LOG_ERR("Busy, TX sequence running"); + goto error; + } + + if ((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX_RX) { + SYS_LOG_ERR("Busy, TX_RX sequence running"); + goto error; + } + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_IDLE)) { + SYS_LOG_ERR("Failed to reset XCV sequence"); + goto error; + } + + if (!mcr20a_mask_irqb(mcr20a, false)) { + goto error; + } + + if (!write_txfifo_content(&mcr20a->spi, buf)) { + SYS_LOG_ERR("Did not write properly into TX FIFO"); + goto error; + } + + atomic_set(&mcr20a->busy, 1); + k_sem_init(&mcr20a->seq_sync, 0, UINT_MAX); + + if (mcr20a_set_sequence(mcr20a, seq)) { + SYS_LOG_ERR("Cannot start transmission"); + goto error; + } + + k_sem_take(&mcr20a->seq_sync, 10); + + return 0; +error: + atomic_set(&mcr20a->busy, 0); + return -EIO; +} + +static int mcr20a_start(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t timeout = 6; + uint8_t status; + + if (!write_reg_pwr_modes(&mcr20a->spi, MCR20A_PM_AUTODOZE)) { + SYS_LOG_ERR("Error starting MCR20A"); + return -EIO; + } + + do { + _usleep(50); + timeout--; + status = read_reg_pwr_modes(&mcr20a->spi); + } while (!(status & MCR20A_PWR_MODES_XTAL_READY) && timeout); + + if (!(status & MCR20A_PWR_MODES_XTAL_READY)) { + SYS_LOG_ERR("Timeout, failed to wake up"); + return -EIO; + } + + /* Clear all interrupt flags */ + write_reg_irqsts1(&mcr20a->spi, MCR20A_IRQSTS1_IRQ_MASK); + write_reg_irqsts2(&mcr20a->spi, MCR20A_IRQSTS2_IRQ_MASK); + write_reg_irqsts3(&mcr20a->spi, MCR20A_IRQSTS3_IRQ_MASK | + MCR20A_IRQSTS3_TMR_MASK); + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_RECEIVE)) { + SYS_LOG_ERR("failed to set XCV sequence"); + return -EIO; + } + + enable_irqb_interrupt(mcr20a, true); + + SYS_LOG_DBG("started"); + return 0; +} + +static int mcr20a_stop(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + if (mcr20a_set_sequence(mcr20a, MCR20A_XCVSEQ_IDLE)) { + goto error; + } + + enable_irqb_interrupt(mcr20a, false); + + if (!write_reg_pwr_modes(&mcr20a->spi, MCR20A_PM_HIBERNATE)) { + goto error; + } + + SYS_LOG_DBG("stopped"); + + return 0; + +error: + SYS_LOG_ERR("Error stopping MCR20A"); + return -EIO; +} + +static uint8_t mcr20a_get_lqi(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + SYS_LOG_DBG(""); + return mcr20a->lqi; +} + +static int mcr20a_update_overwrites(struct mcr20a_context *dev) +{ + struct mcr20a_spi *spi = &dev->spi; + + if (!write_reg_overwrite_ver(spi, overwrites_direct[0].data)) { + goto error; + } + + for (uint8_t i = 0; + i < sizeof(overwrites_indirect) / sizeof(overwrites_t); + i++) { + + spi->cmd_buf[0] = MCR20A_IAR_INDEX | MCR20A_REG_WRITE; + spi->cmd_buf[1] = overwrites_indirect[i].address; + spi->cmd_buf[2] = overwrites_indirect[i].data; + + spi_slave_select(spi->dev, spi->slave); + + if (spi_write(spi->dev, spi->cmd_buf, 3)) { + goto error; + } + } + + return 0; + +error: + SYS_LOG_ERR("Error update overwrites"); + return -EIO; +} + +static int power_on_and_setup(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t timeout = 6; + uint32_t status; + uint8_t tmp = 0; + + set_reset(dev, 0); + _usleep(150); + set_reset(dev, 1); + + do { + _usleep(50); + timeout--; + gpio_pin_read(mcr20a->irq_gpio, + CONFIG_MCR20A_GPIO_IRQ_B_PIN, &status); + } while (status && timeout); + + if (status) { + SYS_LOG_ERR("Timeout, failed to get WAKE IRQ"); + return -EIO; + } + + tmp = MCR20A_CLK_OUT_CONFIG | MCR20A_CLK_OUT_EXTEND; + write_reg_clk_out_ctrl(&mcr20a->spi, tmp); + + if (read_reg_clk_out_ctrl(&mcr20a->spi) != tmp) { + SYS_LOG_ERR("Failed to get device up"); + return -EIO; + } + + /* Clear all interrupt flags */ + write_reg_irqsts1(&mcr20a->spi, MCR20A_IRQSTS1_IRQ_MASK); + write_reg_irqsts2(&mcr20a->spi, MCR20A_IRQSTS2_IRQ_MASK); + write_reg_irqsts3(&mcr20a->spi, MCR20A_IRQSTS3_IRQ_MASK | + MCR20A_IRQSTS3_TMR_MASK); + + mcr20a_update_overwrites(mcr20a); + mcr20a_timer_init(dev, MCR20A_TIMEBASE_62500HZ); + + mcr20a_set_txpower(dev, MCR20A_DEFAULT_TX_POWER); + mcr20a_set_channel(dev, MCR20A_DEFAULT_CHANNEL); + mcr20a_set_cca_mode(dev, 1); + write_reg_rx_wtr_mark(&mcr20a->spi, 8); + + /* Configure PHY behaviour */ + tmp = MCR20A_PHY_CTRL1_CCABFRTX; + if (MCR20A_AUTOACK_ENABLED) { + tmp |= MCR20A_PHY_CTRL1_AUTOACK | + MCR20A_PHY_CTRL1_RXACKRQD; + } + write_reg_phy_ctrl1(&mcr20a->spi, tmp); + + /* Configure PHY interrupts */ + write_reg_phy_ctrl2(&mcr20a->spi, ~(uint8_t)( + MCR20A_PHY_CTRL2_RXMSK | + MCR20A_PHY_CTRL2_TXMSK | + MCR20A_PHY_CTRL2_SEQMSK)); + setup_gpio_callbacks(dev); + + return 0; +} + + +static inline int configure_gpios(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + /* setup gpio for the modem interrupt */ + mcr20a->irq_gpio = device_get_binding(CONFIG_MCR20A_GPIO_IRQ_B_NAME); + if (mcr20a->irq_gpio == NULL) { + SYS_LOG_ERR("Failed to get pointer to %s device", + CONFIG_MCR20A_GPIO_IRQ_B_NAME); + return -EINVAL; + } + + gpio_pin_configure(mcr20a->irq_gpio, + CONFIG_MCR20A_GPIO_IRQ_B_PIN, + GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | + GPIO_INT_ACTIVE_LOW); + + /* setup gpio for the modems reset */ + mcr20a->reset_gpio = device_get_binding(CONFIG_MCR20A_GPIO_RESET_NAME); + if (mcr20a->reset_gpio == NULL) { + SYS_LOG_ERR("Failed to get pointer to %s device", + CONFIG_MCR20A_GPIO_RESET_NAME); + return -EINVAL; + } + + gpio_pin_configure(mcr20a->reset_gpio, CONFIG_MCR20A_GPIO_RESET_PIN, + GPIO_DIR_OUT); + set_reset(dev, 0); + + return 0; +} + +static inline int configure_spi(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + struct spi_config spi_conf = { + .config = SPI_WORD(8), + .max_sys_freq = CONFIG_NXP_MCR20A_SPI_FREQ, + }; + + mcr20a->spi.dev = device_get_binding(CONFIG_NXP_MCR20A_SPI_DRV_NAME); + if (!mcr20a->spi.dev) { + SYS_LOG_ERR("Unable to get SPI device"); + return -ENODEV; + } + + mcr20a->spi.slave = CONFIG_NXP_MCR20A_SPI_SLAVE; + + if (spi_configure(mcr20a->spi.dev, &spi_conf) != 0 || + spi_slave_select(mcr20a->spi.dev, + mcr20a->spi.slave) != 0) { + mcr20a->spi.dev = NULL; + return -EIO; + } + + SYS_LOG_DBG("SPI configured %s, %d", CONFIG_NXP_MCR20A_SPI_DRV_NAME, + CONFIG_NXP_MCR20A_SPI_SLAVE); + + return 0; +} + +static int mcr20a_init(struct device *dev) +{ + struct mcr20a_context *mcr20a = dev->driver_data; + + atomic_set(&mcr20a->busy, 0); + k_sem_init(&mcr20a->trig_sem, 0, UINT_MAX); + + SYS_LOG_DBG("\nInitialize MCR20A Transceiver\n"); + + if (configure_gpios(dev) != 0) { + SYS_LOG_ERR("Configuring GPIOS failed"); + return -EIO; + } + + if (configure_spi(dev) != 0) { + SYS_LOG_ERR("Configuring SPI failed"); + return -EIO; + } + + SYS_LOG_DBG("GPIO and SPI configured"); + + if (power_on_and_setup(dev) != 0) { + SYS_LOG_ERR("Configuring MCR20A failed"); + return -EIO; + } + + k_thread_spawn(mcr20a->mcr20a_rx_stack, + CONFIG_NXP_MCR20A_RX_STACK_SIZE, + (k_thread_entry_t)mcr20a_thread_main, + dev, NULL, NULL, + K_PRIO_COOP(2), 0, 0); + + return 0; +} + +static void mcr20a_iface_init(struct net_if *iface) +{ + struct device *dev = net_if_get_device(iface); + struct mcr20a_context *mcr20a = dev->driver_data; + uint8_t *mac = get_mac(dev); + + net_if_set_link_addr(iface, mac, 8); + + mcr20a->iface = iface; + + ieee802154_init(iface); + + SYS_LOG_DBG("done"); +} + +static struct mcr20a_context mcr20a_context_data; + +static struct ieee802154_radio_api mcr20a_radio_api = { + .iface_api.init = mcr20a_iface_init, + .iface_api.send = ieee802154_radio_send, + + .cca = mcr20a_cca, + .set_channel = mcr20a_set_channel, + .set_pan_id = mcr20a_set_pan_id, + .set_short_addr = mcr20a_set_short_addr, + .set_ieee_addr = mcr20a_set_ieee_addr, + .set_txpower = mcr20a_set_txpower, + .start = mcr20a_start, + .stop = mcr20a_stop, + .tx = mcr20a_tx, + .get_lqi = mcr20a_get_lqi, +}; + +#if defined(CONFIG_NXP_MCR20A_RAW) +DEVICE_AND_API_INIT(mcr20a, CONFIG_NXP_MCR20A_DRV_NAME, + mcr20a_init, &mcr20a_context_data, NULL, + POST_KERNEL, CONFIG_NXP_MCR20A_INIT_PRIO, + &mcr20a_radio_api); +#else +NET_DEVICE_INIT(mcr20a, CONFIG_NXP_MCR20A_DRV_NAME, + mcr20a_init, &mcr20a_context_data, NULL, + CONFIG_NXP_MCR20A_INIT_PRIO, + &mcr20a_radio_api, IEEE802154_L2, + NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125); +#endif diff --git a/drivers/ieee802154/ieee802154_mcr20a.h b/drivers/ieee802154/ieee802154_mcr20a.h new file mode 100644 index 000000000..acc85ec51 --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcr20a.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017 PHYTEC Messtechnik GmbH + * + * Portions of this file are derived from ieee802154_cc2520.h that is + * Copyright (c) 2016 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __IEEE802154_MCR20A_H__ +#define __IEEE802154_MCR20A_H__ + +#include <sections.h> +#include <atomic.h> +#include <spi.h> + +/* Runtime context structure + *************************** + */ +struct mcr20a_spi { + struct device *dev; + uint32_t slave; + /** + * cmd_buf will use at most 9 bytes: + * dummy bytes + 8 ieee address bytes + */ + uint8_t cmd_buf[12]; +}; + +struct mcr20a_context { + struct net_if *iface; + /**************************/ + struct device *irq_gpio; + struct device *reset_gpio; + struct gpio_callback irqb_cb; + struct mcr20a_spi spi; + uint8_t mac_addr[8]; + /*********TX + CCA*********/ + struct k_sem seq_sync; + atomic_t busy; + atomic_t seq_retval; + /************RX************/ + char __stack mcr20a_rx_stack[CONFIG_NXP_MCR20A_RX_STACK_SIZE]; + struct k_sem trig_sem; + uint8_t lqi; +}; + +#include "ieee802154_mcr20a_regs.h" + +uint8_t _mcr20a_read_reg(struct mcr20a_spi *spi, bool dreg, uint8_t addr); +bool _mcr20a_write_reg(struct mcr20a_spi *spi, bool dreg, uint8_t addr, + uint8_t value); +bool _mcr20a_write_burst(struct mcr20a_spi *spi, bool dreg, uint16_t addr, + uint8_t *data_buf, uint8_t len); +bool _mcr20a_read_burst(struct mcr20a_spi *spi, bool dreg, uint16_t addr, + uint8_t *data_buf, uint8_t len); + +#define DEFINE_REG_READ(__reg_name, __reg_addr, __dreg) \ + static inline uint8_t read_reg_##__reg_name(struct mcr20a_spi *spi) \ + { \ + return _mcr20a_read_reg(spi, __dreg, __reg_addr); \ + } + +#define DEFINE_REG_WRITE(__reg_name, __reg_addr, __dreg) \ + static inline bool write_reg_##__reg_name(struct mcr20a_spi *spi, \ + uint8_t value) \ + { \ + return _mcr20a_write_reg(spi, __dreg, __reg_addr, value); \ + } + +#define DEFINE_DREG_READ(__reg_name, __reg_addr) \ + DEFINE_REG_READ(__reg_name, __reg_addr, true) +#define DEFINE_DREG_WRITE(__reg_name, __reg_addr) \ + DEFINE_REG_WRITE(__reg_name, __reg_addr, true) + +#define DEFINE_IREG_READ(__reg_name, __reg_addr) \ + DEFINE_REG_READ(__reg_name, __reg_addr, false) +#define DEFINE_IREG_WRITE(__reg_name, __reg_addr) \ + DEFINE_REG_WRITE(__reg_name, __reg_addr, false) + +DEFINE_DREG_READ(irqsts1, MCR20A_IRQSTS1) +DEFINE_DREG_READ(irqsts2, MCR20A_IRQSTS2) +DEFINE_DREG_READ(irqsts3, MCR20A_IRQSTS3) +DEFINE_DREG_READ(phy_ctrl1, MCR20A_PHY_CTRL1) +DEFINE_DREG_READ(phy_ctrl2, MCR20A_PHY_CTRL2) +DEFINE_DREG_READ(phy_ctrl3, MCR20A_PHY_CTRL3) +DEFINE_DREG_READ(rx_frm_len, MCR20A_RX_FRM_LEN) +DEFINE_DREG_READ(phy_ctrl4, MCR20A_PHY_CTRL4) +DEFINE_DREG_READ(src_ctrl, MCR20A_SRC_CTRL) +DEFINE_DREG_READ(cca1_ed_fnl, MCR20A_CCA1_ED_FNL) +DEFINE_DREG_READ(pll_int0, MCR20A_PLL_INT0) +DEFINE_DREG_READ(pa_pwr, MCR20A_PA_PWR) +DEFINE_DREG_READ(seq_state, MCR20A_SEQ_STATE) +DEFINE_DREG_READ(lqi_value, MCR20A_LQI_VALUE) +DEFINE_DREG_READ(rssi_cca_cnt, MCR20A_RSSI_CCA_CNT) +DEFINE_DREG_READ(asm_ctrl1, MCR20A_ASM_CTRL1) +DEFINE_DREG_READ(asm_ctrl2, MCR20A_ASM_CTRL2) +DEFINE_DREG_READ(overwrite_ver, MCR20A_OVERWRITE_VER) +DEFINE_DREG_READ(clk_out_ctrl, MCR20A_CLK_OUT_CTRL) +DEFINE_DREG_READ(pwr_modes, MCR20A_PWR_MODES) + +DEFINE_DREG_WRITE(irqsts1, MCR20A_IRQSTS1) +DEFINE_DREG_WRITE(irqsts2, MCR20A_IRQSTS2) +DEFINE_DREG_WRITE(irqsts3, MCR20A_IRQSTS3) +DEFINE_DREG_WRITE(phy_ctrl1, MCR20A_PHY_CTRL1) +DEFINE_DREG_WRITE(phy_ctrl2, MCR20A_PHY_CTRL2) +DEFINE_DREG_WRITE(phy_ctrl3, MCR20A_PHY_CTRL3) +DEFINE_DREG_WRITE(phy_ctrl4, MCR20A_PHY_CTRL4) +DEFINE_DREG_WRITE(src_ctrl, MCR20A_SRC_CTRL) +DEFINE_DREG_WRITE(pll_int0, MCR20A_PLL_INT0) +DEFINE_DREG_WRITE(pa_pwr, MCR20A_PA_PWR) +DEFINE_DREG_WRITE(asm_ctrl1, MCR20A_ASM_CTRL1) +DEFINE_DREG_WRITE(asm_ctrl2, MCR20A_ASM_CTRL2) +DEFINE_DREG_WRITE(overwrite_ver, MCR20A_OVERWRITE_VER) +DEFINE_DREG_WRITE(clk_out_ctrl, MCR20A_CLK_OUT_CTRL) +DEFINE_DREG_WRITE(pwr_modes, MCR20A_PWR_MODES) + +DEFINE_IREG_READ(part_id, MCR20A_PART_ID) +DEFINE_IREG_READ(rx_frame_filter, MCR20A_RX_FRAME_FILTER) +DEFINE_IREG_READ(cca1_thresh, MCR20A_CCA1_THRESH) +DEFINE_IREG_READ(cca1_ed_offset_comp, MCR20A_CCA1_ED_OFFSET_COMP) +DEFINE_IREG_READ(lqi_offset_comp, MCR20A_LQI_OFFSET_COMP) +DEFINE_IREG_READ(cca_ctrl, MCR20A_CCA_CTRL) +DEFINE_IREG_READ(cca2_corr_peaks, MCR20A_CCA2_CORR_PEAKS) +DEFINE_IREG_READ(cca2_thresh, MCR20A_CCA2_THRESH) +DEFINE_IREG_READ(tmr_prescale, MCR20A_TMR_PRESCALE) +DEFINE_IREG_READ(rx_byte_count, MCR20A_RX_BYTE_COUNT) +DEFINE_IREG_READ(rx_wtr_mark, MCR20A_RX_WTR_MARK) + +DEFINE_IREG_WRITE(part_id, MCR20A_PART_ID) +DEFINE_IREG_WRITE(rx_frame_filter, MCR20A_RX_FRAME_FILTER) +DEFINE_IREG_WRITE(cca1_thresh, MCR20A_CCA1_THRESH) +DEFINE_IREG_WRITE(cca1_ed_offset_comp, MCR20A_CCA1_ED_OFFSET_COMP) +DEFINE_IREG_WRITE(lqi_offset_comp, MCR20A_LQI_OFFSET_COMP) +DEFINE_IREG_WRITE(cca_ctrl, MCR20A_CCA_CTRL) +DEFINE_IREG_WRITE(cca2_corr_peaks, MCR20A_CCA2_CORR_PEAKS) +DEFINE_IREG_WRITE(cca2_thresh, MCR20A_CCA2_THRESH) +DEFINE_IREG_WRITE(tmr_prescale, MCR20A_TMR_PRESCALE) +DEFINE_IREG_WRITE(rx_byte_count, MCR20A_RX_BYTE_COUNT) +DEFINE_IREG_WRITE(rx_wtr_mark, MCR20A_RX_WTR_MARK) + +#define DEFINE_BITS_SET(__reg_name, __reg_addr, __nibble) \ + static inline uint8_t set_bits_##__reg_name(uint8_t value) \ + { \ + value = (value << __reg_addr##__nibble##_SHIFT) & \ + __reg_addr##__nibble##_MASK; \ + return value; \ + } + +DEFINE_BITS_SET(phy_ctrl1_xcvseq, MCR20A_PHY_CTRL1, _XCVSEQ) +DEFINE_BITS_SET(phy_ctrl4_ccatype, MCR20A_PHY_CTRL4, _CCATYPE) +DEFINE_BITS_SET(pll_int0_val, MCR20A_PLL_INT0, _VAL) +DEFINE_BITS_SET(pa_pwr_val, MCR20A_PA_PWR, _VAL) +DEFINE_BITS_SET(tmr_prescale, MCR20A_TMR_PRESCALE, _VAL) + +#define DEFINE_BURST_WRITE(__reg_addr, __addr, __sz, __dreg) \ + static inline bool write_burst_##__reg_addr(struct mcr20a_spi *spi, \ + uint8_t *buf) \ + { \ + return _mcr20a_write_burst(spi, __dreg, __addr, buf, __sz); \ + } + +#define DEFINE_BURST_READ(__reg_addr, __addr, __sz, __dreg) \ + static inline bool read_burst_##__reg_addr(struct mcr20a_spi *spi, \ + uint8_t *buf) \ + { \ + return _mcr20a_read_burst(spi, __dreg, __addr, buf, __sz); \ + } + +DEFINE_BURST_WRITE(t1cmp, MCR20A_T1CMP_LSB, 3, true) +DEFINE_BURST_WRITE(t2cmp, MCR20A_T2CMP_LSB, 3, true) +DEFINE_BURST_WRITE(t3cmp, MCR20A_T3CMP_LSB, 3, true) +DEFINE_BURST_WRITE(t4cmp, MCR20A_T4CMP_LSB, 3, true) +DEFINE_BURST_WRITE(t2primecmp, MCR20A_T2PRIMECMP_LSB, 2, true) +DEFINE_BURST_WRITE(pll_int0, MCR20A_PLL_INT0, 3, true) + +DEFINE_BURST_WRITE(pan_id, MCR20A_MACPANID0_LSB, 2, false) +DEFINE_BURST_WRITE(short_addr, MCR20A_MACSHORTADDRS0_LSB, 2, false) +DEFINE_BURST_WRITE(ext_addr, MCR20A_MACLONGADDRS0_0, 8, false) + +DEFINE_BURST_READ(event_timer, MCR20A_EVENT_TIMER_LSB, 3, true) +DEFINE_BURST_READ(irqsts1_ctrl4, MCR20A_IRQSTS1, 8, true) + +#endif /* __IEEE802154_MCR20A_H__ */ diff --git a/drivers/ieee802154/ieee802154_mcr20a_regs.h b/drivers/ieee802154/ieee802154_mcr20a_regs.h new file mode 100644 index 000000000..5f22bceb0 --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcr20a_regs.h @@ -0,0 +1,590 @@ +/* ieee802154_mcr20a_regs.h - Registers definition for NXP MCR20A */ + +/* + * Copyright (c) 2016 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + * + * This file is based on MCR20reg.h, it was modified to meet the + * coding style and restructured to make it easier to read. + * Additional identifiers was inserted (_MASK and _SHIFT endings), + * which are used in the macros for the bit field manipulation. + * + * This file are derived from material that is + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __IEEE802154_MCR20A_REGS_H__ +#define __IEEE802154_MCR20A_REGS_H__ + +#define MCR20A_REG_READ (BIT(7)) +#define MCR20A_BUF_READ (BIT(7) | BIT(6)) +#define MCR20A_BUF_BYTE_READ (BIT(7) | BIT(6) | BIT(5)) +#define MCR20A_REG_WRITE (0) +#define MCR20A_BUF_WRITE (BIT(6)) +#define MCR20A_BUF_BYTE_WRITE (BIT(6) | BIT(5)) + +#define MCR20A_IRQSTS1 (0x0) +#define MCR20A_IRQSTS2 (0x1) +#define MCR20A_IRQSTS3 (0x2) +#define MCR20A_PHY_CTRL1 (0x3) +#define MCR20A_PHY_CTRL2 (0x4) +#define MCR20A_PHY_CTRL3 (0x5) +#define MCR20A_RX_FRM_LEN (0x6) +#define MCR20A_PHY_CTRL4 (0x7) +#define MCR20A_SRC_CTRL (0x8) +#define MCR20A_SRC_ADDRS_SUM_LSB (0x9) +#define MCR20A_SRC_ADDRS_SUM_MSB (0xa) +#define MCR20A_CCA1_ED_FNL (0xb) +#define MCR20A_EVENT_TIMER_LSB (0xc) +#define MCR20A_EVENT_TIMER_MSB (0xd) +#define MCR20A_EVENT_TIMER_USB (0xe) +#define MCR20A_TIMESTAMP_LSB (0xf) +#define MCR20A_TIMESTAMP_MSB (0x10) +#define MCR20A_TIMESTAMP_USB (0x11) +#define MCR20A_T3CMP_LSB (0x12) +#define MCR20A_T3CMP_MSB (0x13) +#define MCR20A_T3CMP_USB (0x14) +#define MCR20A_T2PRIMECMP_LSB (0x15) +#define MCR20A_T2PRIMECMP_MSB (0x16) +#define MCR20A_T1CMP_LSB (0x17) +#define MCR20A_T1CMP_MSB (0x18) +#define MCR20A_T1CMP_USB (0x19) +#define MCR20A_T2CMP_LSB (0x1a) +#define MCR20A_T2CMP_MSB (0x1b) +#define MCR20A_T2CMP_USB (0x1c) +#define MCR20A_T4CMP_LSB (0x1d) +#define MCR20A_T4CMP_MSB (0x1e) +#define MCR20A_T4CMP_USB (0x1f) +#define MCR20A_PLL_INT0 (0x20) +#define MCR20A_PLL_FRAC0_LSB (0x21) +#define MCR20A_PLL_FRAC0_MSB (0x22) +#define MCR20A_PA_PWR (0x23) +#define MCR20A_SEQ_STATE (0x24) +#define MCR20A_LQI_VALUE (0x25) +#define MCR20A_RSSI_CCA_CNT (0x26) +/* ---------------- (0x27) */ +#define MCR20A_ASM_CTRL1 (0x28) +#define MCR20A_ASM_CTRL2 (0x29) +#define MCR20A_ASM_DATA_0 (0x2a) +#define MCR20A_ASM_DATA_1 (0x2b) +#define MCR20A_ASM_DATA_2 (0x2c) +#define MCR20A_ASM_DATA_3 (0x2d) +#define MCR20A_ASM_DATA_4 (0x2e) +#define MCR20A_ASM_DATA_5 (0x2f) +#define MCR20A_ASM_DATA_6 (0x30) +#define MCR20A_ASM_DATA_7 (0x31) +#define MCR20A_ASM_DATA_8 (0x32) +#define MCR20A_ASM_DATA_9 (0x33) +#define MCR20A_ASM_DATA_A (0x34) +#define MCR20A_ASM_DATA_B (0x35) +#define MCR20A_ASM_DATA_C (0x36) +#define MCR20A_ASM_DATA_D (0x37) +#define MCR20A_ASM_DATA_E (0x38) +#define MCR20A_ASM_DATA_F (0x39) +/* ---------------- (0x3a) */ +#define MCR20A_OVERWRITE_VER (0x3b) +#define MCR20A_CLK_OUT_CTRL (0x3c) +#define MCR20A_PWR_MODES (0x3d) +#define MCR20A_IAR_INDEX (0x3e) +#define MCR20A_IAR_DATA (0x3f) + +#define MCR20A_IRQSTS1_RX_FRM_PEND BIT(7) +#define MCR20A_IRQSTS1_PLL_UNLOCK_IRQ BIT(6) +#define MCR20A_IRQSTS1_FILTERFAIL_IRQ BIT(5) +#define MCR20A_IRQSTS1_RXWTRMRKIRQ BIT(4) +#define MCR20A_IRQSTS1_CCAIRQ BIT(3) +#define MCR20A_IRQSTS1_RXIRQ BIT(2) +#define MCR20A_IRQSTS1_TXIRQ BIT(1) +#define MCR20A_IRQSTS1_SEQIRQ BIT(0) +#define MCR20A_IRQSTS1_IRQ_MASK (0x7f) + +#define MCR20A_IRQSTS2_CRCVALID BIT(7) +#define MCR20A_IRQSTS2_CCA BIT(6) +#define MCR20A_IRQSTS2_SRCADDR BIT(5) +#define MCR20A_IRQSTS2_PI BIT(4) +#define MCR20A_IRQSTS2_TMRSTATUS BIT(3) +#define MCR20A_IRQSTS2_ASM_IRQ BIT(2) +#define MCR20A_IRQSTS2_PB_ERR_IRQ BIT(1) +#define MCR20A_IRQSTS2_WAKE_IRQ BIT(0) +#define MCR20A_IRQSTS2_IRQ_MASK (0x7) + +#define MCR20A_IRQSTS3_TMR4MSK BIT(7) +#define MCR20A_IRQSTS3_TMR3MSK BIT(6) +#define MCR20A_IRQSTS3_TMR2MSK BIT(5) +#define MCR20A_IRQSTS3_TMR1MSK BIT(4) +#define MCR20A_IRQSTS3_TMR_MASK (0xf0) +#define MCR20A_IRQSTS3_TMR4IRQ BIT(3) +#define MCR20A_IRQSTS3_TMR3IRQ BIT(2) +#define MCR20A_IRQSTS3_TMR2IRQ BIT(1) +#define MCR20A_IRQSTS3_TMR1IRQ BIT(0) +#define MCR20A_IRQSTS3_IRQ_MASK (0xf) +#define MCR20A_IRQSTS3_IRQ_SHIFT (0) + +#define MCR20A_PHY_CTRL1_TMRTRIGEN BIT(7) +#define MCR20A_PHY_CTRL1_SLOTTED BIT(6) +#define MCR20A_PHY_CTRL1_CCABFRTX BIT(5) +#define MCR20A_PHY_CTRL1_RXACKRQD BIT(4) +#define MCR20A_PHY_CTRL1_AUTOACK BIT(3) +#define MCR20A_PHY_CTRL1_XCVSEQ_MASK (0x7) +#define MCR20A_PHY_CTRL1_XCVSEQ_SHIFT (0) + +#define MCR20A_XCVSEQ_IDLE (0) +#define MCR20A_XCVSEQ_RECEIVE (1) +#define MCR20A_XCVSEQ_TX (2) +#define MCR20A_XCVSEQ_CCA (3) +#define MCR20A_XCVSEQ_TX_RX (4) +#define MCR20A_XCVSEQ_CONTINUOUS_CCA (5) + +#define MCR20A_PHY_CTRL2_CRC_MSK BIT(7) +#define MCR20A_PHY_CTRL2_PLL_UNLOCK_MSK BIT(6) +#define MCR20A_PHY_CTRL2_FILTERFAIL_MSK BIT(5) +#define MCR20A_PHY_CTRL2_RX_WMRK_MSK BIT(4) +#define MCR20A_PHY_CTRL2_CCAMSK BIT(3) +#define MCR20A_PHY_CTRL2_RXMSK BIT(2) +#define MCR20A_PHY_CTRL2_TXMSK BIT(1) +#define MCR20A_PHY_CTRL2_SEQMSK BIT(0) + +#define MCR20A_PHY_CTRL3_TMR4CMP_EN BIT(7) +#define MCR20A_PHY_CTRL3_TMR3CMP_EN BIT(6) +#define MCR20A_PHY_CTRL3_TMR2CMP_EN BIT(5) +#define MCR20A_PHY_CTRL3_TMR1CMP_EN BIT(4) +#define MCR20A_PHY_CTRL3_ASM_MSK BIT(2) +#define MCR20A_PHY_CTRL3_PB_ERR_MSK BIT(1) +#define MCR20A_PHY_CTRL3_WAKE_MSK BIT(0) + +#define MCR20A_RX_FRM_LENGTH_MASK (0x7f) + +#define MCR20A_PHY_CTRL4_TRCV_MSK BIT(7) +#define MCR20A_PHY_CTRL4_TC3TMOUT BIT(6) +#define MCR20A_PHY_CTRL4_PANCORDNTR0 BIT(5) +#define MCR20A_PHY_CTRL4_CCATYPE_MASK (0x18) +#define MCR20A_PHY_CTRL4_CCATYPE_SHIFT (3) +#define MCR20A_PHY_CTRL4_TMRLOAD BIT(2) +#define MCR20A_PHY_CTRL4_PROMISCUOUS BIT(1) +#define MCR20A_PHY_CTRL4_TC2PRIME_EN BIT(0) + +#define MCR20A_SRC_CTRL_INDEX_MASK (0xf0) +#define MCR20A_SRC_CTRL_INDEX_SHIFT (4) +#define MCR20A_SRC_CTRL_ACK_FRM_PND BIT(3) +#define MCR20A_SRC_CTRL_SRCADDR_EN BIT(2) +#define MCR20A_SRC_CTRL_INDEX_EN BIT(1) +#define MCR20A_SRC_CTRL_INDEX_DISABLE BIT(0) + +#define MCR20A_PLL_INT0_VAL_MASK (0x1f) +#define MCR20A_PLL_INT0_VAL_SHIFT (0) + +#define MCR20A_PA_PWR_VAL_MASK (0x1f) +#define MCR20A_PA_PWR_VAL_SHIFT (0) + +#define MCR20A_SEQ_STATE_MASK (0x1f) + +#define MCR20A_ASM_CTRL1_CLEAR BIT(7) +#define MCR20A_ASM_CTRL1_START BIT(6) +#define MCR20A_ASM_CTRL1_SELFTST BIT(5) +#define MCR20A_ASM_CTRL1_CTR BIT(4) +#define MCR20A_ASM_CTRL1_CBC BIT(3) +#define MCR20A_ASM_CTRL1_AES BIT(2) +#define MCR20A_ASM_CTRL1_LOAD_MAC BIT(1) + +#define MCR20A_ASM_CTRL2_DATA_REG_TYPE_SELECT_MASK (0x7) +#define MCR20A_ASM_CTRL2_DATA_REG_TYPE_SELECT_SHIFT (5) +#define MCR20A_ASM_CTRL2_TSTPAS BIT(1) + +#define MCR20A_CLK_OUT_EXTEND BIT(7) +#define MCR20A_CLK_OUT_HIZ BIT(6) +#define MCR20A_CLK_OUT_SR BIT(5) +#define MCR20A_CLK_OUT_DS BIT(4) +#define MCR20A_CLK_OUT_EN BIT(3) +#define MCR20A_CLK_OUT_DIV_MASK (0x07) +#define MCR20A_CLK_OUT_DIV_SHIFT (0) + +#define MCR20A_PWR_MODES_XTAL_READY BIT(5) +#define MCR20A_PWR_MODES_XTALEN BIT(4) +#define MCR20A_PWR_MODES_ASM_CLK_EN BIT(3) +#define MCR20A_PWR_MODES_AUTODOZE BIT(1) +#define MCR20A_PWR_MODES_PMC_MODE BIT(0) + +#define MCR20A_PART_ID (0x00) +#define MCR20A_XTAL_TRIM (0x01) +#define MCR20A_PMC_LP_TRIM (0x02) +#define MCR20A_MACPANID0_LSB (0x03) +#define MCR20A_MACPANID0_MSB (0x04) +#define MCR20A_MACSHORTADDRS0_LSB (0x05) +#define MCR20A_MACSHORTADDRS0_MSB (0x06) +#define MCR20A_MACLONGADDRS0_0 (0x07) +#define MCR20A_MACLONGADDRS0_1 (0x08) +#define MCR20A_MACLONGADDRS0_2 (0x09) +#define MCR20A_MACLONGADDRS0_3 (0x0a) +#define MCR20A_MACLONGADDRS0_4 (0x0b) +#define MCR20A_MACLONGADDRS0_5 (0x0c) +#define MCR20A_MACLONGADDRS0_6 (0x0d) +#define MCR20A_MACLONGADDRS0_7 (0x0e) +#define MCR20A_RX_FRAME_FILTER (0x0f) +#define MCR20A_PLL_INT1 (0x10) +#define MCR20A_PLL_FRAC1_LSB (0x11) +#define MCR20A_PLL_FRAC1_MSB (0x12) +#define MCR20A_MACPANID1_LSB (0x13) +#define MCR20A_MACPANID1_MSB (0x14) +#define MCR20A_MACSHORTADDRS1_LSB (0x15) +#define MCR20A_MACSHORTADDRS1_MSB (0x16) +#define MCR20A_MACLONGADDRS1_0 (0x17) +#define MCR20A_MACLONGADDRS1_1 (0x18) +#define MCR20A_MACLONGADDRS1_2 (0x19) +#define MCR20A_MACLONGADDRS1_3 (0x1a) +#define MCR20A_MACLONGADDRS1_4 (0x1b) +#define MCR20A_MACLONGADDRS1_5 (0x1c) +#define MCR20A_MACLONGADDRS1_6 (0x1d) +#define MCR20A_MACLONGADDRS1_7 (0x1e) +#define MCR20A_DUAL_PAN_CTRL (0x1f) +#define MCR20A_DUAL_PAN_DWELL (0x20) +#define MCR20A_DUAL_PAN_STS (0x21) +#define MCR20A_CCA1_THRESH (0x22) +#define MCR20A_CCA1_ED_OFFSET_COMP (0x23) +#define MCR20A_LQI_OFFSET_COMP (0x24) +#define MCR20A_CCA_CTRL (0x25) +#define MCR20A_CCA2_CORR_PEAKS (0x26) +#define MCR20A_CCA2_THRESH (0x27) +#define MCR20A_TMR_PRESCALE (0x28) +/* ---------------- (0x29) */ +#define MCR20A_GPIO_DATA (0x2a) +#define MCR20A_GPIO_DIR (0x2b) +#define MCR20A_GPIO_PUL_EN (0x2c) +#define MCR20A_GPIO_SEL (0x2d) +#define MCR20A_GPIO_DS (0x2e) +/* ---------------- (0x2f) */ +#define MCR20A_ANT_PAD_CTRL (0x30) +#define MCR20A_MISC_PAD_CTRL (0x31) +#define MCR20A_BSM_CTRL (0x32) +/* ---------------- (0x33) */ +#define MCR20A_RNG (0x34) +#define MCR20A_RX_BYTE_COUNT (0x35) +#define MCR20A_RX_WTR_MARK (0x36) +#define MCR20A_SOFT_RESET (0x37) +#define MCR20A_TXDELAY (0x38) +#define MCR20A_ACKDELAY (0x39) +#define MCR20A_SEQ_MGR_CTRL (0x3a) +#define MCR20A_SEQ_MGR_STS (0x3b) +#define MCR20A_SEQ_T_STS (0x3c) +#define MCR20A_ABORT_STS (0x3d) +#define MCR20A_CCCA_BUSY_CNT (0x3e) +#define MCR20A_SRC_ADDR_CHECKSUM1 (0x3f) +#define MCR20A_SRC_ADDR_CHECKSUM2 (0x40) +#define MCR20A_SRC_TBL_VALID1 (0x41) +#define MCR20A_SRC_TBL_VALID2 (0x42) +#define MCR20A_FILTERFAIL_CODE1 (0x43) +#define MCR20A_FILTERFAIL_CODE2 (0x44) +#define MCR20A_SLOT_PRELOAD (0x45) +/* ---------------- (0x46) */ +#define MCR20A_CORR_VT (0x47) +#define MCR20A_SYNC_CTRL (0x48) +#define MCR20A_PN_LSB_0 (0x49) +#define MCR20A_PN_LSB_1 (0x4a) +#define MCR20A_PN_MSB_0 (0x4b) +#define MCR20A_PN_MSB_1 (0x4c) +#define MCR20A_CORR_NVAL (0x4d) +#define MCR20A_TX_MODE_CTRL (0x4e) +#define MCR20A_SNF_THR (0x4f) +#define MCR20A_FAD_THR (0x50) +#define MCR20A_ANT_AGC_CTRL (0x51) +#define MCR20A_AGC_THR1 (0x52) +#define MCR20A_AGC_THR2 (0x53) +#define MCR20A_AGC_HYS (0x54) +#define MCR20A_AFC (0x55) +#define MCR20A_LPPS_CTRL (0x56) +/* ---------------- (0x57) */ +#define MCR20A_PHY_STS (0x58) +#define MCR20A_RX_MAX_CORR (0x59) +#define MCR20A_RX_MAX_PREAMBLE (0x5a) +#define MCR20A_RSSI (0x5b) +/* ---------------- (0x5c) */ +/* ---------------- (0x5d) */ +#define MCR20A_PLL_DIG_CTRL (0x5e) +#define MCR20A_VCO_CAL (0x5f) +#define MCR20A_VCO_BEST_DIFF (0x60) +#define MCR20A_VCO_BIAS (0x61) +#define MCR20A_KMOD_CTRL (0x62) +#define MCR20A_KMOD_CAL (0x63) +#define MCR20A_PA_CAL (0x64) +#define MCR20A_PA_PWRCAL (0x65) +#define MCR20A_ATT_RSSI1 (0x66) +#define MCR20A_ATT_RSSI2 (0x67) +#define MCR20A_RSSI_OFFSET (0x68) +#define MCR20A_RSSI_SLOPE (0x69) +#define MCR20A_RSSI_CAL1 (0x6a) +#define MCR20A_RSSI_CAL2 (0x6b) +/* ---------------- (0x6c) */ +/* ---------------- (0x6d) */ +#define MCR20A_XTAL_CTRL (0x6e) +#define MCR20A_XTAL_COMP_MIN (0x6f) +#define MCR20A_XTAL_COMP_MAX (0x70) +#define MCR20A_XTAL_GM (0x71) +/* ---------------- (0x72) */ +/* ---------------- (0x73) */ +#define MCR20A_LNA_TUNE (0x74) +#define MCR20A_LNA_AGCGAIN (0x75) +/* ---------------- (0x76) */ +/* ---------------- (0x77) */ +#define MCR20A_CHF_PMA_GAIN (0x78) +#define MCR20A_CHF_IBUF (0x79) +#define MCR20A_CHF_QBUF (0x7a) +#define MCR20A_CHF_IRIN (0x7b) +#define MCR20A_CHF_QRIN (0x7c) +#define MCR20A_CHF_IL (0x7d) +#define MCR20A_CHF_QL (0x7e) +#define MCR20A_CHF_CC1 (0x7f) +#define MCR20A_CHF_CCL (0x80) +#define MCR20A_CHF_CC2 (0x81) +#define MCR20A_CHF_IROUT (0x82) +#define MCR20A_CHF_QROUT (0x83) +/* ---------------- (0x84) */ +/* ---------------- (0x85) */ +#define MCR20A_RSSI_CTRL (0x86) +/* ---------------- (0x87) */ +/* ---------------- (0x88) */ +#define MCR20A_PA_BIAS (0x89) +#define MCR20A_PA_TUNING (0x8a) +/* ---------------- (0x8b) */ +/* ---------------- (0x8c) */ +#define MCR20A_PMC_HP_TRIM (0x8d) +#define MCR20A_VREGA_TRIM (0x8e) +/* ---------------- (0x8f) */ +/* ---------------- (0x90) */ +#define MCR20A_VCO_CTRL1 (0x91) +#define MCR20A_VCO_CTRL2 (0x92) +/* ---------------- (0x93) */ +/* ---------------- (0x94) */ +#define MCR20A_ANA_SPARE_OUT1 (0x95) +#define MCR20A_ANA_SPARE_OUT2 (0x96) +#define MCR20A_ANA_SPARE_IN (0x97) +#define MCR20A_MISCELLANEOUS (0x98) +/* ---------------- (0x99) */ +#define MCR20A_SEQ_MGR_OVRD0 (0x9a) +#define MCR20A_SEQ_MGR_OVRD1 (0x9b) +#define MCR20A_SEQ_MGR_OVRD2 (0x9c) +#define MCR20A_SEQ_MGR_OVRD3 (0x9d) +#define MCR20A_SEQ_MGR_OVRD4 (0x9e) +#define MCR20A_SEQ_MGR_OVRD5 (0x9f) +#define MCR20A_SEQ_MGR_OVRD6 (0xa0) +#define MCR20A_SEQ_MGR_OVRD7 (0xa1) +/* ---------------- (0xa2) */ +#define MCR20A_TESTMODE_CTRL (0xa3) +#define MCR20A_DTM_CTRL1 (0xa4) +#define MCR20A_DTM_CTRL2 (0xa5) +#define MCR20A_ATM_CTRL1 (0xa6) +#define MCR20A_ATM_CTRL2 (0xa7) +#define MCR20A_ATM_CTRL3 (0xa8) +/* ---------------- (0xa9) */ +#define MCR20A_LIM_FE_TEST_CTRL (0xaa) +#define MCR20A_CHF_TEST_CTRL (0xab) +#define MCR20A_VCO_TEST_CTRL (0xac) +#define MCR20A_PLL_TEST_CTRL (0xad) +#define MCR20A_PA_TEST_CTRL (0xae) +#define MCR20A_PMC_TEST_CTRL (0xaf) + +#define MCR20A_SCAN_DTM_PROTECT_1 (0xfe) +#define MCR20A_SCAN_DTM_PROTECT_0 (0xff) + +#define MCR20A_RX_FRAME_FILTER_FRM_VER_MASK (0xc0) +#define MCR20A_RX_FRAME_FILTER_FRM_VER_SHIFT (6) +#define MCR20A_RX_FRAME_FILTER_ACTIVE_PROMISCUOUS BIT(5) +#define MCR20A_RX_FRAME_FILTER_NS_FT BIT(4) +#define MCR20A_RX_FRAME_FILTER_CMD_FT BIT(3) +#define MCR20A_RX_FRAME_FILTER_ACK_FT BIT(2) +#define MCR20A_RX_FRAME_FILTER_DATA_FT BIT(1) +#define MCR20A_RX_FRAME_FILTER_BEACON_FT BIT(0) + +#define MCR20A_PLL_INT1_MASK (0x1f) + +#define MCR20A_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MASK (0xf0) +#define MCR20A_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_SHIFT (4) +#define MCR20A_DUAL_PAN_CTRL_CURRENT_NETWORK BIT(3) +#define MCR20A_DUAL_PAN_CTRL_PANCORDNTR1 BIT(2) +#define MCR20A_DUAL_PAN_CTRL_DUAL_PAN_AUTO BIT(1) +#define MCR20A_DUAL_PAN_CTRL_ACTIVE_NETWORK BIT(0) + +#define MCR20A_DUAL_PAN_STS_RECD_ON_PAN1 BIT(7) +#define MCR20A_DUAL_PAN_STS_RECD_ON_PAN0 BIT(6) +#define MCR20A_DUAL_PAN_STS_DUAL_PAN_REMAIN_MASK (0x3f) + +#define MCR20A_CCA_CTRL_AGC_FRZ_EN BIT(6) +#define MCR20A_CCA_CTRL_CONT_RSSI_EN BIT(5) +#define MCR20A_CCA_CTRL_QI_RSSI_NOT_CORR BIT(4) +#define MCR20A_CCA_CTRL_CCA3_AND_NOT_OR BIT(3) +#define MCR20A_CCA_CTRL_OWER_COMP_EN_LQI BIT(2) +#define MCR20A_CCA_CTRL_OWER_COMP_EN_ED BIT(1) +#define MCR20A_CCA_CTRL_OWER_COMP_EN_CCA1 BIT(0) + +#define MCR20A_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH_MASK (0x70) +#define MCR20A_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH_SHIFT (4) +#define MCR20A_CCA2_CORR_PEAKS_CCA2_NUM_CORR_PEAKS_MASK (0x0f) + +#define MCR20A_TMR_PRESCALE_VAL_MASK (0x7) +#define MCR20A_TMR_PRESCALE_VAL_SHIFT (0) + +#define MCR20A_TIMEBASE_500000HZ (2) +#define MCR20A_TIMEBASE_250000HZ (3) +#define MCR20A_TIMEBASE_125000HZ (4) +#define MCR20A_TIMEBASE_62500HZ (5) +#define MCR20A_TIMEBASE_31250HZ (6) +#define MCR20A_TIMEBASE_15625HZ (7) + +#define MCR20A_GPIO_DATA8 BIT(7) +#define MCR20A_GPIO_DATA7 BIT(6) +#define MCR20A_GPIO_DATA6 BIT(5) +#define MCR20A_GPIO_DATA5 BIT(4) +#define MCR20A_GPIO_DATA4 BIT(3) +#define MCR20A_GPIO_DATA3 BIT(2) +#define MCR20A_GPIO_DATA2 BIT(1) +#define MCR20A_GPIO_DATA1 BIT(0) + +#define MCR20A_GPIO_DIR8 BIT(7) +#define MCR20A_GPIO_DIR7 BIT(6) +#define MCR20A_GPIO_DIR6 BIT(5) +#define MCR20A_GPIO_DIR5 BIT(4) +#define MCR20A_GPIO_DIR4 BIT(3) +#define MCR20A_GPIO_DIR3 BIT(2) +#define MCR20A_GPIO_DIR2 BIT(1) +#define MCR20A_GPIO_DIR1 BIT(0) + +#define MCR20A_GPIO_PUL_EN8 BIT(7) +#define MCR20A_GPIO_PUL_EN7 BIT(6) +#define MCR20A_GPIO_PUL_EN6 BIT(5) +#define MCR20A_GPIO_PUL_EN5 BIT(4) +#define MCR20A_GPIO_PUL_EN4 BIT(3) +#define MCR20A_GPIO_PUL_EN3 BIT(2) +#define MCR20A_GPIO_PUL_EN2 BIT(1) +#define MCR20A_GPIO_PUL_EN1 BIT(0) + +#define MCR20A_GPIO_PUL_SEL8 BIT(7) +#define MCR20A_GPIO_PUL_SEL7 BIT(6) +#define MCR20A_GPIO_PUL_SEL6 BIT(5) +#define MCR20A_GPIO_PUL_SEL5 BIT(4) +#define MCR20A_GPIO_PUL_SEL4 BIT(3) +#define MCR20A_GPIO_PUL_SEL3 BIT(2) +#define MCR20A_GPIO_PUL_SEL2 BIT(1) +#define MCR20A_GPIO_PUL_SEL1 BIT(0) + +#define MCR20A_GPIO_DS8 BIT(7) +#define MCR20A_GPIO_DS7 BIT(6) +#define MCR20A_GPIO_DS6 BIT(5) +#define MCR20A_GPIO_DS5 BIT(4) +#define MCR20A_GPIO_DS4 BIT(3) +#define MCR20A_GPIO_DS3 BIT(2) +#define MCR20A_GPIO_DS2 BIT(1) +#define MCR20A_GPIO_DS1 BIT(0) + +#define MCR20A_ANT_PAD_CTRL_ANTX_POL3 BIT(7) +#define MCR20A_ANT_PAD_CTRL_ANTX_POL2 BIT(6) +#define MCR20A_ANT_PAD_CTRL_ANTX_POL1 BIT(5) +#define MCR20A_ANT_PAD_CTRL_ANTX_POL0 BIT(4) +#define MCR20A_ANT_PAD_CTRL_ANTX_CTRLMODE BIT(3) +#define MCR20A_ANT_PAD_CTRL_ANTX_HZ BIT(2) +#define MCR20A_ANT_PAD_CTRL_ANTX_EN_MASK (0x03) +#define MCR20A_ANT_PAD_CTRL_ANTX_EN_SHIFT (0) + +#define MCR20A_MISC_PAD_CTRL_MISO_HIZ_EN BIT(3) +#define MCR20A_MISC_PAD_CTRL_IRQ_B_OD BIT(2) +#define MCR20A_MISC_PAD_CTRL_NON_GPIO_DS BIT(1) +#define MCR20A_MISC_PAD_CTRL_ANTX_CURR BIT(0) + +#define MCR20A_ANT_AGC_CTRL_SNF_EN BIT(7) +#define MCR20A_ANT_AGC_CTRL_AGC_EN BIT(6) +#define MCR20A_ANT_AGC_CTRL_AGC_LEVEL_MASK (0x30) +#define MCR20A_ANT_AGC_CTRL_AGC_LEVEL_SHIFT (4) +#define MCR20A_ANT_AGC_CTRL_ANTX BIT(1) +#define MCR20A_ANT_AGC_CTRL_AD_EN BIT(0) + +#define MCR20A_LPPS_BUFMIX_EN BIT(4) +#define MCR20A_LPPS_LIM_EN BIT(3) +#define MCR20A_LPPS_RSSI_EN BIT(2) +#define MCR20A_LPPS_LNA_EN BIT(1) +#define MCR20A_LPPS_CTRL_LPPS_EN BIT(0) + +/* Undocumented part copied from MCR20reg.h */ +#define MCR20A_SOFT_RESET_SOG_RST BIT(7) +#define MCR20A_SOFT_RESET_REGS_RST BIT(4) +#define MCR20A_SOFT_RESET_PLL_RST BIT(3) +#define MCR20A_SOFT_RESET_TX_RST BIT(2) +#define MCR20A_SOFT_RESET_RX_RST BIT(1) +#define MCR20A_SOFT_RESET_SEQ_MGR_RST BIT(0) + +#define MCR20A_SEQ_MGR_CTRL_SEQ_STATE_CTRL_MASK (0x3) +#define MCR20A_SEQ_MGR_CTRL_SEQ_STATE_CTRL_SHIFT (6) +#define MCR20A_SEQ_MGR_CTRL_NO_RX_RECYCLE BIT(5) +#define MCR20A_SEQ_MGR_CTRL_LATCH_PREAMBLE BIT(4) +#define MCR20A_SEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH BIT(3) +#define MCR20A_SEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT BIT(2) +#define MCR20A_SEQ_MGR_CTRL_PSM_LOCK_DIS BIT(1) +#define MCR20A_SEQ_MGR_CTRL_PLL_ABORT_OVRD BIT(0) + +#define MCR20A_SEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED BIT(7) +#define MCR20A_SEQ_MGR_STS_RX_MODE BIT(6) +#define MCR20A_SEQ_MGR_STS_RX_TIMEOUT_PENDING BIT(5) +#define MCR20A_SEQ_MGR_STS_NEW_SEQ_INHIBIT BIT(4) +#define MCR20A_SEQ_MGR_STS_SEQ_IDLE BIT(3) +#define MCR20A_SEQ_MGR_STS_XCVSEQ_ACTUAL_MASK (0x7) +#define MCR20A_SEQ_MGR_STS_XCVSEQ_ACTUAL_SHIFT (0) + +#define MCR20A_ABORT_STS_PLL_ABORTED BIT(2) +#define MCR20A_ABORT_STS_TC3_ABORTED BIT(1) +#define MCR20A_ABORT_STS_SW_ABORTED BIT(0) + +#define MCR20A_PHY_STS_PLL_UNLOCK BIT(7) +#define MCR20A_PHY_STS_PLL_LOCK_ERR BIT(6) +#define MCR20A_PHY_STS_PLL_LOCK BIT(5) +#define MCR20A_PHY_STS_CRCVALID BIT(3) +#define MCR20A_PHY_STS_FILTERFAIL_FLAG_SEL BIT(2) +#define MCR20A_PHY_STS_SFD_DET BIT(1) +#define MCR20A_PHY_STS_PREAMBLE_DET BIT(0) + +#define MCR20A_TESTMODE_CTRL_HOT_ANT BIT(4) +#define MCR20A_TESTMODE_CTRL_IDEAL_RSSI_EN BIT(3) +#define MCR20A_TESTMODE_CTRL_IDEAL_PFC_EN BIT(2) +#define MCR20A_TESTMODE_CTRL_CONTINUOUS_EN BIT(1) +#define MCR20A_TESTMODE_CTRL_FPGA_EN BIT(0) + +#define MCR20A_DTM_CTRL1_ATM_LOCKED BIT(7) +#define MCR20A_DTM_CTRL1_DTM_EN BIT(6) +#define MCR20A_DTM_CTRL1_PAGE5 BIT(5) +#define MCR20A_DTM_CTRL1_PAGE4 BIT(4) +#define MCR20A_DTM_CTRL1_PAGE3 BIT(3) +#define MCR20A_DTM_CTRL1_PAGE2 BIT(2) +#define MCR20A_DTM_CTRL1_PAGE1 BIT(1) +#define MCR20A_DTM_CTRL1_PAGE0 BIT(0) + +#define MCR20A_TX_MODE_CTRL_TX_INV BIT(4) +#define MCR20A_TX_MODE_CTRL_BT_EN BIT(3) +#define MCR20A_TX_MODE_CTRL_DTS2 BIT(2) +#define MCR20A_TX_MODE_CTRL_DTS1 BIT(1) +#define MCR20A_TX_MODE_CTRL_DTS0 BIT(0) +#define MCR20A_TX_MODE_CTRL_DTS_MASK (7) + +#endif /* __IEEE802154_MCR20A_REGS_H__ */ |