Commit 7b8e19b67c1b171a04f6bd2f973d0b38cb496bf6

Authored by alex.bluesman.smirnov@gmail.com
Committed by David S. Miller
1 parent 5265f46711

drivers/ieee802154: add support for the at86rf230/231 transceivers

The AT86RF231 is a feature rich, low-power 2.4 GHz radio transceiver
designed for industrial and consumer ZigBee/IEEE 802.15.4, 6LoWPAN,
RF4CE and high data rate 2.4 GHz ISM band applications.

This patch adds support for the Atmel RF230/231 radio transceivers.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 4 changed files with 1003 additions and 0 deletions Side-by-side Diff

drivers/ieee802154/Kconfig
... ... @@ -19,6 +19,7 @@
19 19  
20 20 This driver can also be built as a module. To do so say M here.
21 21 The module will be called 'fakehard'.
  22 +
22 23 config IEEE802154_FAKELB
23 24 depends on IEEE802154_DRIVERS && MAC802154
24 25 tristate "IEEE 802.15.4 loopback driver"
... ... @@ -28,4 +29,9 @@
28 29  
29 30 This driver can also be built as a module. To do so say M here.
30 31 The module will be called 'fakelb'.
  32 +
  33 +config IEEE802154_AT86RF230
  34 + depends on IEEE802154_DRIVERS && MAC802154
  35 + tristate "AT86RF230/231 transceiver driver"
  36 + depends on SPI
drivers/ieee802154/Makefile
1 1 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
2 2 obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
  3 +obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
