drivers/ieee802154: Switch MCR20A driver to new SPI API

And adding support for GPIO CS as well.
It looks like the driver could benefit from centralizing all SPI access
into a unique function, the protocol does not seem too convoluted to do
so, like CC2520 or CC1200.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Tomasz Bursztyka 2018-03-05 10:51:26 +01:00 committed by Carles Cufí
commit b62b12eef8
3 changed files with 279 additions and 236 deletions

View file

@ -9,7 +9,6 @@
menuconfig IEEE802154_MCR20A menuconfig IEEE802154_MCR20A
bool "NXP MCR20A Driver support" bool "NXP MCR20A Driver support"
depends on NETWORKING && SPI depends on NETWORKING && SPI
select SPI_LEGACY_API
default n default n
if IEEE802154_MCR20A if IEEE802154_MCR20A
@ -42,6 +41,29 @@ config IEEE802154_MCR20A_SPI_SLAVE
This option sets the SPI slave number SPI controller has to switch This option sets the SPI slave number SPI controller has to switch
to when dealing with MCR20A chip. to when dealing with MCR20A chip.
config IEEE802154_MCR20A_GPIO_SPI_CS
bool "Manage SPI CS through a GPIO pin"
default n
help
This option is useful if one needs to manage SPI CS through a GPIO
pin to by-pass the SPI controller's CS logic.
config IEEE802154_MCR20A_GPIO_SPI_CS_DRV_NAME
string "GPIO driver's name to use to drive SPI CS through"
default ""
depends on IEEE802154_MCR20A_GPIO_SPI_CS
help
This option is mandatory to set which GPIO controller to use in order
to actually emulate the SPI CS.
config IEEE802154_MCR20A_GPIO_SPI_CS_PIN
int "GPIO PIN to use to drive SPI CS through"
default 0
depends on IEEE802154_MCR20A_GPIO_SPI_CS
help
This option is mandatory to set which GPIO pin to use in order
to actually emulate the SPI CS.
config MCR20A_GPIO_IRQ_B_NAME config MCR20A_GPIO_IRQ_B_NAME
string "GPIO device used for IRQ_B output of MCR20A" string "GPIO device used for IRQ_B output of MCR20A"
default GPIO_MCUX_PORTB_NAME default GPIO_MCUX_PORTB_NAME

View file

