summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJohann Fischer <j.fischer@phytec.de>2017-01-09 16:54:28 +0100
committerJukka Rissanen <jukka.rissanen@linux.intel.com>2017-01-27 12:35:51 +0200
commitfa8d9c9d1056e9d77ffa494ee4ab00bdcdfc7bc4 (patch)
tree1f9c3dee202d8bf5513eb5e051b1542eb4adbce5 /drivers
parentd4e5113461ccc97044029ead9b7a014aa4cc943f (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/Kconfig117
-rw-r--r--drivers/ieee802154/Makefile2
-rw-r--r--drivers/ieee802154/ieee802154_mcr20a.c1459
-rw-r--r--drivers/ieee802154/ieee802154_mcr20a.h184
-rw-r--r--drivers/ieee802154/ieee802154_mcr20a_regs.h590
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__ */