diff options
Diffstat (limited to 'drivers/net/ieee802154')
-rw-r--r-- | drivers/net/ieee802154/at86rf230.c | 151 | ||||
-rw-r--r-- | drivers/net/ieee802154/fakehard.c | 21 | ||||
-rw-r--r-- | drivers/net/ieee802154/mrf24j40.c | 41 |
3 files changed, 137 insertions, 76 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index fc1687ea4a42..6f10b4964726 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -51,7 +51,7 @@ struct at86rf230_local { struct ieee802154_dev *dev; spinlock_t lock; - bool irq_disabled; + bool irq_busy; bool is_tx; }; @@ -219,6 +219,9 @@ struct at86rf230_local { #define IRQ_PLL_UNL (1 << 1) #define IRQ_PLL_LOCK (1 << 0) +#define IRQ_ACTIVE_HIGH 0 +#define IRQ_ACTIVE_LOW 1 + #define STATE_P_ON 0x00 /* BUSY */ #define STATE_BUSY_RX 0x01 #define STATE_BUSY_TX 0x02 @@ -233,8 +236,8 @@ struct at86rf230_local { #define STATE_SLEEP 0x0F #define STATE_BUSY_RX_AACK 0x11 #define STATE_BUSY_TX_ARET 0x12 -#define STATE_BUSY_RX_AACK_ON 0x16 -#define STATE_BUSY_TX_ARET_ON 0x19 +#define STATE_RX_AACK_ON 0x16 +#define STATE_TX_ARET_ON 0x19 #define STATE_RX_ON_NOCLK 0x1C #define STATE_RX_AACK_ON_NOCLK 0x1D #define STATE_BUSY_RX_AACK_NOCLK 0x1E @@ -544,7 +547,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) unsigned long flags; spin_lock(&lp->lock); - if (lp->irq_disabled) { + if (lp->irq_busy) { spin_unlock(&lp->lock); return -EBUSY; } @@ -619,6 +622,52 @@ err: return -EINVAL; } +static int +at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, + struct ieee802154_hw_addr_filt *filt, + unsigned long changed) +{ + struct at86rf230_local *lp = dev->priv; + + if (changed & IEEE802515_AFILT_SADDR_CHANGED) { + dev_vdbg(&lp->spi->dev, + "at86rf230_set_hw_addr_filt called for saddr\n"); + __at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr); + __at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8); + } + + if (changed & IEEE802515_AFILT_PANID_CHANGED) { + dev_vdbg(&lp->spi->dev, + "at86rf230_set_hw_addr_filt called for pan id\n"); + __at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id); + __at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8); + } + + if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { + dev_vdbg(&lp->spi->dev, + "at86rf230_set_hw_addr_filt called for IEEE addr\n"); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]); + at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]); + } + + if (changed & IEEE802515_AFILT_PANC_CHANGED) { + dev_vdbg(&lp->spi->dev, + "at86rf230_set_hw_addr_filt called for panc change\n"); + if (filt->pan_coord) + at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1); + else + at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 0); + } + + return 0; +} + static struct ieee802154_ops at86rf230_ops = { .owner = THIS_MODULE, .xmit = at86rf230_xmit, @@ -626,6 +675,7 @@ static struct ieee802154_ops at86rf230_ops = { .set_channel = at86rf230_channel, .start = at86rf230_start, .stop = at86rf230_stop, + .set_hw_addr_filt = at86rf230_set_hw_addr_filt, }; static void at86rf230_irqwork(struct work_struct *work) @@ -658,8 +708,16 @@ static void at86rf230_irqwork(struct work_struct *work) } spin_lock_irqsave(&lp->lock, flags); - lp->irq_disabled = 0; + lp->irq_busy = 0; spin_unlock_irqrestore(&lp->lock, flags); +} + +static void at86rf230_irqwork_level(struct work_struct *work) +{ + struct at86rf230_local *lp = + container_of(work, struct at86rf230_local, irqwork); + + at86rf230_irqwork(work); enable_irq(lp->spi->irq); } @@ -668,10 +726,8 @@ static irqreturn_t at86rf230_isr(int irq, void *data) { struct at86rf230_local *lp = data; - disable_irq_nosync(irq); - spin_lock(&lp->lock); - lp->irq_disabled = 1; + lp->irq_busy = 1; spin_unlock(&lp->lock); schedule_work(&lp->irqwork); @@ -679,11 +735,23 @@ static irqreturn_t at86rf230_isr(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t at86rf230_isr_level(int irq, void *data) +{ + disable_irq_nosync(irq); + + return at86rf230_isr(irq, data); +} + +static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol) +{ + return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol); +} static int at86rf230_hw_init(struct at86rf230_local *lp) { + struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data; + int rc, irq_pol; u8 status; - int rc; rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); if (rc) @@ -701,12 +769,17 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) dev_info(&lp->spi->dev, "Status: %02x\n", status); } - rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR | - * IRQ_CCA_ED | - * IRQ_TRX_END | - * IRQ_PLL_UNL | - * IRQ_PLL_LOCK - */ + /* configure irq polarity, defaults to high active */ + if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) + irq_pol = IRQ_ACTIVE_LOW; + else + irq_pol = IRQ_ACTIVE_HIGH; + + rc = at86rf230_irq_polarity(lp, irq_pol); + if (rc) + return rc; + + rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END); if (rc) return rc; @@ -751,37 +824,38 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) return 0; } -static int at86rf230_fill_data(struct spi_device *spi) +static void at86rf230_fill_data(struct spi_device *spi) { struct at86rf230_local *lp = spi_get_drvdata(spi); struct at86rf230_platform_data *pdata = spi->dev.platform_data; - if (!pdata) { - dev_err(&spi->dev, "no platform_data\n"); - return -EINVAL; - } - lp->rstn = pdata->rstn; lp->slp_tr = pdata->slp_tr; lp->dig2 = pdata->dig2; - - return 0; } static int at86rf230_probe(struct spi_device *spi) { + struct at86rf230_platform_data *pdata; struct ieee802154_dev *dev; struct at86rf230_local *lp; - u8 man_id_0, man_id_1; - int rc; + u8 man_id_0, man_id_1, status; + irq_handler_t irq_handler; + work_func_t irq_worker; + int rc, supported = 0; const char *chip; - int supported = 0; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); return -EINVAL; } + pdata = spi->dev.platform_data; + if (!pdata) { + dev_err(&spi->dev, "no platform_data\n"); + return -EINVAL; + } + dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops); if (!dev) return -ENOMEM; @@ -791,23 +865,28 @@ static int at86rf230_probe(struct spi_device *spi) lp->spi = spi; - dev->priv = lp; dev->parent = &spi->dev; dev->extra_tx_headroom = 0; /* We do support only 2.4 Ghz */ dev->phy->channels_supported[0] = 0x7FFF800; dev->flags = IEEE802154_HW_OMIT_CKSUM; + if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + irq_worker = at86rf230_irqwork; + irq_handler = at86rf230_isr; + } else { + irq_worker = at86rf230_irqwork_level; + irq_handler = at86rf230_isr_level; + } + mutex_init(&lp->bmux); - INIT_WORK(&lp->irqwork, at86rf230_irqwork); + INIT_WORK(&lp->irqwork, irq_worker); spin_lock_init(&lp->lock); init_completion(&lp->tx_complete); spi_set_drvdata(spi, lp); - rc = at86rf230_fill_data(spi); - if (rc) - goto err_fill; + at86rf230_fill_data(spi); rc = gpio_request(lp->rstn, "rstn"); if (rc) @@ -882,18 +961,23 @@ static int at86rf230_probe(struct spi_device *spi) if (rc) goto err_gpio_dir; - rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED, + rc = request_irq(spi->irq, irq_handler, + IRQF_SHARED | pdata->irq_type, dev_name(&spi->dev), lp); if (rc) goto err_gpio_dir; + /* Read irq status register to reset irq line */ + rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); + if (rc) + goto err_irq; + rc = ieee802154_register_device(lp->dev); if (rc) goto err_irq; return rc; - ieee802154_unregister_device(lp->dev); err_irq: free_irq(spi->irq, lp); flush_work(&lp->irqwork); @@ -903,7 +987,6 @@ err_gpio_dir: err_slp_tr: gpio_free(lp->rstn); err_rstn: -err_fill: spi_set_drvdata(spi, NULL); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c index 8f1c25676d44..bf0d55e2dd63 100644 --- a/drivers/net/ieee802154/fakehard.c +++ b/drivers/net/ieee802154/fakehard.c @@ -106,26 +106,6 @@ static u8 fake_get_dsn(const struct net_device *dev) } /** - * fake_get_bsn - Retrieve the BSN of the device. - * @dev: The network device to retrieve the BSN for. - * - * Returns the IEEE 802.15.4 BSN for the network device. - * The BSN is the sequence number which will be added to each - * beacon frame sent by the MAC. - * - * BSN means 'Beacon Sequence Number'. - * - * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 - * document. - */ -static u8 fake_get_bsn(const struct net_device *dev) -{ - BUG_ON(dev->type != ARPHRD_IEEE802154); - - return 0x00; /* BSN are implemented in HW, so return just 0 */ -} - -/** * fake_assoc_req - Make an association request to the HW. * @dev: The network device which we are associating to a network. * @addr: The coordinator with which we wish to associate. @@ -264,7 +244,6 @@ static struct ieee802154_mlme_ops fake_mlme = { .get_pan_id = fake_get_pan_id, .get_short_addr = fake_get_short_addr, .get_dsn = fake_get_dsn, - .get_bsn = fake_get_bsn, }; static int ieee802154_fake_open(struct net_device *dev) diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 3f2c7aaf28c4..ede3ce4912f9 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -22,8 +22,10 @@ #include <linux/spi/spi.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <net/wpan-phy.h> #include <net/mac802154.h> +#include <net/ieee802154.h> /* MRF24J40 Short Address Registers */ #define REG_RXMCR 0x00 /* Receive MAC control */ @@ -91,9 +93,8 @@ struct mrf24j40 { #define MRF24J40_READLONG(reg) (1 << 15 | (reg) << 5) #define MRF24J40_WRITELONG(reg) (1 << 15 | (reg) << 5 | 1 << 4) -/* Maximum speed to run the device at. TODO: Get the real max value from - * someone at Microchip since it isn't in the datasheet. */ -#define MAX_SPI_SPEED_HZ 1000000 +/* The datasheet indicates the theoretical maximum for SCK to be 10MHz */ +#define MAX_SPI_SPEED_HZ 10000000 #define printdev(X) (&X->spi->dev) @@ -349,7 +350,9 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb) if (ret) goto err; val |= 0x1; - val &= ~0x4; + /* Set TXNACKREQ if the ACK bit is set in the packet. */ + if (skb->data[0] & IEEE802154_FC_ACK_REQ) + val |= 0x4; write_short_reg(devrec, REG_TXNCON, val); INIT_COMPLETION(devrec->tx_complete); @@ -361,6 +364,7 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb) if (ret == -ERESTARTSYS) goto err; if (ret == 0) { + dev_warn(printdev(devrec), "Timeout waiting for TX interrupt\n"); ret = -ETIMEDOUT; goto err; } @@ -370,7 +374,7 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb) if (ret) goto err; if (val & 0x1) { - dev_err(printdev(devrec), "Error Sending. Retry count exceeded\n"); + dev_dbg(printdev(devrec), "Error Sending. Retry count exceeded\n"); ret = -ECOMM; /* TODO: Better error code ? */ } else dev_dbg(printdev(devrec), "Packet Sent\n"); @@ -477,7 +481,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, int i; for (i = 0; i < 8; i++) write_short_reg(devrec, REG_EADR0+i, - filt->ieee_addr[i]); + filt->ieee_addr[7-i]); #ifdef DEBUG printk(KERN_DEBUG "Set long addr to: "); @@ -623,6 +627,7 @@ static int mrf24j40_probe(struct spi_device *spi) int ret = -ENOMEM; u8 val; struct mrf24j40 *devrec; + struct pinctrl *pinctrl; printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq); @@ -633,6 +638,11 @@ static int mrf24j40_probe(struct spi_device *spi) if (!devrec->buf) goto err_buf; + pinctrl = devm_pinctrl_get_select_default(&spi->dev); + if (IS_ERR(pinctrl)) + dev_warn(&spi->dev, + "pinctrl pins are not configured from the driver"); + spi->mode = SPI_MODE_0; /* TODO: Is this appropriate for right here? */ if (spi->max_speed_hz > MAX_SPI_SPEED_HZ) spi->max_speed_hz = MAX_SPI_SPEED_HZ; @@ -641,7 +651,7 @@ static int mrf24j40_probe(struct spi_device *spi) init_completion(&devrec->tx_complete); INIT_WORK(&devrec->irqwork, mrf24j40_isrwork); devrec->spi = spi; - dev_set_drvdata(&spi->dev, devrec); + spi_set_drvdata(spi, devrec); /* Register with the 802154 subsystem */ @@ -713,7 +723,7 @@ err_devrec: static int mrf24j40_remove(struct spi_device *spi) { - struct mrf24j40 *devrec = dev_get_drvdata(&spi->dev); + struct mrf24j40 *devrec = spi_get_drvdata(spi); dev_dbg(printdev(devrec), "remove\n"); @@ -725,7 +735,7 @@ static int mrf24j40_remove(struct spi_device *spi) * complete? */ /* Clean up the SPI stuff. */ - dev_set_drvdata(&spi->dev, NULL); + spi_set_drvdata(spi, NULL); kfree(devrec->buf); kfree(devrec); return 0; @@ -749,18 +759,7 @@ static struct spi_driver mrf24j40_driver = { .remove = mrf24j40_remove, }; -static int __init mrf24j40_init(void) -{ - return spi_register_driver(&mrf24j40_driver); -} - -static void __exit mrf24j40_exit(void) -{ - spi_unregister_driver(&mrf24j40_driver); -} - -module_init(mrf24j40_init); -module_exit(mrf24j40_exit); +module_spi_driver(mrf24j40_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alan Ott"); |