@ -147,128 +147,146 @@ static const u16_t pll_frac_lt[16] = {
#define _usleep(usec) k_busy_wait(usec) #define _usleep(usec) k_busy_wait(usec)
/* Read direct (dreg is true) or indirect register (dreg is false) */ /* Read direct (dreg is true) or indirect register (dreg is false) */
u8_t _mcr20a_read_reg(struct mcr20a_spi *spi, bool dreg, u8_t addr) u8_t _mcr20a_read_reg(struct mcr20a_context *dev, bool dreg, u8_t addr)
{ {
u8_t cmd_buf[3] = {
dreg ? (MCR20A_REG_READ | addr) :
(MCR20A_IAR_INDEX | MCR20A_REG_WRITE),
dreg ? 0 : (addr | MCR20A_REG_READ),
0
};
u8_t len = dreg ? 2 : 3; u8_t len = dreg ? 2 : 3;
const struct spi_buf buf = {
.buf = cmd_buf,
.len = len
};
const struct spi_buf_set tx = {
.buffers = &buf,
.count = 1
};
const struct spi_buf_set rx = {
.buffers = &buf,
.count = 1
};
k_sem_take(&spi->spi_sem, K_FOREVER); k_sem_take(&dev->spi_sem, K_FOREVER);
spi->cmd_buf[0] = dreg ? (MCR20A_REG_READ | addr) : if (spi_transceive(dev->spi, &dev->spi_cfg, &tx, &rx) == 0) {
(MCR20A_IAR_INDEX | MCR20A_REG_WRITE); k_sem_give(&dev->spi_sem);
spi->cmd_buf[1] = dreg ? 0 : (addr | MCR20A_REG_READ); return cmd_buf[len - 1];
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) {
k_sem_give(&spi->spi_sem);
return spi->cmd_buf[len - 1];
} }
SYS_LOG_ERR("Failed"); SYS_LOG_ERR("Failed");
k_sem_give(&spi->spi_sem); k_sem_give(&dev->spi_sem);
return 0; return 0;
} }
/* Write direct (dreg is true) or indirect register (dreg is false) */ /* Write direct (dreg is true) or indirect register (dreg is false) */
bool _mcr20a_write_reg(struct mcr20a_spi *spi, bool dreg, u8_t addr, bool _mcr20a_write_reg(struct mcr20a_context *dev, bool dreg, u8_t addr,
u8_t value) u8_t value)
{ {
u8_t len = dreg ? 2 : 3; u8_t cmd_buf[3] = {
dreg ? (MCR20A_REG_WRITE | addr) :
(MCR20A_IAR_INDEX | MCR20A_REG_WRITE),
dreg ? value : (addr | MCR20A_REG_WRITE),
dreg ? 0 : value
};
const struct spi_buf buf = {
.buf = cmd_buf,
.len = dreg ? 2 : 3
};
const struct spi_buf_set tx = {
.buffers = &buf,
.count = 1
};
bool retval; bool retval;
k_sem_take(&spi->spi_sem, K_FOREVER); k_sem_take(&dev->spi_sem, K_FOREVER);
spi->cmd_buf[0] = dreg ? (MCR20A_REG_WRITE | addr) : retval = (spi_write(dev->spi, &dev->spi_cfg, &tx) == 0);
(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); k_sem_give(&dev->spi_sem);
retval = (spi_write(spi->dev, spi->cmd_buf, len) == 0);
k_sem_give(&spi->spi_sem);
return retval; return retval;
} }
/* Write multiple bytes to direct or indirect register */ /* Write multiple bytes to direct or indirect register */
bool _mcr20a_write_burst(struct mcr20a_spi *spi, bool dreg, u16_t addr, bool _mcr20a_write_burst(struct mcr20a_context *dev, bool dreg, u16_t addr,
u8_t *data_buf, u8_t len) u8_t *data_buf, u8_t len)
{ {
u8_t cmd_buf[2] = {
dreg ? MCR20A_REG_WRITE | addr :
MCR20A_IAR_INDEX | MCR20A_REG_WRITE,
dreg ? 0 : addr | MCR20A_REG_WRITE
};
struct spi_buf bufs[2] = {
{
.buf = cmd_buf,
.len = dreg ? 1 : 2
},
{
.buf = data_buf,
.len = len
}
};
const struct spi_buf_set tx = {
.buffers = bufs,
.count = 2
};
bool retval; bool retval;
if ((len + 2) > sizeof(spi->cmd_buf)) { k_sem_take(&dev->spi_sem, K_FOREVER);
SYS_LOG_ERR("cmd buffer too small");
return false;
}
k_sem_take(&spi->spi_sem, K_FOREVER); retval = (spi_write(dev->spi, &dev->spi_cfg, &tx) == 0);
if (dreg) { k_sem_give(&dev->spi_sem);
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);
retval = (spi_write(spi->dev, spi->cmd_buf, len) == 0);
k_sem_give(&spi->spi_sem);
return retval; return retval;
} }
/* Read multiple bytes from direct or indirect register */ /* Read multiple bytes from direct or indirect register */
bool _mcr20a_read_burst(struct mcr20a_spi *spi, bool dreg, u16_t addr, bool _mcr20a_read_burst(struct mcr20a_context *dev, bool dreg, u16_t addr,
u8_t *data_buf, u8_t len) u8_t *data_buf, u8_t len)
{ {
if ((len + 2) > sizeof(spi->cmd_buf)) { u8_t cmd_buf[2] = {
SYS_LOG_ERR("cmd buffer too small"); dreg ? MCR20A_REG_READ | addr :
return false; MCR20A_IAR_INDEX | MCR20A_REG_WRITE,
} dreg ? 0 : addr | MCR20A_REG_READ
};
struct spi_buf bufs[2] = {
{
.buf = cmd_buf,
.len = dreg ? 1 : 2
},
{
.buf = data_buf,
.len = len
}
};
const struct spi_buf_set tx = {
.buffers = bufs,
.count = 1
};
const struct spi_buf_set rx = {
.buffers = bufs,
.count = 2
};
bool retval;
k_sem_take(&spi->spi_sem, K_FOREVER); k_sem_take(&dev->spi_sem, K_FOREVER);
if (dreg) { retval = (spi_transceive(dev->spi, &dev->spi_cfg, &tx, &rx) == 0);
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); k_sem_give(&dev->spi_sem);
if (spi_transceive(spi->dev, spi->cmd_buf, len, return retval;
spi->cmd_buf, len) != 0) {
k_sem_give(&spi->spi_sem);
return false;
}
if (dreg) {
memcpy(data_buf, &spi->cmd_buf[1], len - 1);
} else {
memcpy(data_buf, &spi->cmd_buf[2], len - 2);
}
k_sem_give(&spi->spi_sem);
return true;
} }
/* Mask (msk is true) or unmask all interrupts from asserting IRQ_B */ /* Mask (msk is true) or unmask all interrupts from asserting IRQ_B */
static bool mcr20a_mask_irqb(struct mcr20a_context *dev, bool msk) static bool mcr20a_mask_irqb(struct mcr20a_context *dev, bool msk)
{ {
u8_t ctrl4 = read_reg_phy_ctrl4(&dev->spi); u8_t ctrl4 = read_reg_phy_ctrl4(dev);
if (msk) { if (msk) {
ctrl4 |= MCR20A_PHY_CTRL4_TRCV_MSK; ctrl4 |= MCR20A_PHY_CTRL4_TRCV_MSK;
@ -276,7 +294,7 @@ static bool mcr20a_mask_irqb(struct mcr20a_context *dev, bool msk)
ctrl4 &= ~MCR20A_PHY_CTRL4_TRCV_MSK; ctrl4 &= ~MCR20A_PHY_CTRL4_TRCV_MSK;
} }
return write_reg_phy_ctrl4(&dev->spi, ctrl4); return write_reg_phy_ctrl4(dev, ctrl4);
} }
/** Set an timeout value for the given compare register */ /** Set an timeout value for the given compare register */
@ -288,7 +306,7 @@ static int mcr20a_timer_set(struct mcr20a_context *mcr20a,
u32_t next; u32_t next;
bool retval; bool retval;
if (!read_burst_event_timer(&mcr20a->spi, (u8_t *)&now)) { if (!read_burst_event_timer(mcr20a, (u8_t *)&now)) {
goto error; goto error;
} }
@ -299,16 +317,16 @@ static int mcr20a_timer_set(struct mcr20a_context *mcr20a,
switch (cmp_reg) { switch (cmp_reg) {
case 1: case 1:
retval = write_burst_t1cmp(&mcr20a->spi, (u8_t *)&next); retval = write_burst_t1cmp(mcr20a, (u8_t *)&next);
break; break;
case 2: case 2:
retval = write_burst_t2cmp(&mcr20a->spi, (u8_t *)&next); retval = write_burst_t2cmp(mcr20a, (u8_t *)&next);
break; break;
case 3: case 3:
retval = write_burst_t3cmp(&mcr20a->spi, (u8_t *)&next); retval = write_burst_t3cmp(mcr20a, (u8_t *)&next);
break; break;
case 4: case 4:
retval = write_burst_t4cmp(&mcr20a->spi, (u8_t *)&next); retval = write_burst_t4cmp(mcr20a, (u8_t *)&next);
break; break;
default: default:
goto error; goto error;
@ -331,18 +349,18 @@ static int mcr20a_timer_init(struct device *dev, u8_t tb)
u8_t buf[3] = {0, 0, 0}; u8_t buf[3] = {0, 0, 0};
u8_t ctrl4; u8_t ctrl4;
if (!write_reg_tmr_prescale(&mcr20a->spi, if (!write_reg_tmr_prescale(mcr20a,
set_bits_tmr_prescale(tb))) { set_bits_tmr_prescale(tb))) {
goto error; goto error;
} }
if (!write_burst_t1cmp(&mcr20a->spi, buf)) { if (!write_burst_t1cmp(mcr20a, buf)) {
goto error; goto error;
} }
ctrl4 = read_reg_phy_ctrl4(&mcr20a->spi); ctrl4 = read_reg_phy_ctrl4(mcr20a);
ctrl4 |= MCR20A_PHY_CTRL4_TMRLOAD; ctrl4 |= MCR20A_PHY_CTRL4_TMRLOAD;
if (!write_reg_phy_ctrl4(&mcr20a->spi, ctrl4)) { if (!write_reg_phy_ctrl4(mcr20a, ctrl4)) {
goto error; goto error;
} }
@ -366,16 +384,16 @@ static int mcr20a_t4cmp_set(struct mcr20a_context *mcr20a,
} }
/* enable and clear irq for the timer 4 */ /* enable and clear irq for the timer 4 */
irqsts3 = read_reg_irqsts3(&mcr20a->spi); irqsts3 = read_reg_irqsts3(mcr20a);
irqsts3 &= ~MCR20A_IRQSTS3_TMR4MSK; irqsts3 &= ~MCR20A_IRQSTS3_TMR4MSK;
irqsts3 |= MCR20A_IRQSTS3_TMR4IRQ; irqsts3 |= MCR20A_IRQSTS3_TMR4IRQ;
if (!write_reg_irqsts3(&mcr20a->spi, irqsts3)) { if (!write_reg_irqsts3(mcr20a, irqsts3)) {
goto error; goto error;
} }
ctrl3 = read_reg_phy_ctrl3(&mcr20a->spi); ctrl3 = read_reg_phy_ctrl3(mcr20a);
ctrl3 |= MCR20A_PHY_CTRL3_TMR4CMP_EN; ctrl3 |= MCR20A_PHY_CTRL3_TMR4CMP_EN;
if (!write_reg_phy_ctrl3(&mcr20a->spi, ctrl3)) { if (!write_reg_phy_ctrl3(mcr20a, ctrl3)) {
goto error; goto error;
} }
@ -392,15 +410,15 @@ static int mcr20a_t4cmp_clear(struct mcr20a_context *mcr20a)
u8_t irqsts3; u8_t irqsts3;
u8_t ctrl3; u8_t ctrl3;
ctrl3 = read_reg_phy_ctrl3(&mcr20a->spi); ctrl3 = read_reg_phy_ctrl3(mcr20a);
ctrl3 &= ~MCR20A_PHY_CTRL3_TMR4CMP_EN; ctrl3 &= ~MCR20A_PHY_CTRL3_TMR4CMP_EN;
if (!write_reg_phy_ctrl3(&mcr20a->spi, ctrl3)) { if (!write_reg_phy_ctrl3(mcr20a, ctrl3)) {
goto error; goto error;
} }
irqsts3 = read_reg_irqsts3(&mcr20a->spi); irqsts3 = read_reg_irqsts3(mcr20a);
irqsts3 |= MCR20A_IRQSTS3_TMR4IRQ; irqsts3 |= MCR20A_IRQSTS3_TMR4IRQ;
if (!write_reg_irqsts3(&mcr20a->spi, irqsts3)) { if (!write_reg_irqsts3(mcr20a, irqsts3)) {
goto error; goto error;
} }
@ -417,7 +435,7 @@ static inline void _xcvseq_wait_until_idle(struct mcr20a_context *mcr20a)
u8_t retries = MCR20A_GET_SEQ_STATE_RETRIES; u8_t retries = MCR20A_GET_SEQ_STATE_RETRIES;
do { do {
state = read_reg_seq_state(&mcr20a->spi); state = read_reg_seq_state(mcr20a);
retries--; retries--;
} while ((state & MCR20A_SEQ_STATE_MASK) && retries); } while ((state & MCR20A_SEQ_STATE_MASK) && retries);
@ -431,7 +449,7 @@ static inline int mcr20a_abort_sequence(struct mcr20a_context *mcr20a,
{ {
u8_t ctrl1; u8_t ctrl1;
ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); ctrl1 = read_reg_phy_ctrl1(mcr20a);
SYS_LOG_DBG("CTRL1 0x%02x", ctrl1); SYS_LOG_DBG("CTRL1 0x%02x", ctrl1);
if (((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX) || if (((ctrl1 & MCR20A_PHY_CTRL1_XCVSEQ_MASK) == MCR20A_XCVSEQ_TX) ||
@ -443,14 +461,14 @@ static inline int mcr20a_abort_sequence(struct mcr20a_context *mcr20a,
/* Abort ongoing sequence */ /* Abort ongoing sequence */
ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK; ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK;
if (!write_reg_phy_ctrl1(&mcr20a->spi, ctrl1)) { if (!write_reg_phy_ctrl1(mcr20a, ctrl1)) {
return -1; return -1;
} }
_xcvseq_wait_until_idle(mcr20a); _xcvseq_wait_until_idle(mcr20a);
/* Clear relevant interrupt flags */ /* Clear relevant interrupt flags */
if (!write_reg_irqsts1(&mcr20a->spi, MCR20A_IRQSTS1_IRQ_MASK)) { if (!write_reg_irqsts1(mcr20a, MCR20A_IRQSTS1_IRQ_MASK)) {
return -1; return -1;
} }
@ -464,7 +482,7 @@ static inline int mcr20a_set_sequence(struct mcr20a_context *mcr20a,
u8_t ctrl1 = 0; u8_t ctrl1 = 0;
seq = set_bits_phy_ctrl1_xcvseq(seq); seq = set_bits_phy_ctrl1_xcvseq(seq);
ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); ctrl1 = read_reg_phy_ctrl1(mcr20a);
ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK; ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK;
if ((seq == MCR20A_XCVSEQ_TX_RX) && if ((seq == MCR20A_XCVSEQ_TX_RX) &&
@ -475,7 +493,7 @@ static inline int mcr20a_set_sequence(struct mcr20a_context *mcr20a,
} }
ctrl1 |= seq; ctrl1 |= seq;
if (!write_reg_phy_ctrl1(&mcr20a->spi, ctrl1)) { if (!write_reg_phy_ctrl1(mcr20a, ctrl1)) {
return -EIO; return -EIO;
} }
@ -515,30 +533,38 @@ static inline u8_t *get_mac(struct device *dev)
return mcr20a->mac_addr; return mcr20a->mac_addr;
} }
static inline bool read_rxfifo_content(struct mcr20a_spi *spi, static inline bool read_rxfifo_content(struct mcr20a_context *dev,
struct net_buf *buf, u8_t len) struct net_buf *buf, u8_t len)
{ {
u8_t data[1 + MCR20A_PSDU_LENGTH]; u8_t cmd = MCR20A_BUF_READ;
struct spi_buf bufs[2] = {
{
.buf = &cmd,
.len = 1
},
{
.buf = buf->data,
.len = len
}
};
const struct spi_buf_set tx = {
.buffers = bufs,
.count = 1
};
const struct spi_buf_set rx = {
.buffers = bufs,
.count = 2
};
bool retval;
if (len > MCR20A_PSDU_LENGTH) { k_sem_take(&dev->spi_sem, K_FOREVER);
SYS_LOG_ERR("Packet length too large");
return false; retval = (spi_transceive(dev->spi, &dev->spi_cfg, &tx, &rx) == 0);
if (retval) {
net_buf_add(buf, len);
} }
k_sem_take(&spi->spi_sem, K_FOREVER); k_sem_give(&dev->spi_sem);
data[0] = MCR20A_BUF_READ;
spi_slave_select(spi->dev, spi->slave);
if (spi_transceive(spi->dev, data, len+1, data, len+1) != 0) {
k_sem_give(&spi->spi_sem);
return false;
}
memcpy(buf->data, &data[1], len);
net_buf_add(buf, len);
k_sem_give(&spi->spi_sem);
return true; return true;
} }
@ -565,7 +591,7 @@ static inline void mcr20a_rx(struct mcr20a_context *mcr20a, u8_t len)
net_pkt_frag_insert(pkt, frag); net_pkt_frag_insert(pkt, frag);
if (!read_rxfifo_content(&mcr20a->spi, frag, pkt_len)) { if (!read_rxfifo_content(mcr20a, frag, pkt_len)) {
SYS_LOG_ERR("No content read"); SYS_LOG_ERR("No content read");
goto out; goto out;
} }
@ -575,7 +601,7 @@ static inline void mcr20a_rx(struct mcr20a_context *mcr20a, u8_t len)
goto out; goto out;
} }
net_pkt_set_ieee802154_lqi(pkt, read_reg_lqi_value(&mcr20a->spi)); net_pkt_set_ieee802154_lqi(pkt, read_reg_lqi_value(mcr20a));
net_pkt_set_ieee802154_rssi(pkt, mcr20a_get_rssi( net_pkt_set_ieee802154_rssi(pkt, mcr20a_get_rssi(
net_pkt_ieee802154_lqi(pkt))); net_pkt_ieee802154_lqi(pkt)));
@ -738,7 +764,7 @@ static void mcr20a_thread_main(void *arg)
} }
/* Read the register from IRQSTS1 until CTRL4 */ /* Read the register from IRQSTS1 until CTRL4 */
if (!read_burst_irqsts1_ctrl4(&mcr20a->spi, dregs)) { if (!read_burst_irqsts1_ctrl4(mcr20a, dregs)) {
SYS_LOG_ERR("Failed to read register"); SYS_LOG_ERR("Failed to read register");
goto unmask_irqb; goto unmask_irqb;
} }
@ -765,17 +791,17 @@ static void mcr20a_thread_main(void *arg)
if (set_new_seq) { if (set_new_seq) {
/* Reset sequence manager */ /* Reset sequence manager */
ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK; ctrl1 &= ~MCR20A_PHY_CTRL1_XCVSEQ_MASK;
if (!write_reg_phy_ctrl1(&mcr20a->spi, ctrl1)) { if (!write_reg_phy_ctrl1(mcr20a, ctrl1)) {
SYS_LOG_ERR("Failed to reset SEQ manager"); SYS_LOG_ERR("Failed to reset SEQ manager");
} }
_xcvseq_wait_until_idle(mcr20a); _xcvseq_wait_until_idle(mcr20a);
if (!write_burst_irqsts1_ctrl1(&mcr20a->spi, dregs)) { if (!write_burst_irqsts1_ctrl1(mcr20a, dregs)) {
SYS_LOG_ERR("Failed to write CTRL1"); SYS_LOG_ERR("Failed to write CTRL1");
} }
} else { } else {
if (!write_burst_irqsts1_irqsts3(&mcr20a->spi, dregs)) { if (!write_burst_irqsts1_irqsts3(mcr20a, dregs)) {
SYS_LOG_ERR("Failed to write IRQSTS3"); SYS_LOG_ERR("Failed to write IRQSTS3");
} }
} }
@ -835,11 +861,11 @@ static int mcr20a_set_cca_mode(struct device *dev, u8_t mode)
struct mcr20a_context *mcr20a = dev->driver_data; struct mcr20a_context *mcr20a = dev->driver_data;
u8_t ctrl4; u8_t ctrl4;
ctrl4 = read_reg_phy_ctrl4(&mcr20a->spi); ctrl4 = read_reg_phy_ctrl4(mcr20a);
ctrl4 &= ~MCR20A_PHY_CTRL4_CCATYPE_MASK; ctrl4 &= ~MCR20A_PHY_CTRL4_CCATYPE_MASK;
ctrl4 |= set_bits_phy_ctrl4_ccatype(mode); ctrl4 |= set_bits_phy_ctrl4_ccatype(mode);
if (!write_reg_phy_ctrl4(&mcr20a->spi, ctrl4)) { if (!write_reg_phy_ctrl4(mcr20a, ctrl4)) {
SYS_LOG_ERR("Failed"); SYS_LOG_ERR("Failed");
return -EIO; return -EIO;
} }
@ -922,7 +948,7 @@ static int mcr20a_set_channel(struct device *dev, u16_t channel)
goto out; goto out;
} }
ctrl1 = read_reg_phy_ctrl1(&mcr20a->spi); ctrl1 = read_reg_phy_ctrl1(mcr20a);
if (mcr20a_abort_sequence(mcr20a, true)) { if (mcr20a_abort_sequence(mcr20a, true)) {
SYS_LOG_ERR("Failed to reset XCV sequence"); SYS_LOG_ERR("Failed to reset XCV sequence");
@ -935,7 +961,7 @@ static int mcr20a_set_channel(struct device *dev, u16_t channel)
buf[1] = (u8_t)pll_frac_lt[channel]; buf[1] = (u8_t)pll_frac_lt[channel];
buf[2] = (u8_t)(pll_frac_lt[channel] >> 8); buf[2] = (u8_t)(pll_frac_lt[channel] >> 8);
if (!write_burst_pll_int0(&mcr20a->spi, buf)) { if (!write_burst_pll_int0(mcr20a, buf)) {
SYS_LOG_ERR("Failed to set PLL"); SYS_LOG_ERR("Failed to set PLL");
goto out; goto out;
} }
@ -965,7 +991,7 @@ static int mcr20a_set_pan_id(struct device *dev, u16_t pan_id)
pan_id = sys_le16_to_cpu(pan_id); pan_id = sys_le16_to_cpu(pan_id);
k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER); k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER);
if (!write_burst_pan_id(&mcr20a->spi, (u8_t *) &pan_id)) { if (!write_burst_pan_id(mcr20a, (u8_t *) &pan_id)) {
SYS_LOG_ERR("Failed"); SYS_LOG_ERR("Failed");
k_mutex_unlock(&mcr20a->phy_mutex); k_mutex_unlock(&mcr20a->phy_mutex);
return -EIO; return -EIO;
@ -984,7 +1010,7 @@ static int mcr20a_set_short_addr(struct device *dev, u16_t short_addr)
short_addr = sys_le16_to_cpu(short_addr); short_addr = sys_le16_to_cpu(short_addr);
k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER); k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER);
if (!write_burst_short_addr(&mcr20a->spi, (u8_t *) &short_addr)) { if (!write_burst_short_addr(mcr20a, (u8_t *) &short_addr)) {
SYS_LOG_ERR("Failed"); SYS_LOG_ERR("Failed");
k_mutex_unlock(&mcr20a->phy_mutex); k_mutex_unlock(&mcr20a->phy_mutex);
return -EIO; return -EIO;
@ -1002,7 +1028,7 @@ static int mcr20a_set_ieee_addr(struct device *dev, const u8_t *ieee_addr)
k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER); k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER);
if (!write_burst_ext_addr(&mcr20a->spi, (void *)ieee_addr)) { if (!write_burst_ext_addr(mcr20a, (void *)ieee_addr)) {
SYS_LOG_ERR("Failed"); SYS_LOG_ERR("Failed");
k_mutex_unlock(&mcr20a->phy_mutex); k_mutex_unlock(&mcr20a->phy_mutex);
return -EIO; return -EIO;
@ -1047,7 +1073,7 @@ static int mcr20a_set_txpower(struct device *dev, s16_t dbm)
} }
pwr = pow_lt[dbm - MCR20A_OUTPUT_POWER_MIN]; pwr = pow_lt[dbm - MCR20A_OUTPUT_POWER_MIN];
if (!write_reg_pa_pwr(&mcr20a->spi, set_bits_pa_pwr_val(pwr))) { if (!write_reg_pa_pwr(mcr20a, set_bits_pa_pwr_val(pwr))) {
goto error; goto error;
} }
@ -1060,38 +1086,41 @@ error:
return -EIO; return -EIO;
} }
static inline bool write_txfifo_content(struct mcr20a_spi *spi, static inline bool write_txfifo_content(struct mcr20a_context *dev,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
u8_t cmd[2 + MCR20A_PSDU_LENGTH]; size_t payload_len = net_pkt_ll_reserve(pkt) + frag->len;
u8_t payload_len = net_pkt_ll_reserve(pkt) + frag->len; u8_t cmd_buf[2] = {
u8_t *payload = frag->data - net_pkt_ll_reserve(pkt); MCR20A_BUF_WRITE,
payload_len + MCR20A_FCS_LENGTH
};
const struct spi_buf bufs[2] = {
{
.buf = cmd_buf,
.len = 2
},
{
.buf = frag->data - net_pkt_ll_reserve(pkt),
.len = payload_len
}
};
const struct spi_buf_set tx = {
.buffers = bufs,
.count = 2
};
bool retval; bool retval;
k_sem_take(&spi->spi_sem, K_FOREVER);
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) { if (payload_len > MCR20A_PSDU_LENGTH) {
SYS_LOG_ERR("Payload too long"); SYS_LOG_ERR("Payload too long");
return 0; return 0;
} }
memcpy(&cmd[2], payload, payload_len);
spi_slave_select(spi->dev, spi->slave); k_sem_take(&dev->spi_sem, K_FOREVER);
retval = (spi_transceive(spi->dev, retval = (spi_write(dev->spi, &dev->spi_cfg, &tx) == 0);
cmd, (2 + payload_len),
cmd, (2 + payload_len)) == 0);
k_sem_give(&spi->spi_sem); k_sem_give(&dev->spi_sem);
return retval; return retval;
} }
@ -1120,7 +1149,7 @@ static int mcr20a_tx(struct device *dev,
goto error; goto error;
} }
if (!write_txfifo_content(&mcr20a->spi, pkt, frag)) { if (!write_txfifo_content(mcr20a, pkt, frag)) {
SYS_LOG_ERR("Did not write properly into TX FIFO"); SYS_LOG_ERR("Did not write properly into TX FIFO");
goto error; goto error;
} }
@ -1162,7 +1191,7 @@ static int mcr20a_start(struct device *dev)
k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER); k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER);
enable_irqb_interrupt(mcr20a, false); enable_irqb_interrupt(mcr20a, false);
if (!write_reg_pwr_modes(&mcr20a->spi, MCR20A_PM_AUTODOZE)) { if (!write_reg_pwr_modes(mcr20a, MCR20A_PM_AUTODOZE)) {
SYS_LOG_ERR("Error starting MCR20A"); SYS_LOG_ERR("Error starting MCR20A");
goto error; goto error;
} }
@ -1170,7 +1199,7 @@ static int mcr20a_start(struct device *dev)
do { do {
_usleep(50); _usleep(50);
timeout--; timeout--;
status = read_reg_pwr_modes(&mcr20a->spi); status = read_reg_pwr_modes(mcr20a);
} while (!(status & MCR20A_PWR_MODES_XTAL_READY) && timeout); } while (!(status & MCR20A_PWR_MODES_XTAL_READY) && timeout);
if (!(status & MCR20A_PWR_MODES_XTAL_READY)) { if (!(status & MCR20A_PWR_MODES_XTAL_READY)) {
@ -1179,10 +1208,10 @@ static int mcr20a_start(struct device *dev)
} }
/* Clear all interrupt flags */ /* Clear all interrupt flags */
write_reg_irqsts1(&mcr20a->spi, MCR20A_IRQSTS1_IRQ_MASK); write_reg_irqsts1(mcr20a, MCR20A_IRQSTS1_IRQ_MASK);
write_reg_irqsts2(&mcr20a->spi, MCR20A_IRQSTS2_IRQ_MASK); write_reg_irqsts2(mcr20a, MCR20A_IRQSTS2_IRQ_MASK);
write_reg_irqsts3(&mcr20a->spi, MCR20A_IRQSTS3_IRQ_MASK | write_reg_irqsts3(mcr20a, MCR20A_IRQSTS3_IRQ_MASK |
MCR20A_IRQSTS3_TMR_MASK); MCR20A_IRQSTS3_TMR_MASK);
if (mcr20a_abort_sequence(mcr20a, true)) { if (mcr20a_abort_sequence(mcr20a, true)) {
SYS_LOG_ERR("Failed to reset XCV sequence"); SYS_LOG_ERR("Failed to reset XCV sequence");
@ -1236,7 +1265,7 @@ static int mcr20a_stop(struct device *dev)
power_mode = MCR20A_PM_HIBERNATE; power_mode = MCR20A_PM_HIBERNATE;
} }
if (!write_reg_pwr_modes(&mcr20a->spi, power_mode)) { if (!write_reg_pwr_modes(mcr20a, power_mode)) {
goto error; goto error;
} }
@ -1253,32 +1282,21 @@ error:
static int mcr20a_update_overwrites(struct mcr20a_context *dev) static int mcr20a_update_overwrites(struct mcr20a_context *dev)
{ {
struct mcr20a_spi *spi = &dev->spi; if (!write_reg_overwrite_ver(dev, overwrites_direct[0].data)) {
if (!write_reg_overwrite_ver(spi, overwrites_direct[0].data)) {
goto error; goto error;
} }
k_sem_take(&spi->spi_sem, K_FOREVER);
for (u8_t i = 0; for (u8_t i = 0;
i < sizeof(overwrites_indirect) / sizeof(overwrites_t); i < sizeof(overwrites_indirect) / sizeof(overwrites_t);
i++) { i++) {
spi->cmd_buf[0] = MCR20A_IAR_INDEX | MCR20A_REG_WRITE; if (!_mcr20a_write_reg(dev, true,
spi->cmd_buf[1] = overwrites_indirect[i].address; overwrites_indirect[i].address,
spi->cmd_buf[2] = overwrites_indirect[i].data; overwrites_indirect[i].data)) {
spi_slave_select(spi->dev, spi->slave);
if (spi_write(spi->dev, spi->cmd_buf, 3)) {
k_sem_give(&spi->spi_sem);
goto error; goto error;
} }
} }
k_sem_give(&spi->spi_sem);
return 0; return 0;
error: error:
@ -1313,18 +1331,18 @@ static int power_on_and_setup(struct device *dev)
} }
tmp = MCR20A_CLK_OUT_CONFIG | MCR20A_CLK_OUT_EXTEND; tmp = MCR20A_CLK_OUT_CONFIG | MCR20A_CLK_OUT_EXTEND;
write_reg_clk_out_ctrl(&mcr20a->spi, tmp); write_reg_clk_out_ctrl(mcr20a, tmp);
if (read_reg_clk_out_ctrl(&mcr20a->spi) != tmp) { if (read_reg_clk_out_ctrl(mcr20a) != tmp) {
SYS_LOG_ERR("Failed to get device up"); SYS_LOG_ERR("Failed to get device up");
return -EIO; return -EIO;
} }
/* Clear all interrupt flags */ /* Clear all interrupt flags */
write_reg_irqsts1(&mcr20a->spi, MCR20A_IRQSTS1_IRQ_MASK); write_reg_irqsts1(mcr20a, MCR20A_IRQSTS1_IRQ_MASK);
write_reg_irqsts2(&mcr20a->spi, MCR20A_IRQSTS2_IRQ_MASK); write_reg_irqsts2(mcr20a, MCR20A_IRQSTS2_IRQ_MASK);
write_reg_irqsts3(&mcr20a->spi, MCR20A_IRQSTS3_IRQ_MASK | write_reg_irqsts3(mcr20a, MCR20A_IRQSTS3_IRQ_MASK |
MCR20A_IRQSTS3_TMR_MASK); MCR20A_IRQSTS3_TMR_MASK);
mcr20a_update_overwrites(mcr20a); mcr20a_update_overwrites(mcr20a);
mcr20a_timer_init(dev, MCR20A_TIMEBASE_62500HZ); mcr20a_timer_init(dev, MCR20A_TIMEBASE_62500HZ);
@ -1332,17 +1350,17 @@ static int power_on_and_setup(struct device *dev)
mcr20a_set_txpower(dev, MCR20A_DEFAULT_TX_POWER); mcr20a_set_txpower(dev, MCR20A_DEFAULT_TX_POWER);
mcr20a_set_channel(dev, MCR20A_DEFAULT_CHANNEL); mcr20a_set_channel(dev, MCR20A_DEFAULT_CHANNEL);
mcr20a_set_cca_mode(dev, 1); mcr20a_set_cca_mode(dev, 1);
write_reg_rx_wtr_mark(&mcr20a->spi, 8); write_reg_rx_wtr_mark(mcr20a, 8);
/* Configure PHY behaviour */ /* Configure PHY behaviour */
tmp = MCR20A_PHY_CTRL1_CCABFRTX | tmp = MCR20A_PHY_CTRL1_CCABFRTX |
MCR20A_PHY_CTRL1_AUTOACK | MCR20A_PHY_CTRL1_AUTOACK |
MCR20A_PHY_CTRL1_RXACKRQD; MCR20A_PHY_CTRL1_RXACKRQD;
write_reg_phy_ctrl1(&mcr20a->spi, tmp); write_reg_phy_ctrl1(mcr20a, tmp);
/* Enable Sequence-end interrupt */ /* Enable Sequence-end interrupt */
tmp = MCR20A_PHY_CTRL2_SEQMSK; tmp = MCR20A_PHY_CTRL2_SEQMSK;
write_reg_phy_ctrl2(&mcr20a->spi, ~tmp); write_reg_phy_ctrl2(mcr20a, ~tmp);
setup_gpio_callbacks(mcr20a); setup_gpio_callbacks(mcr20a);
@ -1386,30 +1404,39 @@ static inline int configure_gpios(struct device *dev)
static inline int configure_spi(struct device *dev) static inline int configure_spi(struct device *dev)
{ {
struct mcr20a_context *mcr20a = dev->driver_data; struct mcr20a_context *mcr20a = dev->driver_data;
struct spi_config spi_conf = {
.config = SPI_WORD(8),
.max_sys_freq = CONFIG_IEEE802154_MCR20A_SPI_FREQ,
};
mcr20a->spi.dev = device_get_binding( mcr20a->spi = device_get_binding(
CONFIG_IEEE802154_MCR20A_SPI_DRV_NAME); CONFIG_IEEE802154_MCR20A_SPI_DRV_NAME);
if (!mcr20a->spi.dev) { if (!mcr20a->spi) {
SYS_LOG_ERR("Unable to get SPI device"); SYS_LOG_ERR("Unable to get SPI device");
return -ENODEV; return -ENODEV;
} }
mcr20a->spi.slave = CONFIG_IEEE802154_MCR20A_SPI_SLAVE; #if defined(CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS)
mcr20a->cs_ctrl.gpio_dev = device_get_binding(
if (spi_configure(mcr20a->spi.dev, &spi_conf) != 0 || CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS_DRV_NAME);
spi_slave_select(mcr20a->spi.dev, if (!mcr20a->cs_ctrl.gpio_dev) {
mcr20a->spi.slave) != 0) { SYS_LOG_ERR("Unable to get GPIO SPI CS device");
mcr20a->spi.dev = NULL; return -ENODEV;
return -EIO;
} }
mcr20a->cs_ctrl.gpio_pin = CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS_PIN;
mcr20a->cs_ctrl.delay = 0;
mcr20a->spi_cfg.cs = &mcr20a->cs_ctrl;
SYS_LOG_DBG("SPI GPIO CS configured on %s:%u",
CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS_DRV_NAME,
CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS_PIN);
#endif /* CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS */
mcr20a->spi_cfg.frequency = CONFIG_IEEE802154_MCR20A_SPI_FREQ;
mcr20a->spi_cfg.operation = SPI_WORD_SET(8);
mcr20a->spi_cfg.slave = CONFIG_IEEE802154_MCR20A_SPI_SLAVE;
SYS_LOG_DBG("SPI configured %s, %d", SYS_LOG_DBG("SPI configured %s, %d",
CONFIG_IEEE802154_MCR20A_SPI_DRV_NAME, CONFIG_IEEE802154_MCR20A_SPI_DRV_NAME,
CONFIG_IEEE802154_MCR20A_SPI_SLAVE); CONFIG_IEEE802154_MCR20A_SPI_SLAVE);
return 0; return 0;
} }
@ -1418,7 +1445,7 @@ static int mcr20a_init(struct device *dev)
{ {
struct mcr20a_context *mcr20a = dev->driver_data; struct mcr20a_context *mcr20a = dev->driver_data;
k_sem_init(&mcr20a->spi.spi_sem, 1, UINT_MAX); k_sem_init(&mcr20a->spi_sem, 1, 1);
k_mutex_init(&mcr20a->phy_mutex); k_mutex_init(&mcr20a->phy_mutex);
k_sem_init(&mcr20a->isr_sem, 0, 1); k_sem_init(&mcr20a->isr_sem, 0, 1);

View file

@ -17,24 +17,18 @@
/* Runtime context structure /* Runtime context structure
*************************** ***************************
*/ */
struct mcr20a_spi {
struct device *dev;
u32_t slave;
struct k_sem spi_sem;
/**
* cmd_buf will use at most 9 bytes:
* dummy bytes + 8 ieee address bytes
*/
u8_t cmd_buf[12];
};
struct mcr20a_context { struct mcr20a_context {
struct net_if *iface; struct net_if *iface;
/**************************/ /**************************/
struct device *irq_gpio; struct device *irq_gpio;
struct device *reset_gpio; struct device *reset_gpio;
struct gpio_callback irqb_cb; struct gpio_callback irqb_cb;
struct mcr20a_spi spi; struct device *spi;
struct spi_config spi_cfg;
struct k_sem spi_sem;
#if defined(CONFIG_IEEE802154_MCR20A_GPIO_SPI_CS)
struct spi_cs_control cs_ctrl;
#endif
u8_t mac_addr[8]; u8_t mac_addr[8];
struct k_mutex phy_mutex; struct k_mutex phy_mutex;
struct k_sem isr_sem; struct k_sem isr_sem;
@ -49,25 +43,25 @@ struct mcr20a_context {
#include "ieee802154_mcr20a_regs.h" #include "ieee802154_mcr20a_regs.h"
u8_t _mcr20a_read_reg(struct mcr20a_spi *spi, bool dreg, u8_t addr); u8_t _mcr20a_read_reg(struct mcr20a_context *dev, bool dreg, u8_t addr);
bool _mcr20a_write_reg(struct mcr20a_spi *spi, bool dreg, u8_t addr, bool _mcr20a_write_reg(struct mcr20a_context *dev, bool dreg, u8_t addr,
u8_t value); u8_t value);
bool _mcr20a_write_burst(struct mcr20a_spi *spi, bool dreg, u16_t addr, bool _mcr20a_write_burst(struct mcr20a_context *dev, bool dreg, u16_t addr,
u8_t *data_buf, u8_t len); u8_t *data_buf, u8_t len);
bool _mcr20a_read_burst(struct mcr20a_spi *spi, bool dreg, u16_t addr, bool _mcr20a_read_burst(struct mcr20a_context *dev, bool dreg, u16_t addr,
u8_t *data_buf, u8_t len); u8_t *data_buf, u8_t len);
#define DEFINE_REG_READ(__reg_name, __reg_addr, __dreg) \ #define DEFINE_REG_READ(__reg_name, __reg_addr, __dreg) \
static inline u8_t read_reg_##__reg_name(struct mcr20a_spi *spi) \ static inline u8_t read_reg_##__reg_name(struct mcr20a_context *dev) \
{ \ { \
return _mcr20a_read_reg(spi, __dreg, __reg_addr); \ return _mcr20a_read_reg(dev, __dreg, __reg_addr); \
} }
#define DEFINE_REG_WRITE(__reg_name, __reg_addr, __dreg) \ #define DEFINE_REG_WRITE(__reg_name, __reg_addr, __dreg) \
static inline bool write_reg_##__reg_name(struct mcr20a_spi *spi, \ static inline bool write_reg_##__reg_name(struct mcr20a_context *dev, \
u8_t value) \ u8_t value) \
{ \ { \
return _mcr20a_write_reg(spi, __dreg, __reg_addr, value); \ return _mcr20a_write_reg(dev, __dreg, __reg_addr, value); \
} }
#define DEFINE_DREG_READ(__reg_name, __reg_addr) \ #define DEFINE_DREG_READ(__reg_name, __reg_addr) \
@ -156,18 +150,18 @@ DEFINE_BITS_SET(pa_pwr_val, MCR20A_PA_PWR, _VAL)
DEFINE_BITS_SET(tmr_prescale, MCR20A_TMR_PRESCALE, _VAL) DEFINE_BITS_SET(tmr_prescale, MCR20A_TMR_PRESCALE, _VAL)
DEFINE_BITS_SET(clk_out_div, MCR20A_CLK_OUT, _DIV) DEFINE_BITS_SET(clk_out_div, MCR20A_CLK_OUT, _DIV)
#define DEFINE_BURST_WRITE(__reg_addr, __addr, __sz, __dreg) \ #define DEFINE_BURST_WRITE(__reg_addr, __addr, __sz, __dreg) \
static inline bool write_burst_##__reg_addr(struct mcr20a_spi *spi, \ static inline bool write_burst_##__reg_addr( \
u8_t *buf) \ struct mcr20a_context *dev, u8_t *buf) \
{ \ { \
return _mcr20a_write_burst(spi, __dreg, __addr, buf, __sz); \ return _mcr20a_write_burst(dev, __dreg, __addr, buf, __sz); \
} }
#define DEFINE_BURST_READ(__reg_addr, __addr, __sz, __dreg) \ #define DEFINE_BURST_READ(__reg_addr, __addr, __sz, __dreg) \
static inline bool read_burst_##__reg_addr(struct mcr20a_spi *spi, \ static inline bool read_burst_##__reg_addr(struct mcr20a_context *dev, \
u8_t *buf) \ u8_t *buf) \
{ \ { \
return _mcr20a_read_burst(spi, __dreg, __addr, buf, __sz); \ return _mcr20a_read_burst(dev, __dreg, __addr, buf, __sz); \
} }
DEFINE_BURST_WRITE(t1cmp, MCR20A_T1CMP_LSB, 3, true) DEFINE_BURST_WRITE(t1cmp, MCR20A_T1CMP_LSB, 3, true)