diff --git a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt index dea5124cdc52..d24172cc6d32 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt @@ -1,7 +1,7 @@ * ADF7242 IEEE 802.15.4 * Required properties: - - compatible: should be "adi,adf7242" + - compatible: should be "adi,adf7242", "adi,adf7241" - spi-max-frequency: maximal bus speed (12.5 MHz) - reg: the chipselect index - interrupts: the interrupt generated by the device via pin IRQ1. diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 057e9fdbfac9..e74d8e1da0e2 100644 --- a/Documentation/networking/ieee802154.txt +++ b/Documentation/networking/ieee802154.txt @@ -97,6 +97,46 @@ The include/net/mac802154.h defines following functions: - void ieee802154_unregister_hw(struct ieee802154_hw *hw): freeing registered PHY + - void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, + u8 lqi): + telling 802.15.4 module there is a new received frame in the skb with + the RF Link Quality Indicator (LQI) from the hardware device + + - void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, + bool ifs_handling): + telling 802.15.4 module the frame in the skb is or going to be + transmitted through the hardware device + +The device driver must implement the following callbacks in the IEEE 802.15.4 +operations structure at least: +struct ieee802154_ops { + ... + int (*start)(struct ieee802154_hw *hw); + void (*stop)(struct ieee802154_hw *hw); + ... + int (*xmit_async)(struct ieee802154_hw *hw, struct sk_buff *skb); + int (*ed)(struct ieee802154_hw *hw, u8 *level); + int (*set_channel)(struct ieee802154_hw *hw, u8 page, u8 channel); + ... +}; + + - int start(struct ieee802154_hw *hw): + handler that 802.15.4 module calls for the hardware device initialization. + + - void stop(struct ieee802154_hw *hw): + handler that 802.15.4 module calls for the hardware device cleanup. + + - int xmit_async(struct ieee802154_hw *hw, struct sk_buff *skb): + handler that 802.15.4 module calls for each frame in the skb going to be + transmitted through the hardware device. + + - int ed(struct ieee802154_hw *hw, u8 *level): + handler that 802.15.4 module calls for Energy Detection from the hardware + device. + + - int set_channel(struct ieee802154_hw *hw, u8 page, u8 channel): + set radio for listening on specific channel of the hardware device. + Moreover IEEE 802.15.4 device operations structure should be filled. Fake drivers diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c index 400fdbd3a120..64f1b1e77bc0 100644 --- a/drivers/net/ieee802154/adf7242.c +++ b/drivers/net/ieee802154/adf7242.c @@ -1,7 +1,7 @@ /* * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver * - * Copyright 2009-2015 Analog Devices Inc. + * Copyright 2009-2017 Analog Devices Inc. * * Licensed under the GPL-2 or later. * @@ -344,12 +344,18 @@ static int adf7242_wait_status(struct adf7242_local *lp, unsigned int status, return ret; } -static int adf7242_wait_ready(struct adf7242_local *lp, int line) +static int adf7242_wait_rc_ready(struct adf7242_local *lp, int line) { return adf7242_wait_status(lp, STAT_RC_READY | STAT_SPI_READY, STAT_RC_READY | STAT_SPI_READY, line); } +static int adf7242_wait_spi_ready(struct adf7242_local *lp, int line) +{ + return adf7242_wait_status(lp, STAT_SPI_READY, + STAT_SPI_READY, line); +} + static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8 len) { u8 *buf = lp->buf; @@ -369,7 +375,7 @@ static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8 len) spi_message_add_tail(&xfer_head, &msg); spi_message_add_tail(&xfer_buf, &msg); - adf7242_wait_ready(lp, __LINE__); + adf7242_wait_spi_ready(lp, __LINE__); mutex_lock(&lp->bmux); buf[0] = CMD_SPI_PKT_WR; @@ -401,7 +407,7 @@ static int adf7242_read_fbuf(struct adf7242_local *lp, spi_message_add_tail(&xfer_head, &msg); spi_message_add_tail(&xfer_buf, &msg); - adf7242_wait_ready(lp, __LINE__); + adf7242_wait_spi_ready(lp, __LINE__); mutex_lock(&lp->bmux); if (packet_read) { @@ -432,7 +438,7 @@ static int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8 *data) .rx_buf = lp->buf_read_rx, }; - adf7242_wait_ready(lp, __LINE__); + adf7242_wait_spi_ready(lp, __LINE__); mutex_lock(&lp->bmux); lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr); @@ -462,7 +468,7 @@ static int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8 data) { int status; - adf7242_wait_ready(lp, __LINE__); + adf7242_wait_spi_ready(lp, __LINE__); mutex_lock(&lp->bmux); lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr); @@ -484,7 +490,7 @@ static int adf7242_cmd(struct adf7242_local *lp, unsigned int cmd) dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd); if (cmd != CMD_RC_PC_RESET_NO_WAIT) - adf7242_wait_ready(lp, __LINE__); + adf7242_wait_rc_ready(lp, __LINE__); mutex_lock(&lp->bmux); lp->buf_cmd = cmd; @@ -557,6 +563,22 @@ static int adf7242_verify_firmware(struct adf7242_local *lp, return 0; } +static void adf7242_clear_irqstat(struct adf7242_local *lp) +{ + adf7242_write_reg(lp, REG_IRQ1_SRC1, IRQ_CCA_COMPLETE | IRQ_SFD_RX | + IRQ_SFD_TX | IRQ_RX_PKT_RCVD | IRQ_TX_PKT_SENT | + IRQ_FRAME_VALID | IRQ_ADDRESS_VALID | IRQ_CSMA_CA); +} + +static int adf7242_cmd_rx(struct adf7242_local *lp) +{ + /* Wait until the ACK is sent */ + adf7242_wait_status(lp, RC_STATUS_PHY_RDY, RC_STATUS_MASK, __LINE__); + adf7242_clear_irqstat(lp); + + return adf7242_cmd(lp, CMD_RC_RX); +} + static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm) { struct adf7242_local *lp = hw->priv; @@ -660,7 +682,7 @@ static int adf7242_start(struct ieee802154_hw *hw) struct adf7242_local *lp = hw->priv; adf7242_cmd(lp, CMD_RC_PHY_RDY); - adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); + adf7242_clear_irqstat(lp); enable_irq(lp->spi->irq); set_bit(FLAG_START, &lp->flags); @@ -671,10 +693,10 @@ static void adf7242_stop(struct ieee802154_hw *hw) { struct adf7242_local *lp = hw->priv; + disable_irq(lp->spi->irq); adf7242_cmd(lp, CMD_RC_IDLE); clear_bit(FLAG_START, &lp->flags); - disable_irq(lp->spi->irq); - adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); + adf7242_clear_irqstat(lp); } static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel) @@ -789,9 +811,12 @@ static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) struct adf7242_local *lp = hw->priv; int ret; + /* ensure existing instances of the IRQ handler have completed */ + disable_irq(lp->spi->irq); set_bit(FLAG_XMIT, &lp->flags); reinit_completion(&lp->tx_complete); adf7242_cmd(lp, CMD_RC_PHY_RDY); + adf7242_clear_irqstat(lp); ret = adf7242_write_fbuf(lp, skb->data, skb->len); if (ret) @@ -800,6 +825,7 @@ static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) ret = adf7242_cmd(lp, CMD_RC_CSMACA); if (ret) goto err; + enable_irq(lp->spi->irq); ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, HZ / 10); @@ -822,7 +848,7 @@ static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) err: clear_bit(FLAG_XMIT, &lp->flags); - adf7242_cmd(lp, CMD_RC_RX); + adf7242_cmd_rx(lp); return ret; } @@ -846,7 +872,7 @@ static int adf7242_rx(struct adf7242_local *lp) skb = dev_alloc_skb(len); if (!skb) { - adf7242_cmd(lp, CMD_RC_RX); + adf7242_cmd_rx(lp); return -ENOMEM; } @@ -854,14 +880,14 @@ static int adf7242_rx(struct adf7242_local *lp) ret = adf7242_read_fbuf(lp, data, len, true); if (ret < 0) { kfree_skb(skb); - adf7242_cmd(lp, CMD_RC_RX); + adf7242_cmd_rx(lp); return ret; } lqi = data[len - 2]; lp->rssi = data[len - 1]; - adf7242_cmd(lp, CMD_RC_RX); + ret = adf7242_cmd_rx(lp); skb_trim(skb, len - 2); /* Don't put RSSI/LQI or CRC into the frame */ @@ -870,7 +896,7 @@ static int adf7242_rx(struct adf7242_local *lp) dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n", __func__, ret, (int)len, (int)lqi, lp->rssi); - return 0; + return ret; } static const struct ieee802154_ops adf7242_ops = { @@ -888,7 +914,7 @@ static const struct ieee802154_ops adf7242_ops = { .set_cca_ed_level = adf7242_set_cca_ed_level, }; -static void adf7242_debug(u8 irq1) +static void adf7242_debug(struct adf7242_local *lp, u8 irq1) { #ifdef DEBUG u8 stat; @@ -906,9 +932,12 @@ static void adf7242_debug(u8 irq1) irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "", irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : ""); - dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s%s%s%s%s\n", + dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s\n%s\n%s\n%s%s%s%s%s\n", __func__, stat, + stat & STAT_SPI_READY ? "SPI_READY" : "SPI_BUSY", + stat & STAT_IRQ_STATUS ? "IRQ_PENDING" : "IRQ_CLEAR", stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY", + stat & STAT_CCA_RESULT ? "CHAN_IDLE" : "CHAN_BUSY", (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "", (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "", (stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "", @@ -923,20 +952,20 @@ static irqreturn_t adf7242_isr(int irq, void *data) unsigned int xmit; u8 irq1; - adf7242_wait_status(lp, RC_STATUS_PHY_RDY, RC_STATUS_MASK, __LINE__); - adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1); - adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1); if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA))) dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n", __func__, irq1); - adf7242_debug(irq1); + adf7242_debug(lp, irq1); xmit = test_bit(FLAG_XMIT, &lp->flags); if (xmit && (irq1 & IRQ_CSMA_CA)) { + adf7242_wait_status(lp, RC_STATUS_PHY_RDY, + RC_STATUS_MASK, __LINE__); + if (ADF7242_REPORT_CSMA_CA_STAT) { u8 astat; @@ -957,6 +986,7 @@ static irqreturn_t adf7242_isr(int irq, void *data) lp->tx_stat = SUCCESS; } complete(&lp->tx_complete); + adf7242_clear_irqstat(lp); } else if (!xmit && (irq1 & IRQ_RX_PKT_RCVD) && (irq1 & IRQ_FRAME_VALID)) { adf7242_rx(lp); @@ -965,16 +995,19 @@ static irqreturn_t adf7242_isr(int irq, void *data) dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X\n", __func__, __LINE__, irq1); adf7242_cmd(lp, CMD_RC_PHY_RDY); - adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); - adf7242_cmd(lp, CMD_RC_RX); + adf7242_cmd_rx(lp); } else { /* This can only be xmit without IRQ, likely a RX packet. * we get an TX IRQ shortly - do nothing or let the xmit * timeout handle this */ + dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X, xmit %d\n", __func__, __LINE__, irq1, xmit); + adf7242_wait_status(lp, RC_STATUS_PHY_RDY, + RC_STATUS_MASK, __LINE__); complete(&lp->tx_complete); + adf7242_clear_irqstat(lp); } return IRQ_HANDLED; @@ -994,7 +1027,7 @@ static int adf7242_soft_reset(struct adf7242_local *lp, int line) adf7242_set_promiscuous_mode(lp->hw, lp->promiscuous); adf7242_set_csma_params(lp->hw, lp->min_be, lp->max_be, lp->max_cca_retries); - adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); + adf7242_clear_irqstat(lp); if (test_bit(FLAG_START, &lp->flags)) { enable_irq(lp->spi->irq); @@ -1060,7 +1093,7 @@ static int adf7242_hw_init(struct adf7242_local *lp) adf7242_write_reg(lp, REG_IRQ1_EN0, 0); adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA); - adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); + adf7242_clear_irqstat(lp); adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF); adf7242_cmd(lp, CMD_RC_IDLE); @@ -1086,8 +1119,11 @@ static int adf7242_stats_show(struct seq_file *file, void *offset) irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "", irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : ""); - seq_printf(file, "STATUS = %X:\n%s\n%s%s%s%s%s\n", stat, + seq_printf(file, "STATUS = %X:\n%s\n%s\n%s\n%s\n%s%s%s%s%s\n", stat, + stat & STAT_SPI_READY ? "SPI_READY" : "SPI_BUSY", + stat & STAT_IRQ_STATUS ? "IRQ_PENDING" : "IRQ_CLEAR", stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY", + stat & STAT_CCA_RESULT ? "CHAN_IDLE" : "CHAN_BUSY", (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "", (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "", (stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "", @@ -1257,12 +1293,14 @@ static int adf7242_remove(struct spi_device *spi) static const struct of_device_id adf7242_of_match[] = { { .compatible = "adi,adf7242", }, + { .compatible = "adi,adf7241", }, { }, }; MODULE_DEVICE_TABLE(of, adf7242_of_match); static const struct spi_device_id adf7242_device_id[] = { { .name = "adf7242", }, + { .name = "adf7241", }, { }, }; MODULE_DEVICE_TABLE(spi, adf7242_device_id);