Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Driver for TI CC2520 802.15.4 Wireless-PAN Networking controller
0003  *
0004  * Copyright (C) 2014 Varka Bhadram <varkab@cdac.in>
0005  *            Md.Jamal Mohiuddin <mjmohiuddin@cdac.in>
0006  *            P Sowjanya <sowjanyap@cdac.in>
0007  */
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/gpio.h>
0011 #include <linux/delay.h>
0012 #include <linux/spi/spi.h>
0013 #include <linux/spi/cc2520.h>
0014 #include <linux/workqueue.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/skbuff.h>
0017 #include <linux/of_gpio.h>
0018 #include <linux/ieee802154.h>
0019 #include <linux/crc-ccitt.h>
0020 #include <asm/unaligned.h>
0021 
0022 #include <net/mac802154.h>
0023 #include <net/cfg802154.h>
0024 
0025 #define SPI_COMMAND_BUFFER  3
0026 #define HIGH            1
0027 #define LOW         0
0028 #define STATE_IDLE      0
0029 #define RSSI_VALID      0
0030 #define RSSI_OFFSET     78
0031 
0032 #define CC2520_RAM_SIZE     640
0033 #define CC2520_FIFO_SIZE    128
0034 
0035 #define CC2520RAM_TXFIFO    0x100
0036 #define CC2520RAM_RXFIFO    0x180
0037 #define CC2520RAM_IEEEADDR  0x3EA
0038 #define CC2520RAM_PANID     0x3F2
0039 #define CC2520RAM_SHORTADDR 0x3F4
0040 
0041 #define CC2520_FREG_MASK    0x3F
0042 
0043 /* status byte values */
0044 #define CC2520_STATUS_XOSC32M_STABLE    BIT(7)
0045 #define CC2520_STATUS_RSSI_VALID    BIT(6)
0046 #define CC2520_STATUS_TX_UNDERFLOW  BIT(3)
0047 
0048 /* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */
0049 #define CC2520_MINCHANNEL       11
0050 #define CC2520_MAXCHANNEL       26
0051 #define CC2520_CHANNEL_SPACING      5
0052 
0053 /* command strobes */
0054 #define CC2520_CMD_SNOP         0x00
0055 #define CC2520_CMD_IBUFLD       0x02
0056 #define CC2520_CMD_SIBUFEX      0x03
0057 #define CC2520_CMD_SSAMPLECCA       0x04
0058 #define CC2520_CMD_SRES         0x0f
0059 #define CC2520_CMD_MEMORY_MASK      0x0f
0060 #define CC2520_CMD_MEMORY_READ      0x10
0061 #define CC2520_CMD_MEMORY_WRITE     0x20
0062 #define CC2520_CMD_RXBUF        0x30
0063 #define CC2520_CMD_RXBUFCP      0x38
0064 #define CC2520_CMD_RXBUFMOV     0x32
0065 #define CC2520_CMD_TXBUF        0x3A
0066 #define CC2520_CMD_TXBUFCP      0x3E
0067 #define CC2520_CMD_RANDOM       0x3C
0068 #define CC2520_CMD_SXOSCON      0x40
0069 #define CC2520_CMD_STXCAL       0x41
0070 #define CC2520_CMD_SRXON        0x42
0071 #define CC2520_CMD_STXON        0x43
0072 #define CC2520_CMD_STXONCCA     0x44
0073 #define CC2520_CMD_SRFOFF       0x45
0074 #define CC2520_CMD_SXOSCOFF     0x46
0075 #define CC2520_CMD_SFLUSHRX     0x47
0076 #define CC2520_CMD_SFLUSHTX     0x48
0077 #define CC2520_CMD_SACK         0x49
0078 #define CC2520_CMD_SACKPEND     0x4A
0079 #define CC2520_CMD_SNACK        0x4B
0080 #define CC2520_CMD_SRXMASKBITSET    0x4C
0081 #define CC2520_CMD_SRXMASKBITCLR    0x4D
0082 #define CC2520_CMD_RXMASKAND        0x4E
0083 #define CC2520_CMD_RXMASKOR     0x4F
0084 #define CC2520_CMD_MEMCP        0x50
0085 #define CC2520_CMD_MEMCPR       0x52
0086 #define CC2520_CMD_MEMXCP       0x54
0087 #define CC2520_CMD_MEMXWR       0x56
0088 #define CC2520_CMD_BCLR         0x58
0089 #define CC2520_CMD_BSET         0x59
0090 #define CC2520_CMD_CTR_UCTR     0x60
0091 #define CC2520_CMD_CBCMAC       0x64
0092 #define CC2520_CMD_UCBCMAC      0x66
0093 #define CC2520_CMD_CCM          0x68
0094 #define CC2520_CMD_UCCM         0x6A
0095 #define CC2520_CMD_ECB          0x70
0096 #define CC2520_CMD_ECBO         0x72
0097 #define CC2520_CMD_ECBX         0x74
0098 #define CC2520_CMD_INC          0x78
0099 #define CC2520_CMD_ABORT        0x7F
0100 #define CC2520_CMD_REGISTER_READ    0x80
0101 #define CC2520_CMD_REGISTER_WRITE   0xC0
0102 
0103 /* status registers */
0104 #define CC2520_CHIPID           0x40
0105 #define CC2520_VERSION          0x42
0106 #define CC2520_EXTCLOCK         0x44
0107 #define CC2520_MDMCTRL0         0x46
0108 #define CC2520_MDMCTRL1         0x47
0109 #define CC2520_FREQEST          0x48
0110 #define CC2520_RXCTRL           0x4A
0111 #define CC2520_FSCTRL           0x4C
0112 #define CC2520_FSCAL0           0x4E
0113 #define CC2520_FSCAL1           0x4F
0114 #define CC2520_FSCAL2           0x50
0115 #define CC2520_FSCAL3           0x51
0116 #define CC2520_AGCCTRL0         0x52
0117 #define CC2520_AGCCTRL1         0x53
0118 #define CC2520_AGCCTRL2         0x54
0119 #define CC2520_AGCCTRL3         0x55
0120 #define CC2520_ADCTEST0         0x56
0121 #define CC2520_ADCTEST1         0x57
0122 #define CC2520_ADCTEST2         0x58
0123 #define CC2520_MDMTEST0         0x5A
0124 #define CC2520_MDMTEST1         0x5B
0125 #define CC2520_DACTEST0         0x5C
0126 #define CC2520_DACTEST1         0x5D
0127 #define CC2520_ATEST            0x5E
0128 #define CC2520_DACTEST2         0x5F
0129 #define CC2520_PTEST0           0x60
0130 #define CC2520_PTEST1           0x61
0131 #define CC2520_RESERVED         0x62
0132 #define CC2520_DPUBIST          0x7A
0133 #define CC2520_ACTBIST          0x7C
0134 #define CC2520_RAMBIST          0x7E
0135 
0136 /* frame registers */
0137 #define CC2520_FRMFILT0         0x00
0138 #define CC2520_FRMFILT1         0x01
0139 #define CC2520_SRCMATCH         0x02
0140 #define CC2520_SRCSHORTEN0      0x04
0141 #define CC2520_SRCSHORTEN1      0x05
0142 #define CC2520_SRCSHORTEN2      0x06
0143 #define CC2520_SRCEXTEN0        0x08
0144 #define CC2520_SRCEXTEN1        0x09
0145 #define CC2520_SRCEXTEN2        0x0A
0146 #define CC2520_FRMCTRL0         0x0C
0147 #define CC2520_FRMCTRL1         0x0D
0148 #define CC2520_RXENABLE0        0x0E
0149 #define CC2520_RXENABLE1        0x0F
0150 #define CC2520_EXCFLAG0         0x10
0151 #define CC2520_EXCFLAG1         0x11
0152 #define CC2520_EXCFLAG2         0x12
0153 #define CC2520_EXCMASKA0        0x14
0154 #define CC2520_EXCMASKA1        0x15
0155 #define CC2520_EXCMASKA2        0x16
0156 #define CC2520_EXCMASKB0        0x18
0157 #define CC2520_EXCMASKB1        0x19
0158 #define CC2520_EXCMASKB2        0x1A
0159 #define CC2520_EXCBINDX0        0x1C
0160 #define CC2520_EXCBINDX1        0x1D
0161 #define CC2520_EXCBINDY0        0x1E
0162 #define CC2520_EXCBINDY1        0x1F
0163 #define CC2520_GPIOCTRL0        0x20
0164 #define CC2520_GPIOCTRL1        0x21
0165 #define CC2520_GPIOCTRL2        0x22
0166 #define CC2520_GPIOCTRL3        0x23
0167 #define CC2520_GPIOCTRL4        0x24
0168 #define CC2520_GPIOCTRL5        0x25
0169 #define CC2520_GPIOPOLARITY     0x26
0170 #define CC2520_GPIOCTRL         0x28
0171 #define CC2520_DPUCON           0x2A
0172 #define CC2520_DPUSTAT          0x2C
0173 #define CC2520_FREQCTRL         0x2E
0174 #define CC2520_FREQTUNE         0x2F
0175 #define CC2520_TXPOWER          0x30
0176 #define CC2520_TXCTRL           0x31
0177 #define CC2520_FSMSTAT0         0x32
0178 #define CC2520_FSMSTAT1         0x33
0179 #define CC2520_FIFOPCTRL        0x34
0180 #define CC2520_FSMCTRL          0x35
0181 #define CC2520_CCACTRL0         0x36
0182 #define CC2520_CCACTRL1         0x37
0183 #define CC2520_RSSI         0x38
0184 #define CC2520_RSSISTAT         0x39
0185 #define CC2520_RXFIRST          0x3C
0186 #define CC2520_RXFIFOCNT        0x3E
0187 #define CC2520_TXFIFOCNT        0x3F
0188 
0189 /* CC2520_FRMFILT0 */
0190 #define FRMFILT0_FRAME_FILTER_EN    BIT(0)
0191 #define FRMFILT0_PAN_COORDINATOR    BIT(1)
0192 
0193 /* CC2520_FRMCTRL0 */
0194 #define FRMCTRL0_AUTOACK        BIT(5)
0195 #define FRMCTRL0_AUTOCRC        BIT(6)
0196 
0197 /* CC2520_FRMCTRL1 */
0198 #define FRMCTRL1_SET_RXENMASK_ON_TX BIT(0)
0199 #define FRMCTRL1_IGNORE_TX_UNDERF   BIT(1)
0200 
0201 /* Driver private information */
0202 struct cc2520_private {
0203     struct spi_device *spi;     /* SPI device structure */
0204     struct ieee802154_hw *hw;   /* IEEE-802.15.4 device */
0205     u8 *buf;            /* SPI TX/Rx data buffer */
0206     struct mutex buffer_mutex;  /* SPI buffer mutex */
0207     bool is_tx;         /* Flag for sync b/w Tx and Rx */
0208     bool amplified;         /* Flag for CC2591 */
0209     int fifo_pin;           /* FIFO GPIO pin number */
0210     struct work_struct fifop_irqwork;/* Workqueue for FIFOP */
0211     spinlock_t lock;        /* Lock for is_tx*/
0212     struct completion tx_complete;  /* Work completion for Tx */
0213     bool promiscuous;               /* Flag for promiscuous mode */
0214 };
0215 
0216 /* Generic Functions */
0217 static int
0218 cc2520_cmd_strobe(struct cc2520_private *priv, u8 cmd)
0219 {
0220     int ret;
0221     struct spi_message msg;
0222     struct spi_transfer xfer = {
0223         .len = 0,
0224         .tx_buf = priv->buf,
0225         .rx_buf = priv->buf,
0226     };
0227 
0228     spi_message_init(&msg);
0229     spi_message_add_tail(&xfer, &msg);
0230 
0231     mutex_lock(&priv->buffer_mutex);
0232     priv->buf[xfer.len++] = cmd;
0233     dev_vdbg(&priv->spi->dev,
0234          "command strobe buf[0] = %02x\n",
0235          priv->buf[0]);
0236 
0237     ret = spi_sync(priv->spi, &msg);
0238     dev_vdbg(&priv->spi->dev,
0239          "buf[0] = %02x\n", priv->buf[0]);
0240     mutex_unlock(&priv->buffer_mutex);
0241 
0242     return ret;
0243 }
0244 
0245 static int
0246 cc2520_get_status(struct cc2520_private *priv, u8 *status)
0247 {
0248     int ret;
0249     struct spi_message msg;
0250     struct spi_transfer xfer = {
0251         .len = 0,
0252         .tx_buf = priv->buf,
0253         .rx_buf = priv->buf,
0254     };
0255 
0256     spi_message_init(&msg);
0257     spi_message_add_tail(&xfer, &msg);
0258 
0259     mutex_lock(&priv->buffer_mutex);
0260     priv->buf[xfer.len++] = CC2520_CMD_SNOP;
0261     dev_vdbg(&priv->spi->dev,
0262          "get status command buf[0] = %02x\n", priv->buf[0]);
0263 
0264     ret = spi_sync(priv->spi, &msg);
0265     if (!ret)
0266         *status = priv->buf[0];
0267     dev_vdbg(&priv->spi->dev,
0268          "buf[0] = %02x\n", priv->buf[0]);
0269     mutex_unlock(&priv->buffer_mutex);
0270 
0271     return ret;
0272 }
0273 
0274 static int
0275 cc2520_write_register(struct cc2520_private *priv, u8 reg, u8 value)
0276 {
0277     int status;
0278     struct spi_message msg;
0279     struct spi_transfer xfer = {
0280         .len = 0,
0281         .tx_buf = priv->buf,
0282         .rx_buf = priv->buf,
0283     };
0284 
0285     spi_message_init(&msg);
0286     spi_message_add_tail(&xfer, &msg);
0287 
0288     mutex_lock(&priv->buffer_mutex);
0289 
0290     if (reg <= CC2520_FREG_MASK) {
0291         priv->buf[xfer.len++] = CC2520_CMD_REGISTER_WRITE | reg;
0292         priv->buf[xfer.len++] = value;
0293     } else {
0294         priv->buf[xfer.len++] = CC2520_CMD_MEMORY_WRITE;
0295         priv->buf[xfer.len++] = reg;
0296         priv->buf[xfer.len++] = value;
0297     }
0298     status = spi_sync(priv->spi, &msg);
0299     if (msg.status)
0300         status = msg.status;
0301 
0302     mutex_unlock(&priv->buffer_mutex);
0303 
0304     return status;
0305 }
0306 
0307 static int
0308 cc2520_write_ram(struct cc2520_private *priv, u16 reg, u8 len, u8 *data)
0309 {
0310     int status;
0311     struct spi_message msg;
0312     struct spi_transfer xfer_head = {
0313         .len        = 0,
0314         .tx_buf        = priv->buf,
0315         .rx_buf        = priv->buf,
0316     };
0317 
0318     struct spi_transfer xfer_buf = {
0319         .len = len,
0320         .tx_buf = data,
0321     };
0322 
0323     mutex_lock(&priv->buffer_mutex);
0324     priv->buf[xfer_head.len++] = (CC2520_CMD_MEMORY_WRITE |
0325                         ((reg >> 8) & 0xff));
0326     priv->buf[xfer_head.len++] = reg & 0xff;
0327 
0328     spi_message_init(&msg);
0329     spi_message_add_tail(&xfer_head, &msg);
0330     spi_message_add_tail(&xfer_buf, &msg);
0331 
0332     status = spi_sync(priv->spi, &msg);
0333     dev_dbg(&priv->spi->dev, "spi status = %d\n", status);
0334     if (msg.status)
0335         status = msg.status;
0336 
0337     mutex_unlock(&priv->buffer_mutex);
0338     return status;
0339 }
0340 
0341 static int
0342 cc2520_read_register(struct cc2520_private *priv, u8 reg, u8 *data)
0343 {
0344     int status;
0345     struct spi_message msg;
0346     struct spi_transfer xfer1 = {
0347         .len = 0,
0348         .tx_buf = priv->buf,
0349         .rx_buf = priv->buf,
0350     };
0351 
0352     struct spi_transfer xfer2 = {
0353         .len = 1,
0354         .rx_buf = data,
0355     };
0356 
0357     spi_message_init(&msg);
0358     spi_message_add_tail(&xfer1, &msg);
0359     spi_message_add_tail(&xfer2, &msg);
0360 
0361     mutex_lock(&priv->buffer_mutex);
0362     priv->buf[xfer1.len++] = CC2520_CMD_MEMORY_READ;
0363     priv->buf[xfer1.len++] = reg;
0364 
0365     status = spi_sync(priv->spi, &msg);
0366     dev_dbg(&priv->spi->dev,
0367         "spi status = %d\n", status);
0368     if (msg.status)
0369         status = msg.status;
0370 
0371     mutex_unlock(&priv->buffer_mutex);
0372 
0373     return status;
0374 }
0375 
0376 static int
0377 cc2520_write_txfifo(struct cc2520_private *priv, u8 pkt_len, u8 *data, u8 len)
0378 {
0379     int status;
0380 
0381     /* length byte must include FCS even
0382      * if it is calculated in the hardware
0383      */
0384     int len_byte = pkt_len;
0385 
0386     struct spi_message msg;
0387 
0388     struct spi_transfer xfer_head = {
0389         .len = 0,
0390         .tx_buf = priv->buf,
0391         .rx_buf = priv->buf,
0392     };
0393     struct spi_transfer xfer_len = {
0394         .len = 1,
0395         .tx_buf = &len_byte,
0396     };
0397     struct spi_transfer xfer_buf = {
0398         .len = len,
0399         .tx_buf = data,
0400     };
0401 
0402     spi_message_init(&msg);
0403     spi_message_add_tail(&xfer_head, &msg);
0404     spi_message_add_tail(&xfer_len, &msg);
0405     spi_message_add_tail(&xfer_buf, &msg);
0406 
0407     mutex_lock(&priv->buffer_mutex);
0408     priv->buf[xfer_head.len++] = CC2520_CMD_TXBUF;
0409     dev_vdbg(&priv->spi->dev,
0410          "TX_FIFO cmd buf[0] = %02x\n", priv->buf[0]);
0411 
0412     status = spi_sync(priv->spi, &msg);
0413     dev_vdbg(&priv->spi->dev, "status = %d\n", status);
0414     if (msg.status)
0415         status = msg.status;
0416     dev_vdbg(&priv->spi->dev, "status = %d\n", status);
0417     dev_vdbg(&priv->spi->dev, "buf[0] = %02x\n", priv->buf[0]);
0418     mutex_unlock(&priv->buffer_mutex);
0419 
0420     return status;
0421 }
0422 
0423 static int
0424 cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len)
0425 {
0426     int status;
0427     struct spi_message msg;
0428 
0429     struct spi_transfer xfer_head = {
0430         .len = 0,
0431         .tx_buf = priv->buf,
0432         .rx_buf = priv->buf,
0433     };
0434     struct spi_transfer xfer_buf = {
0435         .len = len,
0436         .rx_buf = data,
0437     };
0438 
0439     spi_message_init(&msg);
0440     spi_message_add_tail(&xfer_head, &msg);
0441     spi_message_add_tail(&xfer_buf, &msg);
0442 
0443     mutex_lock(&priv->buffer_mutex);
0444     priv->buf[xfer_head.len++] = CC2520_CMD_RXBUF;
0445 
0446     dev_vdbg(&priv->spi->dev, "read rxfifo buf[0] = %02x\n", priv->buf[0]);
0447     dev_vdbg(&priv->spi->dev, "buf[1] = %02x\n", priv->buf[1]);
0448 
0449     status = spi_sync(priv->spi, &msg);
0450     dev_vdbg(&priv->spi->dev, "status = %d\n", status);
0451     if (msg.status)
0452         status = msg.status;
0453     dev_vdbg(&priv->spi->dev, "status = %d\n", status);
0454     dev_vdbg(&priv->spi->dev,
0455          "return status buf[0] = %02x\n", priv->buf[0]);
0456     dev_vdbg(&priv->spi->dev, "length buf[1] = %02x\n", priv->buf[1]);
0457 
0458     mutex_unlock(&priv->buffer_mutex);
0459 
0460     return status;
0461 }
0462 
0463 static int cc2520_start(struct ieee802154_hw *hw)
0464 {
0465     return cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRXON);
0466 }
0467 
0468 static void cc2520_stop(struct ieee802154_hw *hw)
0469 {
0470     cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRFOFF);
0471 }
0472 
0473 static int
0474 cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
0475 {
0476     struct cc2520_private *priv = hw->priv;
0477     unsigned long flags;
0478     int rc;
0479     u8 status = 0;
0480     u8 pkt_len;
0481 
0482     /* In promiscuous mode we disable AUTOCRC so we can get the raw CRC
0483      * values on RX. This means we need to manually add the CRC on TX.
0484      */
0485     if (priv->promiscuous) {
0486         u16 crc = crc_ccitt(0, skb->data, skb->len);
0487 
0488         put_unaligned_le16(crc, skb_put(skb, 2));
0489         pkt_len = skb->len;
0490     } else {
0491         pkt_len = skb->len + 2;
0492     }
0493 
0494     rc = cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX);
0495     if (rc)
0496         goto err_tx;
0497 
0498     rc = cc2520_write_txfifo(priv, pkt_len, skb->data, skb->len);
0499     if (rc)
0500         goto err_tx;
0501 
0502     rc = cc2520_get_status(priv, &status);
0503     if (rc)
0504         goto err_tx;
0505 
0506     if (status & CC2520_STATUS_TX_UNDERFLOW) {
0507         rc = -EINVAL;
0508         dev_err(&priv->spi->dev, "cc2520 tx underflow exception\n");
0509         goto err_tx;
0510     }
0511 
0512     spin_lock_irqsave(&priv->lock, flags);
0513     WARN_ON(priv->is_tx);
0514     priv->is_tx = 1;
0515     spin_unlock_irqrestore(&priv->lock, flags);
0516 
0517     rc = cc2520_cmd_strobe(priv, CC2520_CMD_STXONCCA);
0518     if (rc)
0519         goto err;
0520 
0521     rc = wait_for_completion_interruptible(&priv->tx_complete);
0522     if (rc < 0)
0523         goto err;
0524 
0525     cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX);
0526     cc2520_cmd_strobe(priv, CC2520_CMD_SRXON);
0527 
0528     return rc;
0529 err:
0530     spin_lock_irqsave(&priv->lock, flags);
0531     priv->is_tx = 0;
0532     spin_unlock_irqrestore(&priv->lock, flags);
0533 err_tx:
0534     return rc;
0535 }
0536 
0537 static int cc2520_rx(struct cc2520_private *priv)
0538 {
0539     u8 len = 0, lqi = 0, bytes = 1;
0540     struct sk_buff *skb;
0541 
0542     /* Read single length byte from the radio. */
0543     cc2520_read_rxfifo(priv, &len, bytes);
0544 
0545     if (!ieee802154_is_valid_psdu_len(len)) {
0546         /* Corrupted frame received, clear frame buffer by
0547          * reading entire buffer.
0548          */
0549         dev_dbg(&priv->spi->dev, "corrupted frame received\n");
0550         len = IEEE802154_MTU;
0551     }
0552 
0553     skb = dev_alloc_skb(len);
0554     if (!skb)
0555         return -ENOMEM;
0556 
0557     if (cc2520_read_rxfifo(priv, skb_put(skb, len), len)) {
0558         dev_dbg(&priv->spi->dev, "frame reception failed\n");
0559         kfree_skb(skb);
0560         return -EINVAL;
0561     }
0562 
0563     /* In promiscuous mode, we configure the radio to include the
0564      * CRC (AUTOCRC==0) and we pass on the packet unconditionally. If not
0565      * in promiscuous mode, we check the CRC here, but leave the
0566      * RSSI/LQI/CRC_OK bytes as they will get removed in the mac layer.
0567      */
0568     if (!priv->promiscuous) {
0569         bool crc_ok;
0570 
0571         /* Check if the CRC is valid. With AUTOCRC set, the most
0572          * significant bit of the last byte returned from the CC2520
0573          * is CRC_OK flag. See section 20.3.4 of the datasheet.
0574          */
0575         crc_ok = skb->data[len - 1] & BIT(7);
0576 
0577         /* If we failed CRC drop the packet in the driver layer. */
0578         if (!crc_ok) {
0579             dev_dbg(&priv->spi->dev, "CRC check failed\n");
0580             kfree_skb(skb);
0581             return -EINVAL;
0582         }
0583 
0584         /* To calculate LQI, the lower 7 bits of the last byte (the
0585          * correlation value provided by the radio) must be scaled to
0586          * the range 0-255. According to section 20.6, the correlation
0587          * value ranges from 50-110. Ideally this would be calibrated
0588          * per hardware design, but we use roughly the datasheet values
0589          * to get close enough while avoiding floating point.
0590          */
0591         lqi = skb->data[len - 1] & 0x7f;
0592         if (lqi < 50)
0593             lqi = 50;
0594         else if (lqi > 113)
0595             lqi = 113;
0596         lqi = (lqi - 50) * 4;
0597     }
0598 
0599     ieee802154_rx_irqsafe(priv->hw, skb, lqi);
0600 
0601     dev_vdbg(&priv->spi->dev, "RXFIFO: %x %x\n", len, lqi);
0602 
0603     return 0;
0604 }
0605 
0606 static int
0607 cc2520_ed(struct ieee802154_hw *hw, u8 *level)
0608 {
0609     struct cc2520_private *priv = hw->priv;
0610     u8 status = 0xff;
0611     u8 rssi;
0612     int ret;
0613 
0614     ret = cc2520_read_register(priv, CC2520_RSSISTAT, &status);
0615     if (ret)
0616         return ret;
0617 
0618     if (status != RSSI_VALID)
0619         return -EINVAL;
0620 
0621     ret = cc2520_read_register(priv, CC2520_RSSI, &rssi);
0622     if (ret)
0623         return ret;
0624 
0625     /* level = RSSI(rssi) - OFFSET [dBm] : offset is 76dBm */
0626     *level = rssi - RSSI_OFFSET;
0627 
0628     return 0;
0629 }
0630 
0631 static int
0632 cc2520_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
0633 {
0634     struct cc2520_private *priv = hw->priv;
0635     int ret;
0636 
0637     dev_dbg(&priv->spi->dev, "trying to set channel\n");
0638 
0639     WARN_ON(page != 0);
0640     WARN_ON(channel < CC2520_MINCHANNEL);
0641     WARN_ON(channel > CC2520_MAXCHANNEL);
0642 
0643     ret = cc2520_write_register(priv, CC2520_FREQCTRL,
0644                     11 + 5 * (channel - 11));
0645 
0646     return ret;
0647 }
0648 
0649 static int
0650 cc2520_filter(struct ieee802154_hw *hw,
0651           struct ieee802154_hw_addr_filt *filt, unsigned long changed)
0652 {
0653     struct cc2520_private *priv = hw->priv;
0654     int ret = 0;
0655 
0656     if (changed & IEEE802154_AFILT_PANID_CHANGED) {
0657         u16 panid = le16_to_cpu(filt->pan_id);
0658 
0659         dev_vdbg(&priv->spi->dev, "%s called for pan id\n", __func__);
0660         ret = cc2520_write_ram(priv, CC2520RAM_PANID,
0661                        sizeof(panid), (u8 *)&panid);
0662     }
0663 
0664     if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
0665         dev_vdbg(&priv->spi->dev,
0666              "%s called for IEEE addr\n", __func__);
0667         ret = cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
0668                        sizeof(filt->ieee_addr),
0669                        (u8 *)&filt->ieee_addr);
0670     }
0671 
0672     if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
0673         u16 addr = le16_to_cpu(filt->short_addr);
0674 
0675         dev_vdbg(&priv->spi->dev, "%s called for saddr\n", __func__);
0676         ret = cc2520_write_ram(priv, CC2520RAM_SHORTADDR,
0677                        sizeof(addr), (u8 *)&addr);
0678     }
0679 
0680     if (changed & IEEE802154_AFILT_PANC_CHANGED) {
0681         u8 frmfilt0;
0682 
0683         dev_vdbg(&priv->spi->dev,
0684              "%s called for panc change\n", __func__);
0685 
0686         cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0);
0687 
0688         if (filt->pan_coord)
0689             frmfilt0 |= FRMFILT0_PAN_COORDINATOR;
0690         else
0691             frmfilt0 &= ~FRMFILT0_PAN_COORDINATOR;
0692 
0693         ret = cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0);
0694     }
0695 
0696     return ret;
0697 }
0698 
0699 static inline int cc2520_set_tx_power(struct cc2520_private *priv, s32 mbm)
0700 {
0701     u8 power;
0702 
0703     switch (mbm) {
0704     case 500:
0705         power = 0xF7;
0706         break;
0707     case 300:
0708         power = 0xF2;
0709         break;
0710     case 200:
0711         power = 0xAB;
0712         break;
0713     case 100:
0714         power = 0x13;
0715         break;
0716     case 0:
0717         power = 0x32;
0718         break;
0719     case -200:
0720         power = 0x81;
0721         break;
0722     case -400:
0723         power = 0x88;
0724         break;
0725     case -700:
0726         power = 0x2C;
0727         break;
0728     case -1800:
0729         power = 0x03;
0730         break;
0731     default:
0732         return -EINVAL;
0733     }
0734 
0735     return cc2520_write_register(priv, CC2520_TXPOWER, power);
0736 }
0737 
0738 static inline int cc2520_cc2591_set_tx_power(struct cc2520_private *priv,
0739                          s32 mbm)
0740 {
0741     u8 power;
0742 
0743     switch (mbm) {
0744     case 1700:
0745         power = 0xF9;
0746         break;
0747     case 1600:
0748         power = 0xF0;
0749         break;
0750     case 1400:
0751         power = 0xA0;
0752         break;
0753     case 1100:
0754         power = 0x2C;
0755         break;
0756     case -100:
0757         power = 0x03;
0758         break;
0759     case -800:
0760         power = 0x01;
0761         break;
0762     default:
0763         return -EINVAL;
0764     }
0765 
0766     return cc2520_write_register(priv, CC2520_TXPOWER, power);
0767 }
0768 
0769 #define CC2520_MAX_TX_POWERS 0x8
0770 static const s32 cc2520_powers[CC2520_MAX_TX_POWERS + 1] = {
0771     500, 300, 200, 100, 0, -200, -400, -700, -1800,
0772 };
0773 
0774 #define CC2520_CC2591_MAX_TX_POWERS 0x5
0775 static const s32 cc2520_cc2591_powers[CC2520_CC2591_MAX_TX_POWERS + 1] = {
0776     1700, 1600, 1400, 1100, -100, -800,
0777 };
0778 
0779 static int
0780 cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm)
0781 {
0782     struct cc2520_private *priv = hw->priv;
0783 
0784     if (!priv->amplified)
0785         return cc2520_set_tx_power(priv, mbm);
0786 
0787     return cc2520_cc2591_set_tx_power(priv, mbm);
0788 }
0789 
0790 static int
0791 cc2520_set_promiscuous_mode(struct ieee802154_hw *hw, bool on)
0792 {
0793     struct cc2520_private *priv = hw->priv;
0794     u8 frmfilt0;
0795 
0796     dev_dbg(&priv->spi->dev, "%s : mode %d\n", __func__, on);
0797 
0798     priv->promiscuous = on;
0799 
0800     cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0);
0801 
0802     if (on) {
0803         /* Disable automatic ACK, automatic CRC, and frame filtering. */
0804         cc2520_write_register(priv, CC2520_FRMCTRL0, 0);
0805         frmfilt0 &= ~FRMFILT0_FRAME_FILTER_EN;
0806     } else {
0807         cc2520_write_register(priv, CC2520_FRMCTRL0, FRMCTRL0_AUTOACK |
0808                                  FRMCTRL0_AUTOCRC);
0809         frmfilt0 |= FRMFILT0_FRAME_FILTER_EN;
0810     }
0811     return cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0);
0812 }
0813 
0814 static const struct ieee802154_ops cc2520_ops = {
0815     .owner = THIS_MODULE,
0816     .start = cc2520_start,
0817     .stop = cc2520_stop,
0818     .xmit_sync = cc2520_tx,
0819     .ed = cc2520_ed,
0820     .set_channel = cc2520_set_channel,
0821     .set_hw_addr_filt = cc2520_filter,
0822     .set_txpower = cc2520_set_txpower,
0823     .set_promiscuous_mode = cc2520_set_promiscuous_mode,
0824 };
0825 
0826 static int cc2520_register(struct cc2520_private *priv)
0827 {
0828     int ret = -ENOMEM;
0829 
0830     priv->hw = ieee802154_alloc_hw(sizeof(*priv), &cc2520_ops);
0831     if (!priv->hw)
0832         goto err_ret;
0833 
0834     priv->hw->priv = priv;
0835     priv->hw->parent = &priv->spi->dev;
0836     priv->hw->extra_tx_headroom = 0;
0837     ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr);
0838 
0839     /* We do support only 2.4 Ghz */
0840     priv->hw->phy->supported.channels[0] = 0x7FFF800;
0841     priv->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
0842               IEEE802154_HW_PROMISCUOUS;
0843 
0844     priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;
0845 
0846     if (!priv->amplified) {
0847         priv->hw->phy->supported.tx_powers = cc2520_powers;
0848         priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_powers);
0849         priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[4];
0850     } else {
0851         priv->hw->phy->supported.tx_powers = cc2520_cc2591_powers;
0852         priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_cc2591_powers);
0853         priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[0];
0854     }
0855 
0856     priv->hw->phy->current_channel = 11;
0857 
0858     dev_vdbg(&priv->spi->dev, "registered cc2520\n");
0859     ret = ieee802154_register_hw(priv->hw);
0860     if (ret)
0861         goto err_free_device;
0862 
0863     return 0;
0864 
0865 err_free_device:
0866     ieee802154_free_hw(priv->hw);
0867 err_ret:
0868     return ret;
0869 }
0870 
0871 static void cc2520_fifop_irqwork(struct work_struct *work)
0872 {
0873     struct cc2520_private *priv
0874         = container_of(work, struct cc2520_private, fifop_irqwork);
0875 
0876     dev_dbg(&priv->spi->dev, "fifop interrupt received\n");
0877 
0878     if (gpio_get_value(priv->fifo_pin))
0879         cc2520_rx(priv);
0880     else
0881         dev_dbg(&priv->spi->dev, "rxfifo overflow\n");
0882 
0883     cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX);
0884     cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX);
0885 }
0886 
0887 static irqreturn_t cc2520_fifop_isr(int irq, void *data)
0888 {
0889     struct cc2520_private *priv = data;
0890 
0891     schedule_work(&priv->fifop_irqwork);
0892 
0893     return IRQ_HANDLED;
0894 }
0895 
0896 static irqreturn_t cc2520_sfd_isr(int irq, void *data)
0897 {
0898     struct cc2520_private *priv = data;
0899     unsigned long flags;
0900 
0901     spin_lock_irqsave(&priv->lock, flags);
0902     if (priv->is_tx) {
0903         priv->is_tx = 0;
0904         spin_unlock_irqrestore(&priv->lock, flags);
0905         dev_dbg(&priv->spi->dev, "SFD for TX\n");
0906         complete(&priv->tx_complete);
0907     } else {
0908         spin_unlock_irqrestore(&priv->lock, flags);
0909         dev_dbg(&priv->spi->dev, "SFD for RX\n");
0910     }
0911 
0912     return IRQ_HANDLED;
0913 }
0914 
0915 static int cc2520_get_platform_data(struct spi_device *spi,
0916                     struct cc2520_platform_data *pdata)
0917 {
0918     struct device_node *np = spi->dev.of_node;
0919     struct cc2520_private *priv = spi_get_drvdata(spi);
0920 
0921     if (!np) {
0922         struct cc2520_platform_data *spi_pdata = spi->dev.platform_data;
0923 
0924         if (!spi_pdata)
0925             return -ENOENT;
0926         *pdata = *spi_pdata;
0927         priv->fifo_pin = pdata->fifo;
0928         return 0;
0929     }
0930 
0931     pdata->fifo = of_get_named_gpio(np, "fifo-gpio", 0);
0932     priv->fifo_pin = pdata->fifo;
0933 
0934     pdata->fifop = of_get_named_gpio(np, "fifop-gpio", 0);
0935 
0936     pdata->sfd = of_get_named_gpio(np, "sfd-gpio", 0);
0937     pdata->cca = of_get_named_gpio(np, "cca-gpio", 0);
0938     pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0);
0939     pdata->reset = of_get_named_gpio(np, "reset-gpio", 0);
0940 
0941     /* CC2591 front end for CC2520 */
0942     if (of_property_read_bool(np, "amplified"))
0943         priv->amplified = true;
0944 
0945     return 0;
0946 }
0947 
0948 static int cc2520_hw_init(struct cc2520_private *priv)
0949 {
0950     u8 status = 0, state = 0xff;
0951     int ret;
0952     int timeout = 100;
0953     struct cc2520_platform_data pdata;
0954 
0955     ret = cc2520_get_platform_data(priv->spi, &pdata);
0956     if (ret)
0957         goto err_ret;
0958 
0959     ret = cc2520_read_register(priv, CC2520_FSMSTAT1, &state);
0960     if (ret)
0961         goto err_ret;
0962 
0963     if (state != STATE_IDLE)
0964         return -EINVAL;
0965 
0966     do {
0967         ret = cc2520_get_status(priv, &status);
0968         if (ret)
0969             goto err_ret;
0970 
0971         if (timeout-- <= 0) {
0972             dev_err(&priv->spi->dev, "oscillator start failed!\n");
0973             return ret;
0974         }
0975         udelay(1);
0976     } while (!(status & CC2520_STATUS_XOSC32M_STABLE));
0977 
0978     dev_vdbg(&priv->spi->dev, "oscillator brought up\n");
0979 
0980     /* If the CC2520 is connected to a CC2591 amplifier, we must both
0981      * configure GPIOs on the CC2520 to correctly configure the CC2591
0982      * and change a couple settings of the CC2520 to work with the
0983      * amplifier. See section 8 page 17 of TI application note AN065.
0984      * http://www.ti.com/lit/an/swra229a/swra229a.pdf
0985      */
0986     if (priv->amplified) {
0987         ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16);
0988         if (ret)
0989             goto err_ret;
0990 
0991         ret = cc2520_write_register(priv, CC2520_GPIOCTRL0, 0x46);
0992         if (ret)
0993             goto err_ret;
0994 
0995         ret = cc2520_write_register(priv, CC2520_GPIOCTRL5, 0x47);
0996         if (ret)
0997             goto err_ret;
0998 
0999         ret = cc2520_write_register(priv, CC2520_GPIOPOLARITY, 0x1e);
1000         if (ret)
1001             goto err_ret;
1002 
1003         ret = cc2520_write_register(priv, CC2520_TXCTRL, 0xc1);
1004         if (ret)
1005             goto err_ret;
1006     } else {
1007         ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11);
1008         if (ret)
1009             goto err_ret;
1010     }
1011 
1012     /* Registers default value: section 28.1 in Datasheet */
1013 
1014     /* Set the CCA threshold to -50 dBm. This seems to have been copied
1015      * from the TinyOS CC2520 driver and is much higher than the -84 dBm
1016      * threshold suggested in the datasheet.
1017      */
1018     ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A);
1019     if (ret)
1020         goto err_ret;
1021 
1022     ret = cc2520_write_register(priv, CC2520_MDMCTRL0, 0x85);
1023     if (ret)
1024         goto err_ret;
1025 
1026     ret = cc2520_write_register(priv, CC2520_MDMCTRL1, 0x14);
1027     if (ret)
1028         goto err_ret;
1029 
1030     ret = cc2520_write_register(priv, CC2520_RXCTRL, 0x3f);
1031     if (ret)
1032         goto err_ret;
1033 
1034     ret = cc2520_write_register(priv, CC2520_FSCTRL, 0x5a);
1035     if (ret)
1036         goto err_ret;
1037 
1038     ret = cc2520_write_register(priv, CC2520_FSCAL1, 0x2b);
1039     if (ret)
1040         goto err_ret;
1041 
1042     ret = cc2520_write_register(priv, CC2520_ADCTEST0, 0x10);
1043     if (ret)
1044         goto err_ret;
1045 
1046     ret = cc2520_write_register(priv, CC2520_ADCTEST1, 0x0e);
1047     if (ret)
1048         goto err_ret;
1049 
1050     ret = cc2520_write_register(priv, CC2520_ADCTEST2, 0x03);
1051     if (ret)
1052         goto err_ret;
1053 
1054     /* Configure registers correctly for this driver. */
1055     ret = cc2520_write_register(priv, CC2520_FRMCTRL1,
1056                     FRMCTRL1_SET_RXENMASK_ON_TX |
1057                     FRMCTRL1_IGNORE_TX_UNDERF);
1058     if (ret)
1059         goto err_ret;
1060 
1061     ret = cc2520_write_register(priv, CC2520_FIFOPCTRL, 127);
1062     if (ret)
1063         goto err_ret;
1064 
1065     return 0;
1066 
1067 err_ret:
1068     return ret;
1069 }
1070 
1071 static int cc2520_probe(struct spi_device *spi)
1072 {
1073     struct cc2520_private *priv;
1074     struct cc2520_platform_data pdata;
1075     int ret;
1076 
1077     priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
1078     if (!priv)
1079         return -ENOMEM;
1080 
1081     spi_set_drvdata(spi, priv);
1082 
1083     ret = cc2520_get_platform_data(spi, &pdata);
1084     if (ret < 0) {
1085         dev_err(&spi->dev, "no platform data\n");
1086         return -EINVAL;
1087     }
1088 
1089     priv->spi = spi;
1090 
1091     priv->buf = devm_kzalloc(&spi->dev,
1092                  SPI_COMMAND_BUFFER, GFP_KERNEL);
1093     if (!priv->buf)
1094         return -ENOMEM;
1095 
1096     mutex_init(&priv->buffer_mutex);
1097     INIT_WORK(&priv->fifop_irqwork, cc2520_fifop_irqwork);
1098     spin_lock_init(&priv->lock);
1099     init_completion(&priv->tx_complete);
1100 
1101     /* Assumption that CC2591 is not connected */
1102     priv->amplified = false;
1103 
1104     /* Request all the gpio's */
1105     if (!gpio_is_valid(pdata.fifo)) {
1106         dev_err(&spi->dev, "fifo gpio is not valid\n");
1107         ret = -EINVAL;
1108         goto err_hw_init;
1109     }
1110 
1111     ret = devm_gpio_request_one(&spi->dev, pdata.fifo,
1112                     GPIOF_IN, "fifo");
1113     if (ret)
1114         goto err_hw_init;
1115 
1116     if (!gpio_is_valid(pdata.cca)) {
1117         dev_err(&spi->dev, "cca gpio is not valid\n");
1118         ret = -EINVAL;
1119         goto err_hw_init;
1120     }
1121 
1122     ret = devm_gpio_request_one(&spi->dev, pdata.cca,
1123                     GPIOF_IN, "cca");
1124     if (ret)
1125         goto err_hw_init;
1126 
1127     if (!gpio_is_valid(pdata.fifop)) {
1128         dev_err(&spi->dev, "fifop gpio is not valid\n");
1129         ret = -EINVAL;
1130         goto err_hw_init;
1131     }
1132 
1133     ret = devm_gpio_request_one(&spi->dev, pdata.fifop,
1134                     GPIOF_IN, "fifop");
1135     if (ret)
1136         goto err_hw_init;
1137 
1138     if (!gpio_is_valid(pdata.sfd)) {
1139         dev_err(&spi->dev, "sfd gpio is not valid\n");
1140         ret = -EINVAL;
1141         goto err_hw_init;
1142     }
1143 
1144     ret = devm_gpio_request_one(&spi->dev, pdata.sfd,
1145                     GPIOF_IN, "sfd");
1146     if (ret)
1147         goto err_hw_init;
1148 
1149     if (!gpio_is_valid(pdata.reset)) {
1150         dev_err(&spi->dev, "reset gpio is not valid\n");
1151         ret = -EINVAL;
1152         goto err_hw_init;
1153     }
1154 
1155     ret = devm_gpio_request_one(&spi->dev, pdata.reset,
1156                     GPIOF_OUT_INIT_LOW, "reset");
1157     if (ret)
1158         goto err_hw_init;
1159 
1160     if (!gpio_is_valid(pdata.vreg)) {
1161         dev_err(&spi->dev, "vreg gpio is not valid\n");
1162         ret = -EINVAL;
1163         goto err_hw_init;
1164     }
1165 
1166     ret = devm_gpio_request_one(&spi->dev, pdata.vreg,
1167                     GPIOF_OUT_INIT_LOW, "vreg");
1168     if (ret)
1169         goto err_hw_init;
1170 
1171     gpio_set_value(pdata.vreg, HIGH);
1172     usleep_range(100, 150);
1173 
1174     gpio_set_value(pdata.reset, HIGH);
1175     usleep_range(200, 250);
1176 
1177     ret = cc2520_hw_init(priv);
1178     if (ret)
1179         goto err_hw_init;
1180 
1181     /* Set up fifop interrupt */
1182     ret = devm_request_irq(&spi->dev,
1183                    gpio_to_irq(pdata.fifop),
1184                    cc2520_fifop_isr,
1185                    IRQF_TRIGGER_RISING,
1186                    dev_name(&spi->dev),
1187                    priv);
1188     if (ret) {
1189         dev_err(&spi->dev, "could not get fifop irq\n");
1190         goto err_hw_init;
1191     }
1192 
1193     /* Set up sfd interrupt */
1194     ret = devm_request_irq(&spi->dev,
1195                    gpio_to_irq(pdata.sfd),
1196                    cc2520_sfd_isr,
1197                    IRQF_TRIGGER_FALLING,
1198                    dev_name(&spi->dev),
1199                    priv);
1200     if (ret) {
1201         dev_err(&spi->dev, "could not get sfd irq\n");
1202         goto err_hw_init;
1203     }
1204 
1205     ret = cc2520_register(priv);
1206     if (ret)
1207         goto err_hw_init;
1208 
1209     return 0;
1210 
1211 err_hw_init:
1212     mutex_destroy(&priv->buffer_mutex);
1213     flush_work(&priv->fifop_irqwork);
1214     return ret;
1215 }
1216 
1217 static void cc2520_remove(struct spi_device *spi)
1218 {
1219     struct cc2520_private *priv = spi_get_drvdata(spi);
1220 
1221     mutex_destroy(&priv->buffer_mutex);
1222     flush_work(&priv->fifop_irqwork);
1223 
1224     ieee802154_unregister_hw(priv->hw);
1225     ieee802154_free_hw(priv->hw);
1226 }
1227 
1228 static const struct spi_device_id cc2520_ids[] = {
1229     {"cc2520", },
1230     {},
1231 };
1232 MODULE_DEVICE_TABLE(spi, cc2520_ids);
1233 
1234 static const struct of_device_id cc2520_of_ids[] = {
1235     {.compatible = "ti,cc2520", },
1236     {},
1237 };
1238 MODULE_DEVICE_TABLE(of, cc2520_of_ids);
1239 
1240 /* SPI driver structure */
1241 static struct spi_driver cc2520_driver = {
1242     .driver = {
1243         .name = "cc2520",
1244         .of_match_table = of_match_ptr(cc2520_of_ids),
1245     },
1246     .id_table = cc2520_ids,
1247     .probe = cc2520_probe,
1248     .remove = cc2520_remove,
1249 };
1250 module_spi_driver(cc2520_driver);
1251 
1252 MODULE_AUTHOR("Varka Bhadram <varkab@cdac.in>");
1253 MODULE_DESCRIPTION("CC2520 Transceiver Driver");
1254 MODULE_LICENSE("GPL v2");