drivers/ieee802154/at86rf230.c
  1 +/*
  2 + * AT86RF230/RF231 driver
  3 + *
  4 + * Copyright (C) 2009-2012 Siemens AG
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License version 2
  8 + * as published by the Free Software Foundation.
  9 + *
  10 + * This program is distributed in the hope that it will be useful,
  11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 + * GNU General Public License for more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License along
  16 + * with this program; if not, write to the Free Software Foundation, Inc.,
  17 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18 + *
  19 + * Written by:
  20 + * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  21 + * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  22 + */
  23 +#include <linux/kernel.h>
  24 +#include <linux/module.h>
  25 +#include <linux/interrupt.h>
  26 +#include <linux/gpio.h>
  27 +#include <linux/delay.h>
  28 +#include <linux/mutex.h>
  29 +#include <linux/workqueue.h>
  30 +#include <linux/spinlock.h>
  31 +#include <linux/spi/spi.h>
  32 +#include <linux/spi/at86rf230.h>
  33 +#include <linux/skbuff.h>
  34 +
  35 +#include <net/mac802154.h>
  36 +#include <net/wpan-phy.h>
  37 +
  38 +struct at86rf230_local {
  39 + struct spi_device *spi;
  40 + int rstn, slp_tr, dig2;
  41 +
  42 + u8 part;
  43 + u8 vers;
  44 +
  45 + u8 buf[2];
  46 + struct mutex bmux;
  47 +
  48 + struct work_struct irqwork;
  49 + struct completion tx_complete;
  50 +
  51 + struct ieee802154_dev *dev;
  52 +
  53 + spinlock_t lock;
  54 + bool irq_disabled;
  55 + bool is_tx;
  56 +};
  57 +
  58 +#define RG_TRX_STATUS (0x01)
  59 +#define SR_TRX_STATUS 0x01, 0x1f, 0
  60 +#define SR_RESERVED_01_3 0x01, 0x20, 5
  61 +#define SR_CCA_STATUS 0x01, 0x40, 6
  62 +#define SR_CCA_DONE 0x01, 0x80, 7
  63 +#define RG_TRX_STATE (0x02)
  64 +#define SR_TRX_CMD 0x02, 0x1f, 0
  65 +#define SR_TRAC_STATUS 0x02, 0xe0, 5
  66 +#define RG_TRX_CTRL_0 (0x03)
  67 +#define SR_CLKM_CTRL 0x03, 0x07, 0
  68 +#define SR_CLKM_SHA_SEL 0x03, 0x08, 3
  69 +#define SR_PAD_IO_CLKM 0x03, 0x30, 4
  70 +#define SR_PAD_IO 0x03, 0xc0, 6
  71 +#define RG_TRX_CTRL_1 (0x04)
  72 +#define SR_IRQ_POLARITY 0x04, 0x01, 0
  73 +#define SR_IRQ_MASK_MODE 0x04, 0x02, 1
  74 +#define SR_SPI_CMD_MODE 0x04, 0x0c, 2
  75 +#define SR_RX_BL_CTRL 0x04, 0x10, 4
  76 +#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
  77 +#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6
  78 +#define SR_PA_EXT_EN 0x04, 0x80, 7
  79 +#define RG_PHY_TX_PWR (0x05)
  80 +#define SR_TX_PWR 0x05, 0x0f, 0
  81 +#define SR_PA_LT 0x05, 0x30, 4
  82 +#define SR_PA_BUF_LT 0x05, 0xc0, 6
  83 +#define RG_PHY_RSSI (0x06)
  84 +#define SR_RSSI 0x06, 0x1f, 0
  85 +#define SR_RND_VALUE 0x06, 0x60, 5
  86 +#define SR_RX_CRC_VALID 0x06, 0x80, 7
  87 +#define RG_PHY_ED_LEVEL (0x07)
  88 +#define SR_ED_LEVEL 0x07, 0xff, 0
  89 +#define RG_PHY_CC_CCA (0x08)
  90 +#define SR_CHANNEL 0x08, 0x1f, 0
  91 +#define SR_CCA_MODE 0x08, 0x60, 5
  92 +#define SR_CCA_REQUEST 0x08, 0x80, 7
  93 +#define RG_CCA_THRES (0x09)
  94 +#define SR_CCA_ED_THRES 0x09, 0x0f, 0
  95 +#define SR_RESERVED_09_1 0x09, 0xf0, 4
  96 +#define RG_RX_CTRL (0x0a)
  97 +#define SR_PDT_THRES 0x0a, 0x0f, 0
  98 +#define SR_RESERVED_0a_1 0x0a, 0xf0, 4
  99 +#define RG_SFD_VALUE (0x0b)
  100 +#define SR_SFD_VALUE 0x0b, 0xff, 0
  101 +#define RG_TRX_CTRL_2 (0x0c)
  102 +#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
  103 +#define SR_RESERVED_0c_2 0x0c, 0x7c, 2
  104 +#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
  105 +#define RG_ANT_DIV (0x0d)
  106 +#define SR_ANT_CTRL 0x0d, 0x03, 0
  107 +#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2
  108 +#define SR_ANT_DIV_EN 0x0d, 0x08, 3
  109 +#define SR_RESERVED_0d_2 0x0d, 0x70, 4
  110 +#define SR_ANT_SEL 0x0d, 0x80, 7
  111 +#define RG_IRQ_MASK (0x0e)
  112 +#define SR_IRQ_MASK 0x0e, 0xff, 0
  113 +#define RG_IRQ_STATUS (0x0f)
  114 +#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0
  115 +#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1
  116 +#define SR_IRQ_2_RX_START 0x0f, 0x04, 2
  117 +#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3
  118 +#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4
  119 +#define SR_IRQ_5_AMI 0x0f, 0x20, 5
  120 +#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6
  121 +#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7
  122 +#define RG_VREG_CTRL (0x10)
  123 +#define SR_RESERVED_10_6 0x10, 0x03, 0
  124 +#define SR_DVDD_OK 0x10, 0x04, 2
  125 +#define SR_DVREG_EXT 0x10, 0x08, 3
  126 +#define SR_RESERVED_10_3 0x10, 0x30, 4
  127 +#define SR_AVDD_OK 0x10, 0x40, 6
  128 +#define SR_AVREG_EXT 0x10, 0x80, 7
  129 +#define RG_BATMON (0x11)
  130 +#define SR_BATMON_VTH 0x11, 0x0f, 0
  131 +#define SR_BATMON_HR 0x11, 0x10, 4
  132 +#define SR_BATMON_OK 0x11, 0x20, 5
  133 +#define SR_RESERVED_11_1 0x11, 0xc0, 6
  134 +#define RG_XOSC_CTRL (0x12)
  135 +#define SR_XTAL_TRIM 0x12, 0x0f, 0
  136 +#define SR_XTAL_MODE 0x12, 0xf0, 4
  137 +#define RG_RX_SYN (0x15)
  138 +#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0
  139 +#define SR_RESERVED_15_2 0x15, 0x70, 4
  140 +#define SR_RX_PDT_DIS 0x15, 0x80, 7
  141 +#define RG_XAH_CTRL_1 (0x17)
  142 +#define SR_RESERVED_17_8 0x17, 0x01, 0
  143 +#define SR_AACK_PROM_MODE 0x17, 0x02, 1
  144 +#define SR_AACK_ACK_TIME 0x17, 0x04, 2
  145 +#define SR_RESERVED_17_5 0x17, 0x08, 3
  146 +#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
  147 +#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
  148 +#define SR_RESERVED_17_2 0x17, 0x40, 6
  149 +#define SR_RESERVED_17_1 0x17, 0x80, 7
  150 +#define RG_FTN_CTRL (0x18)
  151 +#define SR_RESERVED_18_2 0x18, 0x7f, 0
  152 +#define SR_FTN_START 0x18, 0x80, 7
  153 +#define RG_PLL_CF (0x1a)
  154 +#define SR_RESERVED_1a_2 0x1a, 0x7f, 0
  155 +#define SR_PLL_CF_START 0x1a, 0x80, 7
  156 +#define RG_PLL_DCU (0x1b)
  157 +#define SR_RESERVED_1b_3 0x1b, 0x3f, 0
  158 +#define SR_RESERVED_1b_2 0x1b, 0x40, 6
  159 +#define SR_PLL_DCU_START 0x1b, 0x80, 7
  160 +#define RG_PART_NUM (0x1c)
  161 +#define SR_PART_NUM 0x1c, 0xff, 0
  162 +#define RG_VERSION_NUM (0x1d)
  163 +#define SR_VERSION_NUM 0x1d, 0xff, 0
  164 +#define RG_MAN_ID_0 (0x1e)
  165 +#define SR_MAN_ID_0 0x1e, 0xff, 0
  166 +#define RG_MAN_ID_1 (0x1f)
  167 +#define SR_MAN_ID_1 0x1f, 0xff, 0
  168 +#define RG_SHORT_ADDR_0 (0x20)
  169 +#define SR_SHORT_ADDR_0 0x20, 0xff, 0
  170 +#define RG_SHORT_ADDR_1 (0x21)
  171 +#define SR_SHORT_ADDR_1 0x21, 0xff, 0
  172 +#define RG_PAN_ID_0 (0x22)
  173 +#define SR_PAN_ID_0 0x22, 0xff, 0
  174 +#define RG_PAN_ID_1 (0x23)
  175 +#define SR_PAN_ID_1 0x23, 0xff, 0
  176 +#define RG_IEEE_ADDR_0 (0x24)
  177 +#define SR_IEEE_ADDR_0 0x24, 0xff, 0
  178 +#define RG_IEEE_ADDR_1 (0x25)
  179 +#define SR_IEEE_ADDR_1 0x25, 0xff, 0
  180 +#define RG_IEEE_ADDR_2 (0x26)
  181 +#define SR_IEEE_ADDR_2 0x26, 0xff, 0
  182 +#define RG_IEEE_ADDR_3 (0x27)
  183 +#define SR_IEEE_ADDR_3 0x27, 0xff, 0
  184 +#define RG_IEEE_ADDR_4 (0x28)
  185 +#define SR_IEEE_ADDR_4 0x28, 0xff, 0
  186 +#define RG_IEEE_ADDR_5 (0x29)
  187 +#define SR_IEEE_ADDR_5 0x29, 0xff, 0
  188 +#define RG_IEEE_ADDR_6 (0x2a)
  189 +#define SR_IEEE_ADDR_6 0x2a, 0xff, 0
  190 +#define RG_IEEE_ADDR_7 (0x2b)
  191 +#define SR_IEEE_ADDR_7 0x2b, 0xff, 0
  192 +#define RG_XAH_CTRL_0 (0x2c)
  193 +#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0
  194 +#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1
  195 +#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4
  196 +#define RG_CSMA_SEED_0 (0x2d)
  197 +#define SR_CSMA_SEED_0 0x2d, 0xff, 0
  198 +#define RG_CSMA_SEED_1 (0x2e)
  199 +#define SR_CSMA_SEED_1 0x2e, 0x07, 0
  200 +#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3
  201 +#define SR_AACK_DIS_ACK 0x2e, 0x10, 4
  202 +#define SR_AACK_SET_PD 0x2e, 0x20, 5
  203 +#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6
  204 +#define RG_CSMA_BE (0x2f)
  205 +#define SR_MIN_BE 0x2f, 0x0f, 0
  206 +#define SR_MAX_BE 0x2f, 0xf0, 4
  207 +
  208 +#define CMD_REG 0x80
  209 +#define CMD_REG_MASK 0x3f
  210 +#define CMD_WRITE 0x40
  211 +#define CMD_FB 0x20
  212 +
  213 +#define IRQ_BAT_LOW (1 << 7)
  214 +#define IRQ_TRX_UR (1 << 6)
  215 +#define IRQ_AMI (1 << 5)
  216 +#define IRQ_CCA_ED (1 << 4)
  217 +#define IRQ_TRX_END (1 << 3)
  218 +#define IRQ_RX_START (1 << 2)
  219 +#define IRQ_PLL_UNL (1 << 1)
  220 +#define IRQ_PLL_LOCK (1 << 0)
  221 +
  222 +#define STATE_P_ON 0x00 /* BUSY */
  223 +#define STATE_BUSY_RX 0x01
  224 +#define STATE_BUSY_TX 0x02
  225 +#define STATE_FORCE_TRX_OFF 0x03
  226 +#define STATE_FORCE_TX_ON 0x04 /* IDLE */
  227 +/* 0x05 */ /* INVALID_PARAMETER */
  228 +#define STATE_RX_ON 0x06
  229 +/* 0x07 */ /* SUCCESS */
  230 +#define STATE_TRX_OFF 0x08
  231 +#define STATE_TX_ON 0x09
  232 +/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
  233 +#define STATE_SLEEP 0x0F
  234 +#define STATE_BUSY_RX_AACK 0x11
  235 +#define STATE_BUSY_TX_ARET 0x12
  236 +#define STATE_BUSY_RX_AACK_ON 0x16
  237 +#define STATE_BUSY_TX_ARET_ON 0x19
  238 +#define STATE_RX_ON_NOCLK 0x1C
  239 +#define STATE_RX_AACK_ON_NOCLK 0x1D
  240 +#define STATE_BUSY_RX_AACK_NOCLK 0x1E
  241 +#define STATE_TRANSITION_IN_PROGRESS 0x1F
  242 +
  243 +static int
  244 +__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
  245 +{
  246 + u8 *buf = lp->buf;
  247 + int status;
  248 + struct spi_message msg;
  249 + struct spi_transfer xfer = {
  250 + .len = 2,
  251 + .tx_buf = buf,
  252 + };
  253 +
  254 + buf[0] = (addr & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
  255 + buf[1] = data;
  256 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  257 + dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
  258 + spi_message_init(&msg);
  259 + spi_message_add_tail(&xfer, &msg);
  260 +
  261 + status = spi_sync(lp->spi, &msg);
  262 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  263 + if (msg.status)
  264 + status = msg.status;
  265 +
  266 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  267 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  268 + dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
  269 +
  270 + return status;
  271 +}
  272 +
  273 +static int
  274 +__at86rf230_read_subreg(struct at86rf230_local *lp,
  275 + u8 addr, u8 mask, int shift, u8 *data)
  276 +{
  277 + u8 *buf = lp->buf;
  278 + int status;
  279 + struct spi_message msg;
  280 + struct spi_transfer xfer = {
  281 + .len = 2,
  282 + .tx_buf = buf,
  283 + .rx_buf = buf,
  284 + };
  285 +
  286 + buf[0] = (addr & CMD_REG_MASK) | CMD_REG;
  287 + buf[1] = 0xff;
  288 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  289 + spi_message_init(&msg);
  290 + spi_message_add_tail(&xfer, &msg);
  291 +
  292 + status = spi_sync(lp->spi, &msg);
  293 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  294 + if (msg.status)
  295 + status = msg.status;
  296 +
  297 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  298 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  299 + dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
  300 +
  301 + if (status == 0)
  302 + *data = buf[1];
  303 +
  304 + return status;
  305 +}
  306 +
  307 +static int
  308 +at86rf230_read_subreg(struct at86rf230_local *lp,
  309 + u8 addr, u8 mask, int shift, u8 *data)
  310 +{
  311 + int status;
  312 +
  313 + mutex_lock(&lp->bmux);
  314 + status = __at86rf230_read_subreg(lp, addr, mask, shift, data);
  315 + mutex_unlock(&lp->bmux);
  316 +
  317 + return status;
  318 +}
  319 +
  320 +static int
  321 +at86rf230_write_subreg(struct at86rf230_local *lp,
  322 + u8 addr, u8 mask, int shift, u8 data)
  323 +{
  324 + int status;
  325 + u8 val;
  326 +
  327 + mutex_lock(&lp->bmux);
  328 + status = __at86rf230_read_subreg(lp, addr, 0xff, 0, &val);
  329 + if (status)
  330 + goto out;
  331 +
  332 + val &= ~mask;
  333 + val |= (data << shift) & mask;
  334 +
  335 + status = __at86rf230_write(lp, addr, val);
  336 +out:
  337 + mutex_unlock(&lp->bmux);
  338 +
  339 + return status;
  340 +}
  341 +
  342 +static int
  343 +at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len)
  344 +{
  345 + u8 *buf = lp->buf;
  346 + int status;
  347 + struct spi_message msg;
  348 + struct spi_transfer xfer_head = {
  349 + .len = 2,
  350 + .tx_buf = buf,
  351 +
  352 + };
  353 + struct spi_transfer xfer_buf = {
  354 + .len = len,
  355 + .tx_buf = data,
  356 + };
  357 +
  358 + mutex_lock(&lp->bmux);
  359 + buf[0] = CMD_WRITE | CMD_FB;
  360 + buf[1] = len + 2; /* 2 bytes for CRC that isn't written */
  361 +
  362 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  363 + dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
  364 +
  365 + spi_message_init(&msg);
  366 + spi_message_add_tail(&xfer_head, &msg);
  367 + spi_message_add_tail(&xfer_buf, &msg);
  368 +
  369 + status = spi_sync(lp->spi, &msg);
  370 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  371 + if (msg.status)
  372 + status = msg.status;
  373 +
  374 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  375 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  376 + dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
  377 +
  378 + mutex_unlock(&lp->bmux);
  379 + return status;
  380 +}
  381 +
  382 +static int
  383 +at86rf230_read_fbuf(struct at86rf230_local *lp, u8 *data, u8 *len, u8 *lqi)
  384 +{
  385 + u8 *buf = lp->buf;
  386 + int status;
  387 + struct spi_message msg;
  388 + struct spi_transfer xfer_head = {
  389 + .len = 2,
  390 + .tx_buf = buf,
  391 + .rx_buf = buf,
  392 + };
  393 + struct spi_transfer xfer_head1 = {
  394 + .len = 2,
  395 + .tx_buf = buf,
  396 + .rx_buf = buf,
  397 + };
  398 + struct spi_transfer xfer_buf = {
  399 + .len = 0,
  400 + .rx_buf = data,
  401 + };
  402 +
  403 + mutex_lock(&lp->bmux);
  404 +
  405 + buf[0] = CMD_FB;
  406 + buf[1] = 0x00;
  407 +
  408 + spi_message_init(&msg);
  409 + spi_message_add_tail(&xfer_head, &msg);
  410 +
  411 + status = spi_sync(lp->spi, &msg);
  412 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  413 +
  414 + xfer_buf.len = *(buf + 1) + 1;
  415 + *len = buf[1];
  416 +
  417 + buf[0] = CMD_FB;
  418 + buf[1] = 0x00;
  419 +
  420 + spi_message_init(&msg);
  421 + spi_message_add_tail(&xfer_head1, &msg);
  422 + spi_message_add_tail(&xfer_buf, &msg);
  423 +
  424 + status = spi_sync(lp->spi, &msg);
  425 +
  426 + if (msg.status)
  427 + status = msg.status;
  428 +
  429 + dev_vdbg(&lp->spi->dev, "status = %d\n", status);
  430 + dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
  431 + dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
  432 +
  433 + if (status) {
  434 + if (lqi && (*len > lp->buf[1]))
  435 + *lqi = data[lp->buf[1]];
  436 + }
  437 + mutex_unlock(&lp->bmux);
  438 +
  439 + return status;
  440 +}
  441 +
  442 +static int
  443 +at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
  444 +{
  445 + might_sleep();
  446 + BUG_ON(!level);
  447 + *level = 0xbe;
  448 + return 0;
  449 +}
  450 +
  451 +static int
  452 +at86rf230_state(struct ieee802154_dev *dev, int state)
  453 +{
  454 + struct at86rf230_local *lp = dev->priv;
  455 + int rc;
  456 + u8 val;
  457 + u8 desired_status;
  458 +
  459 + might_sleep();
  460 +
  461 + if (state == STATE_FORCE_TX_ON)
  462 + desired_status = STATE_TX_ON;
  463 + else if (state == STATE_FORCE_TRX_OFF)
  464 + desired_status = STATE_TRX_OFF;
  465 + else
  466 + desired_status = state;
  467 +
  468 + do {
  469 + rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
  470 + if (rc)
  471 + goto err;
  472 + } while (val == STATE_TRANSITION_IN_PROGRESS);
  473 +
  474 + if (val == desired_status)
  475 + return 0;
  476 +
  477 + /* state is equal to phy states */
  478 + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, state);
  479 + if (rc)
  480 + goto err;
  481 +
  482 + do {
  483 + rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
  484 + if (rc)
  485 + goto err;
  486 + } while (val == STATE_TRANSITION_IN_PROGRESS);
  487 +
  488 +
  489 + if (val == desired_status)
  490 + return 0;
  491 +
  492 + pr_err("unexpected state change: %d, asked for %d\n", val, state);
  493 + return -EBUSY;
  494 +
  495 +err:
  496 + pr_err("error: %d\n", rc);
  497 + return rc;
  498 +}
  499 +
  500 +static int
  501 +at86rf230_start(struct ieee802154_dev *dev)
  502 +{
  503 + struct at86rf230_local *lp = dev->priv;
  504 + u8 rc;
  505 +
  506 + rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1);
  507 + if (rc)
  508 + return rc;
  509 +
  510 + return at86rf230_state(dev, STATE_RX_ON);
  511 +}
  512 +
  513 +static void
  514 +at86rf230_stop(struct ieee802154_dev *dev)
  515 +{
  516 + at86rf230_state(dev, STATE_FORCE_TRX_OFF);
  517 +}
  518 +
  519 +static int
  520 +at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
  521 +{
  522 + struct at86rf230_local *lp = dev->priv;
  523 + int rc;
  524 +
  525 + might_sleep();
  526 +
  527 + if (page != 0 || channel < 11 || channel > 26) {
  528 + WARN_ON(1);
  529 + return -EINVAL;
  530 + }
  531 +
  532 + rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
  533 + msleep(1); /* Wait for PLL */
  534 + dev->phy->current_channel = channel;
  535 +
  536 + return 0;
  537 +}
  538 +
  539 +static int
  540 +at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
  541 +{
  542 + struct at86rf230_local *lp = dev->priv;
  543 + int rc;
  544 + unsigned long flags;
  545 +
  546 + might_sleep();
  547 +
  548 + rc = at86rf230_state(dev, STATE_FORCE_TX_ON);
  549 + if (rc)
  550 + goto err;
  551 +
  552 + spin_lock_irqsave(&lp->lock, flags);
  553 + lp->is_tx = 1;
  554 + INIT_COMPLETION(lp->tx_complete);
  555 + spin_unlock_irqrestore(&lp->lock, flags);
  556 +
  557 + rc = at86rf230_write_fbuf(lp, skb->data, skb->len);
  558 + if (rc)
  559 + goto err_rx;
  560 +
  561 + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
  562 + if (rc)
  563 + goto err_rx;
  564 +
  565 + rc = wait_for_completion_interruptible(&lp->tx_complete);
  566 + if (rc < 0)
  567 + goto err_rx;
  568 +
  569 + rc = at86rf230_start(dev);
  570 +
  571 + return rc;
  572 +
  573 +err_rx:
  574 + at86rf230_start(dev);
  575 +err:
  576 + pr_err("error: %d\n", rc);
  577 +
  578 + spin_lock_irqsave(&lp->lock, flags);
  579 + lp->is_tx = 0;
  580 + spin_unlock_irqrestore(&lp->lock, flags);
  581 +
  582 + return rc;
  583 +}
  584 +
  585 +static int at86rf230_rx(struct at86rf230_local *lp)
  586 +{
  587 + u8 len = 128, lqi = 0;
  588 + int rc;
  589 + struct sk_buff *skb;
  590 +
  591 + skb = alloc_skb(len, GFP_KERNEL);
  592 +
  593 + if (!skb)
  594 + return -ENOMEM;
  595 +
  596 + if (at86rf230_write_subreg(lp, SR_RX_PDT_DIS, 1) ||
  597 + at86rf230_read_fbuf(lp, skb_put(skb, len), &len, &lqi) ||
  598 + at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1) ||
  599 + at86rf230_write_subreg(lp, SR_RX_PDT_DIS, 0)) {
  600 + goto err;
  601 + }
  602 +
  603 + if (len < 2)
  604 + goto err;
  605 +
  606 + skb_trim(skb, len - 2); /* We do not put CRC into the frame */
  607 +
  608 + ieee802154_rx_irqsafe(lp->dev, skb, lqi);
  609 +
  610 + dev_dbg(&lp->spi->dev, "READ_FBUF: %d %d %x\n", rc, len, lqi);
  611 +
  612 + return 0;
  613 +err:
  614 + pr_debug("received frame is too small\n");
  615 +
  616 + kfree_skb(skb);
  617 + return -EINVAL;
  618 +}
  619 +
  620 +static struct ieee802154_ops at86rf230_ops = {
  621 + .owner = THIS_MODULE,
  622 + .xmit = at86rf230_xmit,
  623 + .ed = at86rf230_ed,
  624 + .set_channel = at86rf230_channel,
  625 + .start = at86rf230_start,
  626 + .stop = at86rf230_stop,
  627 +};
  628 +
  629 +static void at86rf230_irqwork(struct work_struct *work)
  630 +{
  631 + struct at86rf230_local *lp =
  632 + container_of(work, struct at86rf230_local, irqwork);
  633 + u8 status = 0, val;
  634 + int rc;
  635 + unsigned long flags;
  636 +
  637 + spin_lock_irqsave(&lp->lock, flags);
  638 + rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val);
  639 + status |= val;
  640 +
  641 + status &= ~IRQ_PLL_LOCK; /* ignore */
  642 + status &= ~IRQ_RX_START; /* ignore */
  643 + status &= ~IRQ_AMI; /* ignore */
  644 + status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
  645 +
  646 + if (status & IRQ_TRX_END) {
  647 + status &= ~IRQ_TRX_END;
  648 + if (lp->is_tx) {
  649 + lp->is_tx = 0;
  650 + complete(&lp->tx_complete);
  651 + } else {
  652 + at86rf230_rx(lp);
  653 + }
  654 + }
  655 +
  656 + if (lp->irq_disabled) {
  657 + lp->irq_disabled = 0;
  658 + enable_irq(lp->spi->irq);
  659 + }
  660 + spin_unlock_irqrestore(&lp->lock, flags);
  661 +}
  662 +
  663 +static irqreturn_t at86rf230_isr(int irq, void *data)
  664 +{
  665 + struct at86rf230_local *lp = data;
  666 +
  667 + spin_lock(&lp->lock);
  668 + if (!lp->irq_disabled) {
  669 + disable_irq_nosync(irq);
  670 + lp->irq_disabled = 1;
  671 + }
  672 + spin_unlock(&lp->lock);
  673 +
  674 + schedule_work(&lp->irqwork);
  675 +
  676 + return IRQ_HANDLED;
  677 +}
  678 +
  679 +
  680 +static int at86rf230_hw_init(struct at86rf230_local *lp)
  681 +{
  682 + u8 status;
  683 + int rc;
  684 +
  685 + rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
  686 + if (rc)
  687 + return rc;
  688 +
  689 + dev_info(&lp->spi->dev, "Status: %02x\n", status);
  690 + if (status == STATE_P_ON) {
  691 + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
  692 + if (rc)
  693 + return rc;
  694 + msleep(1);
  695 + rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
  696 + if (rc)
  697 + return rc;
  698 + dev_info(&lp->spi->dev, "Status: %02x\n", status);
  699 + }
  700 +
  701 + rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR |
  702 + * IRQ_CCA_ED |
  703 + * IRQ_TRX_END |
  704 + * IRQ_PLL_UNL |
  705 + * IRQ_PLL_LOCK
  706 + */
  707 + if (rc)
  708 + return rc;
  709 +
  710 + /* CLKM changes are applied immediately */
  711 + rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
  712 + if (rc)
  713 + return rc;
  714 +
  715 + /* Turn CLKM Off */
  716 + rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00);
  717 + if (rc)
  718 + return rc;
  719 + /* Wait the next SLEEP cycle */
  720 + msleep(100);
  721 +
  722 + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
  723 + if (rc)
  724 + return rc;
  725 + msleep(1);
  726 +
  727 + rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
  728 + if (rc)
  729 + return rc;
  730 + dev_info(&lp->spi->dev, "Status: %02x\n", status);
  731 +
  732 + rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
  733 + if (rc)
  734 + return rc;
  735 + if (!status) {
  736 + dev_err(&lp->spi->dev, "DVDD error\n");
  737 + return -EINVAL;
  738 + }
  739 +
  740 + rc = at86rf230_read_subreg(lp, SR_AVDD_OK, &status);
  741 + if (rc)
  742 + return rc;
  743 + if (!status) {
  744 + dev_err(&lp->spi->dev, "AVDD error\n");
  745 + return -EINVAL;
  746 + }
  747 +
  748 + return 0;
  749 +}
  750 +
  751 +static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
  752 +{
  753 + return 0;
  754 +}
  755 +
  756 +static int at86rf230_resume(struct spi_device *spi)
  757 +{
  758 + return 0;
  759 +}
  760 +
  761 +static int at86rf230_fill_data(struct spi_device *spi)
  762 +{
  763 + struct at86rf230_local *lp = spi_get_drvdata(spi);
  764 + struct at86rf230_platform_data *pdata = spi->dev.platform_data;
  765 +
  766 + if (!pdata) {
  767 + dev_err(&spi->dev, "no platform_data\n");
  768 + return -EINVAL;
  769 + }
  770 +
  771 + lp->rstn = pdata->rstn;
  772 + lp->slp_tr = pdata->slp_tr;
  773 + lp->dig2 = pdata->dig2;
  774 +
  775 + return 0;
  776 +}
  777 +
  778 +static int __devinit at86rf230_probe(struct spi_device *spi)
  779 +{
  780 + struct ieee802154_dev *dev;
  781 + struct at86rf230_local *lp;
  782 + u8 man_id_0, man_id_1;
  783 + int rc;
  784 + const char *chip;
  785 + int supported = 0;
  786 +
  787 + if (!spi->irq) {
  788 + dev_err(&spi->dev, "no IRQ specified\n");
  789 + return -EINVAL;
  790 + }
  791 +
  792 + dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
  793 + if (!dev)
  794 + return -ENOMEM;
  795 +
  796 + lp = dev->priv;
  797 + lp->dev = dev;
  798 +
  799 + lp->spi = spi;
  800 +
  801 + dev->priv = lp;
  802 + dev->parent = &spi->dev;
  803 + dev->extra_tx_headroom = 0;
  804 + /* We do support only 2.4 Ghz */
  805 + dev->phy->channels_supported[0] = 0x7FFF800;
  806 + dev->flags = IEEE802154_HW_OMIT_CKSUM;
  807 +
  808 + mutex_init(&lp->bmux);
  809 + INIT_WORK(&lp->irqwork, at86rf230_irqwork);
  810 + spin_lock_init(&lp->lock);
  811 + init_completion(&lp->tx_complete);
  812 +
  813 + spi_set_drvdata(spi, lp);
  814 +
  815 + rc = at86rf230_fill_data(spi);
  816 + if (rc)
  817 + goto err_fill;
  818 +
  819 + rc = gpio_request(lp->rstn, "rstn");
  820 + if (rc)
  821 + goto err_rstn;
  822 +
  823 + if (gpio_is_valid(lp->slp_tr)) {
  824 + rc = gpio_request(lp->slp_tr, "slp_tr");
  825 + if (rc)
  826 + goto err_slp_tr;
  827 + }
  828 +
  829 + rc = gpio_direction_output(lp->rstn, 1);
  830 + if (rc)
  831 + goto err_gpio_dir;
  832 +
  833 + if (gpio_is_valid(lp->slp_tr)) {
  834 + rc = gpio_direction_output(lp->slp_tr, 0);
  835 + if (rc)
  836 + goto err_gpio_dir;
  837 + }
  838 +
  839 + /* Reset */
  840 + msleep(1);
  841 + gpio_set_value(lp->rstn, 0);
  842 + msleep(1);
  843 + gpio_set_value(lp->rstn, 1);
  844 + msleep(1);
  845 +
  846 + rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
  847 + if (rc)
  848 + goto err_gpio_dir;
  849 + rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
  850 + if (rc)
  851 + goto err_gpio_dir;
  852 +
  853 + if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
  854 + dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
  855 + man_id_1, man_id_0);
  856 + rc = -EINVAL;
  857 + goto err_gpio_dir;
  858 + }
  859 +
  860 + rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
  861 + if (rc)
  862 + goto err_gpio_dir;
  863 +
  864 + rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
  865 + if (rc)
  866 + goto err_gpio_dir;
  867 +
  868 + switch (lp->part) {
  869 + case 2:
  870 + chip = "at86rf230";
  871 + /* supported = 1; FIXME: should be easy to support; */
  872 + break;
  873 + case 3:
  874 + chip = "at86rf231";
  875 + supported = 1;
  876 + break;
  877 + default:
  878 + chip = "UNKNOWN";
  879 + break;
  880 + }
  881 +
  882 + dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
  883 + if (!supported) {
  884 + rc = -ENOTSUPP;
  885 + goto err_gpio_dir;
  886 + }
  887 +
  888 + rc = at86rf230_hw_init(lp);
  889 + if (rc)
  890 + goto err_gpio_dir;
  891 +
  892 + rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED,
  893 + dev_name(&spi->dev), lp);
  894 + if (rc)
  895 + goto err_gpio_dir;
  896 +
  897 + rc = ieee802154_register_device(lp->dev);
  898 + if (rc)
  899 + goto err_irq;
  900 +
  901 + return rc;
  902 +
  903 + ieee802154_unregister_device(lp->dev);
  904 +err_irq:
  905 + free_irq(spi->irq, lp);
  906 + flush_work(&lp->irqwork);
  907 +err_gpio_dir:
  908 + if (gpio_is_valid(lp->slp_tr))
  909 + gpio_free(lp->slp_tr);
  910 +err_slp_tr:
  911 + gpio_free(lp->rstn);
  912 +err_rstn:
  913 +err_fill:
  914 + spi_set_drvdata(spi, NULL);
  915 + mutex_destroy(&lp->bmux);
  916 + ieee802154_free_device(lp->dev);
  917 + return rc;
  918 +}
  919 +
  920 +static int __devexit at86rf230_remove(struct spi_device *spi)
  921 +{
  922 + struct at86rf230_local *lp = spi_get_drvdata(spi);
  923 +
  924 + ieee802154_unregister_device(lp->dev);
  925 +
  926 + free_irq(spi->irq, lp);
  927 + flush_work(&lp->irqwork);
  928 +
  929 + if (gpio_is_valid(lp->slp_tr))
  930 + gpio_free(lp->slp_tr);
  931 + gpio_free(lp->rstn);
  932 +
  933 + spi_set_drvdata(spi, NULL);
  934 + mutex_destroy(&lp->bmux);
  935 + ieee802154_free_device(lp->dev);
  936 +
  937 + dev_dbg(&spi->dev, "unregistered at86rf230\n");
  938 + return 0;
  939 +}
  940 +
  941 +static struct spi_driver at86rf230_driver = {
  942 + .driver = {
  943 + .name = "at86rf230",
  944 + .owner = THIS_MODULE,
  945 + },
  946 + .probe = at86rf230_probe,
  947 + .remove = __devexit_p(at86rf230_remove),
  948 + .suspend = at86rf230_suspend,
  949 + .resume = at86rf230_resume,
  950 +};
  951 +
  952 +static int __init at86rf230_init(void)
  953 +{
  954 + return spi_register_driver(&at86rf230_driver);
  955 +}
  956 +module_init(at86rf230_init);
  957 +
  958 +static void __exit at86rf230_exit(void)
  959 +{
  960 + spi_unregister_driver(&at86rf230_driver);
  961 +}
  962 +module_exit(at86rf230_exit);
  963 +
  964 +MODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
  965 +MODULE_LICENSE("GPL v2");
include/linux/spi/at86rf230.h
  1 +/*
  2 + * AT86RF230/RF231 driver
  3 + *
  4 + * Copyright (C) 2009-2012 Siemens AG
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License version 2
  8 + * as published by the Free Software Foundation.
  9 + *
  10 + * This program is distributed in the hope that it will be useful,
  11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 + * GNU General Public License for more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License along
  16 + * with this program; if not, write to the Free Software Foundation, Inc.,
  17 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18 + *
  19 + * Written by:
  20 + * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
  21 + */
  22 +#ifndef AT86RF230_H
  23 +#define AT86RF230_H
  24 +
  25 +struct at86rf230_platform_data {
  26 + int rstn;
  27 + int slp_tr;
  28 + int dig2;
  29 +};
  30 +
  31 +#endif