diff options
author | Alan Ott <alan@signal11.us> | 2012-09-02 11:44:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-04 14:43:55 -0400 |
commit | 3731a334c012ed825a87e1f152bbf980f79dabb2 (patch) | |
tree | 15bd34887ee32e1fd9e8e3810303fb511fca0524 /drivers/net | |
parent | 798b2cbf9227b1bd7d37ae9af4d9c750e6f4de9c (diff) |
ieee802154: MRF24J40 driver
Driver for the Microchip MRF24J40 802.15.4 WPAN module.
Signed-off-by: Alan Ott <alan@signal11.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ieee802154/Kconfig | 11 | ||||
-rw-r--r-- | drivers/net/ieee802154/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ieee802154/mrf24j40.c | 767 |
3 files changed, 779 insertions, 0 deletions
diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 1fc4eefc20ed..08ae4655423a 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig | |||
@@ -34,3 +34,14 @@ config IEEE802154_AT86RF230 | |||
34 | depends on IEEE802154_DRIVERS && MAC802154 | 34 | depends on IEEE802154_DRIVERS && MAC802154 |
35 | tristate "AT86RF230/231 transceiver driver" | 35 | tristate "AT86RF230/231 transceiver driver" |
36 | depends on SPI | 36 | depends on SPI |
37 | |||
38 | config IEEE802154_MRF24J40 | ||
39 | tristate "Microchip MRF24J40 transceiver driver" | ||
40 | depends on IEEE802154_DRIVERS && MAC802154 | ||
41 | depends on SPI | ||
42 | ---help--- | ||
43 | Say Y here to enable the MRF24J20 SPI 802.15.4 wireless | ||
44 | controller. | ||
45 | |||
46 | This driver can also be built as a module. To do so, say M here. | ||
47 | the module will be called 'mrf24j40'. | ||
diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile index 4f4371d3aa7d..abb0c08decb0 100644 --- a/drivers/net/ieee802154/Makefile +++ b/drivers/net/ieee802154/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o | 1 | obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o |
2 | obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o | 2 | obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o |
3 | obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o | 3 | obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o |
4 | obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o | ||
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c new file mode 100644 index 000000000000..0e53d4f431d2 --- /dev/null +++ b/drivers/net/ieee802154/mrf24j40.c | |||
@@ -0,0 +1,767 @@ | |||
1 | /* | ||
2 | * Driver for Microchip MRF24J40 802.15.4 Wireless-PAN Networking controller | ||
3 | * | ||
4 | * Copyright (C) 2012 Alan Ott <alan@signal11.us> | ||
5 | * Signal 11 Software | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/spi/spi.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <net/wpan-phy.h> | ||
26 | #include <net/mac802154.h> | ||
27 | |||
28 | /* MRF24J40 Short Address Registers */ | ||
29 | #define REG_RXMCR 0x00 /* Receive MAC control */ | ||
30 | #define REG_PANIDL 0x01 /* PAN ID (low) */ | ||
31 | #define REG_PANIDH 0x02 /* PAN ID (high) */ | ||
32 | #define REG_SADRL 0x03 /* Short address (low) */ | ||
33 | #define REG_SADRH 0x04 /* Short address (high) */ | ||
34 | #define REG_EADR0 0x05 /* Long address (low) (high is EADR7) */ | ||
35 | #define REG_TXMCR 0x11 /* Transmit MAC control */ | ||
36 | #define REG_PACON0 0x16 /* Power Amplifier Control */ | ||
37 | #define REG_PACON1 0x17 /* Power Amplifier Control */ | ||
38 | #define REG_PACON2 0x18 /* Power Amplifier Control */ | ||
39 | #define REG_TXNCON 0x1B /* Transmit Normal FIFO Control */ | ||
40 | #define REG_TXSTAT 0x24 /* TX MAC Status Register */ | ||
41 | #define REG_SOFTRST 0x2A /* Soft Reset */ | ||
42 | #define REG_TXSTBL 0x2E /* TX Stabilization */ | ||
43 | #define REG_INTSTAT 0x31 /* Interrupt Status */ | ||
44 | #define REG_INTCON 0x32 /* Interrupt Control */ | ||
45 | #define REG_RFCTL 0x36 /* RF Control Mode Register */ | ||
46 | #define REG_BBREG1 0x39 /* Baseband Registers */ | ||
47 | #define REG_BBREG2 0x3A /* */ | ||
48 | #define REG_BBREG6 0x3E /* */ | ||
49 | #define REG_CCAEDTH 0x3F /* Energy Detection Threshold */ | ||
50 | |||
51 | /* MRF24J40 Long Address Registers */ | ||
52 | #define REG_RFCON0 0x200 /* RF Control Registers */ | ||
53 | #define REG_RFCON1 0x201 | ||
54 | #define REG_RFCON2 0x202 | ||
55 | #define REG_RFCON3 0x203 | ||
56 | #define REG_RFCON5 0x205 | ||
57 | #define REG_RFCON6 0x206 | ||
58 | #define REG_RFCON7 0x207 | ||
59 | #define REG_RFCON8 0x208 | ||
60 | #define REG_RSSI 0x210 | ||
61 | #define REG_SLPCON0 0x211 /* Sleep Clock Control Registers */ | ||
62 | #define REG_SLPCON1 0x220 | ||
63 | #define REG_WAKETIMEL 0x222 /* Wake-up Time Match Value Low */ | ||
64 | #define REG_WAKETIMEH 0x223 /* Wake-up Time Match Value High */ | ||
65 | #define REG_RX_FIFO 0x300 /* Receive FIFO */ | ||
66 | |||
67 | /* Device configuration: Only channels 11-26 on page 0 are supported. */ | ||
68 | #define MRF24J40_CHAN_MIN 11 | ||
69 | #define MRF24J40_CHAN_MAX 26 | ||
70 | #define CHANNEL_MASK (((u32)1 << (MRF24J40_CHAN_MAX + 1)) \ | ||
71 | - ((u32)1 << MRF24J40_CHAN_MIN)) | ||
72 | |||
73 | #define TX_FIFO_SIZE 128 /* From datasheet */ | ||
74 | #define RX_FIFO_SIZE 144 /* From datasheet */ | ||
75 | #define SET_CHANNEL_DELAY_US 192 /* From datasheet */ | ||
76 | |||
77 | /* Device Private Data */ | ||
78 | struct mrf24j40 { | ||
79 | struct spi_device *spi; | ||
80 | struct ieee802154_dev *dev; | ||
81 | |||
82 | struct mutex buffer_mutex; /* only used to protect buf */ | ||
83 | struct completion tx_complete; | ||
84 | struct work_struct irqwork; | ||
85 | u8 *buf; /* 3 bytes. Used for SPI single-register transfers. */ | ||
86 | }; | ||
87 | |||
88 | /* Read/Write SPI Commands for Short and Long Address registers. */ | ||
89 | #define MRF24J40_READSHORT(reg) ((reg) << 1) | ||
90 | #define MRF24J40_WRITESHORT(reg) ((reg) << 1 | 1) | ||
91 | #define MRF24J40_READLONG(reg) (1 << 15 | (reg) << 5) | ||
92 | #define MRF24J40_WRITELONG(reg) (1 << 15 | (reg) << 5 | 1 << 4) | ||
93 | |||
94 | /* Maximum speed to run the device at. TODO: Get the real max value from | ||
95 | * someone at Microchip since it isn't in the datasheet. */ | ||
96 | #define MAX_SPI_SPEED_HZ 1000000 | ||
97 | |||
98 | #define printdev(X) (&X->spi->dev) | ||
99 | |||
100 | static int write_short_reg(struct mrf24j40 *devrec, u8 reg, u8 value) | ||
101 | { | ||
102 | int ret; | ||
103 | struct spi_message msg; | ||
104 | struct spi_transfer xfer = { | ||
105 | .len = 2, | ||
106 | .tx_buf = devrec->buf, | ||
107 | .rx_buf = devrec->buf, | ||
108 | }; | ||
109 | |||
110 | spi_message_init(&msg); | ||
111 | spi_message_add_tail(&xfer, &msg); | ||
112 | |||
113 | mutex_lock(&devrec->buffer_mutex); | ||
114 | devrec->buf[0] = MRF24J40_WRITESHORT(reg); | ||
115 | devrec->buf[1] = value; | ||
116 | |||
117 | ret = spi_sync(devrec->spi, &msg); | ||
118 | if (ret) | ||
119 | dev_err(printdev(devrec), | ||
120 | "SPI write Failed for short register 0x%hhx\n", reg); | ||
121 | |||
122 | mutex_unlock(&devrec->buffer_mutex); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | static int read_short_reg(struct mrf24j40 *devrec, u8 reg, u8 *val) | ||
127 | { | ||
128 | int ret = -1; | ||
129 | struct spi_message msg; | ||
130 | struct spi_transfer xfer = { | ||
131 | .len = 2, | ||
132 | .tx_buf = devrec->buf, | ||
133 | .rx_buf = devrec->buf, | ||
134 | }; | ||
135 | |||
136 | spi_message_init(&msg); | ||
137 | spi_message_add_tail(&xfer, &msg); | ||
138 | |||
139 | mutex_lock(&devrec->buffer_mutex); | ||
140 | devrec->buf[0] = MRF24J40_READSHORT(reg); | ||
141 | devrec->buf[1] = 0; | ||
142 | |||
143 | ret = spi_sync(devrec->spi, &msg); | ||
144 | if (ret) | ||
145 | dev_err(printdev(devrec), | ||
146 | "SPI read Failed for short register 0x%hhx\n", reg); | ||
147 | else | ||
148 | *val = devrec->buf[1]; | ||
149 | |||
150 | mutex_unlock(&devrec->buffer_mutex); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int read_long_reg(struct mrf24j40 *devrec, u16 reg, u8 *value) | ||
155 | { | ||
156 | int ret; | ||
157 | u16 cmd; | ||
158 | struct spi_message msg; | ||
159 | struct spi_transfer xfer = { | ||
160 | .len = 3, | ||
161 | .tx_buf = devrec->buf, | ||
162 | .rx_buf = devrec->buf, | ||
163 | }; | ||
164 | |||
165 | spi_message_init(&msg); | ||
166 | spi_message_add_tail(&xfer, &msg); | ||
167 | |||
168 | cmd = MRF24J40_READLONG(reg); | ||
169 | mutex_lock(&devrec->buffer_mutex); | ||
170 | devrec->buf[0] = cmd >> 8 & 0xff; | ||
171 | devrec->buf[1] = cmd & 0xff; | ||
172 | devrec->buf[2] = 0; | ||
173 | |||
174 | ret = spi_sync(devrec->spi, &msg); | ||
175 | if (ret) | ||
176 | dev_err(printdev(devrec), | ||
177 | "SPI read Failed for long register 0x%hx\n", reg); | ||
178 | else | ||
179 | *value = devrec->buf[2]; | ||
180 | |||
181 | mutex_unlock(&devrec->buffer_mutex); | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | static int write_long_reg(struct mrf24j40 *devrec, u16 reg, u8 val) | ||
186 | { | ||
187 | int ret; | ||
188 | u16 cmd; | ||
189 | struct spi_message msg; | ||
190 | struct spi_transfer xfer = { | ||
191 | .len = 3, | ||
192 | .tx_buf = devrec->buf, | ||
193 | .rx_buf = devrec->buf, | ||
194 | }; | ||
195 | |||
196 | spi_message_init(&msg); | ||
197 | spi_message_add_tail(&xfer, &msg); | ||
198 | |||
199 | cmd = MRF24J40_WRITELONG(reg); | ||
200 | mutex_lock(&devrec->buffer_mutex); | ||
201 | devrec->buf[0] = cmd >> 8 & 0xff; | ||
202 | devrec->buf[1] = cmd & 0xff; | ||
203 | devrec->buf[2] = val; | ||
204 | |||
205 | ret = spi_sync(devrec->spi, &msg); | ||
206 | if (ret) | ||
207 | dev_err(printdev(devrec), | ||
208 | "SPI write Failed for long register 0x%hx\n", reg); | ||
209 | |||
210 | mutex_unlock(&devrec->buffer_mutex); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | /* This function relies on an undocumented write method. Once a write command | ||
215 | and address is set, as many bytes of data as desired can be clocked into | ||
216 | the device. The datasheet only shows setting one byte at a time. */ | ||
217 | static int write_tx_buf(struct mrf24j40 *devrec, u16 reg, | ||
218 | const u8 *data, size_t length) | ||
219 | { | ||
220 | int ret; | ||
221 | u16 cmd; | ||
222 | u8 lengths[2]; | ||
223 | struct spi_message msg; | ||
224 | struct spi_transfer addr_xfer = { | ||
225 | .len = 2, | ||
226 | .tx_buf = devrec->buf, | ||
227 | }; | ||
228 | struct spi_transfer lengths_xfer = { | ||
229 | .len = 2, | ||
230 | .tx_buf = &lengths, /* TODO: Is DMA really required for SPI? */ | ||
231 | }; | ||
232 | struct spi_transfer data_xfer = { | ||
233 | .len = length, | ||
234 | .tx_buf = data, | ||
235 | }; | ||
236 | |||
237 | /* Range check the length. 2 bytes are used for the length fields.*/ | ||
238 | if (length > TX_FIFO_SIZE-2) { | ||
239 | dev_err(printdev(devrec), "write_tx_buf() was passed too large a buffer. Performing short write.\n"); | ||
240 | length = TX_FIFO_SIZE-2; | ||
241 | } | ||
242 | |||
243 | spi_message_init(&msg); | ||
244 | spi_message_add_tail(&addr_xfer, &msg); | ||
245 | spi_message_add_tail(&lengths_xfer, &msg); | ||
246 | spi_message_add_tail(&data_xfer, &msg); | ||
247 | |||
248 | cmd = MRF24J40_WRITELONG(reg); | ||
249 | mutex_lock(&devrec->buffer_mutex); | ||
250 | devrec->buf[0] = cmd >> 8 & 0xff; | ||
251 | devrec->buf[1] = cmd & 0xff; | ||
252 | lengths[0] = 0x0; /* Header Length. Set to 0 for now. TODO */ | ||
253 | lengths[1] = length; /* Total length */ | ||
254 | |||
255 | ret = spi_sync(devrec->spi, &msg); | ||
256 | if (ret) | ||
257 | dev_err(printdev(devrec), "SPI write Failed for TX buf\n"); | ||
258 | |||
259 | mutex_unlock(&devrec->buffer_mutex); | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, | ||
264 | u8 *data, u8 *len, u8 *lqi) | ||
265 | { | ||
266 | u8 rx_len; | ||
267 | u8 addr[2]; | ||
268 | u8 lqi_rssi[2]; | ||
269 | u16 cmd; | ||
270 | int ret; | ||
271 | struct spi_message msg; | ||
272 | struct spi_transfer addr_xfer = { | ||
273 | .len = 2, | ||
274 | .tx_buf = &addr, | ||
275 | }; | ||
276 | struct spi_transfer data_xfer = { | ||
277 | .len = 0x0, /* set below */ | ||
278 | .rx_buf = data, | ||
279 | }; | ||
280 | struct spi_transfer status_xfer = { | ||
281 | .len = 2, | ||
282 | .rx_buf = &lqi_rssi, | ||
283 | }; | ||
284 | |||
285 | /* Get the length of the data in the RX FIFO. The length in this | ||
286 | * register exclues the 1-byte length field at the beginning. */ | ||
287 | ret = read_long_reg(devrec, REG_RX_FIFO, &rx_len); | ||
288 | if (ret) | ||
289 | goto out; | ||
290 | |||
291 | /* Range check the RX FIFO length, accounting for the one-byte | ||
292 | * length field at the begining. */ | ||
293 | if (rx_len > RX_FIFO_SIZE-1) { | ||
294 | dev_err(printdev(devrec), "Invalid length read from device. Performing short read.\n"); | ||
295 | rx_len = RX_FIFO_SIZE-1; | ||
296 | } | ||
297 | |||
298 | if (rx_len > *len) { | ||
299 | /* Passed in buffer wasn't big enough. Should never happen. */ | ||
300 | dev_err(printdev(devrec), "Buffer not big enough. Performing short read\n"); | ||
301 | rx_len = *len; | ||
302 | } | ||
303 | |||
304 | /* Set up the commands to read the data. */ | ||
305 | cmd = MRF24J40_READLONG(REG_RX_FIFO+1); | ||
306 | addr[0] = cmd >> 8 & 0xff; | ||
307 | addr[1] = cmd & 0xff; | ||
308 | data_xfer.len = rx_len; | ||
309 | |||
310 | spi_message_init(&msg); | ||
311 | spi_message_add_tail(&addr_xfer, &msg); | ||
312 | spi_message_add_tail(&data_xfer, &msg); | ||
313 | spi_message_add_tail(&status_xfer, &msg); | ||
314 | |||
315 | ret = spi_sync(devrec->spi, &msg); | ||
316 | if (ret) { | ||
317 | dev_err(printdev(devrec), "SPI RX Buffer Read Failed.\n"); | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | *lqi = lqi_rssi[0]; | ||
322 | *len = rx_len; | ||
323 | |||
324 | #ifdef DEBUG | ||
325 | print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ", | ||
326 | DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); | ||
327 | printk(KERN_DEBUG "mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", | ||
328 | lqi_rssi[0], lqi_rssi[1]); | ||
329 | #endif | ||
330 | |||
331 | out: | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb) | ||
336 | { | ||
337 | struct mrf24j40 *devrec = dev->priv; | ||
338 | u8 val; | ||
339 | int ret = 0; | ||
340 | |||
341 | dev_dbg(printdev(devrec), "tx packet of %d bytes\n", skb->len); | ||
342 | |||
343 | ret = write_tx_buf(devrec, 0x000, skb->data, skb->len); | ||
344 | if (ret) | ||
345 | goto err; | ||
346 | |||
347 | /* Set TXNTRIG bit of TXNCON to send packet */ | ||
348 | ret = read_short_reg(devrec, REG_TXNCON, &val); | ||
349 | if (ret) | ||
350 | goto err; | ||
351 | val |= 0x1; | ||
352 | val &= ~0x4; | ||
353 | write_short_reg(devrec, REG_TXNCON, val); | ||
354 | |||
355 | INIT_COMPLETION(devrec->tx_complete); | ||
356 | |||
357 | /* Wait for the device to send the TX complete interrupt. */ | ||
358 | ret = wait_for_completion_interruptible_timeout( | ||
359 | &devrec->tx_complete, | ||
360 | 5 * HZ); | ||
361 | if (ret == -ERESTARTSYS) | ||
362 | goto err; | ||
363 | if (ret == 0) { | ||
364 | ret = -ETIMEDOUT; | ||
365 | goto err; | ||
366 | } | ||
367 | |||
368 | /* Check for send error from the device. */ | ||
369 | ret = read_short_reg(devrec, REG_TXSTAT, &val); | ||
370 | if (ret) | ||
371 | goto err; | ||
372 | if (val & 0x1) { | ||
373 | dev_err(printdev(devrec), "Error Sending. Retry count exceeded\n"); | ||
374 | ret = -ECOMM; /* TODO: Better error code ? */ | ||
375 | } else | ||
376 | dev_dbg(printdev(devrec), "Packet Sent\n"); | ||
377 | |||
378 | err: | ||
379 | |||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level) | ||
384 | { | ||
385 | /* TODO: */ | ||
386 | printk(KERN_WARNING "mrf24j40: ed not implemented\n"); | ||
387 | *level = 0; | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int mrf24j40_start(struct ieee802154_dev *dev) | ||
392 | { | ||
393 | struct mrf24j40 *devrec = dev->priv; | ||
394 | u8 val; | ||
395 | int ret; | ||
396 | |||
397 | dev_dbg(printdev(devrec), "start\n"); | ||
398 | |||
399 | ret = read_short_reg(devrec, REG_INTCON, &val); | ||
400 | if (ret) | ||
401 | return ret; | ||
402 | val &= ~(0x1|0x8); /* Clear TXNIE and RXIE. Enable interrupts */ | ||
403 | write_short_reg(devrec, REG_INTCON, val); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static void mrf24j40_stop(struct ieee802154_dev *dev) | ||
409 | { | ||
410 | struct mrf24j40 *devrec = dev->priv; | ||
411 | u8 val; | ||
412 | int ret; | ||
413 | dev_dbg(printdev(devrec), "stop\n"); | ||
414 | |||
415 | ret = read_short_reg(devrec, REG_INTCON, &val); | ||
416 | if (ret) | ||
417 | return; | ||
418 | val |= 0x1|0x8; /* Set TXNIE and RXIE. Disable Interrupts */ | ||
419 | write_short_reg(devrec, REG_INTCON, val); | ||
420 | |||
421 | return; | ||
422 | } | ||
423 | |||
424 | static int mrf24j40_set_channel(struct ieee802154_dev *dev, | ||
425 | int page, int channel) | ||
426 | { | ||
427 | struct mrf24j40 *devrec = dev->priv; | ||
428 | u8 val; | ||
429 | int ret; | ||
430 | |||
431 | dev_dbg(printdev(devrec), "Set Channel %d\n", channel); | ||
432 | |||
433 | WARN_ON(page != 0); | ||
434 | WARN_ON(channel < MRF24J40_CHAN_MIN); | ||
435 | WARN_ON(channel > MRF24J40_CHAN_MAX); | ||
436 | |||
437 | /* Set Channel TODO */ | ||
438 | val = (channel-11) << 4 | 0x03; | ||
439 | write_long_reg(devrec, REG_RFCON0, val); | ||
440 | |||
441 | /* RF Reset */ | ||
442 | ret = read_short_reg(devrec, REG_RFCTL, &val); | ||
443 | if (ret) | ||
444 | return ret; | ||
445 | val |= 0x04; | ||
446 | write_short_reg(devrec, REG_RFCTL, val); | ||
447 | val &= ~0x04; | ||
448 | write_short_reg(devrec, REG_RFCTL, val); | ||
449 | |||
450 | udelay(SET_CHANNEL_DELAY_US); /* per datasheet */ | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int mrf24j40_filter(struct ieee802154_dev *dev, | ||
456 | struct ieee802154_hw_addr_filt *filt, | ||
457 | unsigned long changed) | ||
458 | { | ||
459 | struct mrf24j40 *devrec = dev->priv; | ||
460 | |||
461 | dev_dbg(printdev(devrec), "filter\n"); | ||
462 | |||
463 | if (changed & IEEE802515_AFILT_SADDR_CHANGED) { | ||
464 | /* Short Addr */ | ||
465 | u8 addrh, addrl; | ||
466 | addrh = filt->short_addr >> 8 & 0xff; | ||
467 | addrl = filt->short_addr & 0xff; | ||
468 | |||
469 | write_short_reg(devrec, REG_SADRH, addrh); | ||
470 | write_short_reg(devrec, REG_SADRL, addrl); | ||
471 | dev_dbg(printdev(devrec), | ||
472 | "Set short addr to %04hx\n", filt->short_addr); | ||
473 | } | ||
474 | |||
475 | if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { | ||
476 | /* Device Address */ | ||
477 | int i; | ||
478 | for (i = 0; i < 8; i++) | ||
479 | write_short_reg(devrec, REG_EADR0+i, | ||
480 | filt->ieee_addr[i]); | ||
481 | |||
482 | #ifdef DEBUG | ||
483 | printk(KERN_DEBUG "Set long addr to: "); | ||
484 | for (i = 0; i < 8; i++) | ||
485 | printk("%02hhx ", filt->ieee_addr[i]); | ||
486 | printk(KERN_DEBUG "\n"); | ||
487 | #endif | ||
488 | } | ||
489 | |||
490 | if (changed & IEEE802515_AFILT_PANID_CHANGED) { | ||
491 | /* PAN ID */ | ||
492 | u8 panidl, panidh; | ||
493 | panidh = filt->pan_id >> 8 & 0xff; | ||
494 | panidl = filt->pan_id & 0xff; | ||
495 | write_short_reg(devrec, REG_PANIDH, panidh); | ||
496 | write_short_reg(devrec, REG_PANIDL, panidl); | ||
497 | |||
498 | dev_dbg(printdev(devrec), "Set PANID to %04hx\n", filt->pan_id); | ||
499 | } | ||
500 | |||
501 | if (changed & IEEE802515_AFILT_PANC_CHANGED) { | ||
502 | /* Pan Coordinator */ | ||
503 | u8 val; | ||
504 | int ret; | ||
505 | |||
506 | ret = read_short_reg(devrec, REG_RXMCR, &val); | ||
507 | if (ret) | ||
508 | return ret; | ||
509 | if (filt->pan_coord) | ||
510 | val |= 0x8; | ||
511 | else | ||
512 | val &= ~0x8; | ||
513 | write_short_reg(devrec, REG_RXMCR, val); | ||
514 | |||
515 | /* REG_SLOTTED is maintained as default (unslotted/CSMA-CA). | ||
516 | * REG_ORDER is maintained as default (no beacon/superframe). | ||
517 | */ | ||
518 | |||
519 | dev_dbg(printdev(devrec), "Set Pan Coord to %s\n", | ||
520 | filt->pan_coord ? "on" : "off"); | ||
521 | } | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int mrf24j40_handle_rx(struct mrf24j40 *devrec) | ||
527 | { | ||
528 | u8 len = RX_FIFO_SIZE; | ||
529 | u8 lqi = 0; | ||
530 | u8 val; | ||
531 | int ret = 0; | ||
532 | struct sk_buff *skb; | ||
533 | |||
534 | /* Turn off reception of packets off the air. This prevents the | ||
535 | * device from overwriting the buffer while we're reading it. */ | ||
536 | ret = read_short_reg(devrec, REG_BBREG1, &val); | ||
537 | if (ret) | ||
538 | goto out; | ||
539 | val |= 4; /* SET RXDECINV */ | ||
540 | write_short_reg(devrec, REG_BBREG1, val); | ||
541 | |||
542 | skb = alloc_skb(len, GFP_KERNEL); | ||
543 | if (!skb) { | ||
544 | ret = -ENOMEM; | ||
545 | goto out; | ||
546 | } | ||
547 | |||
548 | ret = mrf24j40_read_rx_buf(devrec, skb_put(skb, len), &len, &lqi); | ||
549 | if (ret < 0) { | ||
550 | dev_err(printdev(devrec), "Failure reading RX FIFO\n"); | ||
551 | kfree_skb(skb); | ||
552 | ret = -EINVAL; | ||
553 | goto out; | ||
554 | } | ||
555 | |||
556 | /* Cut off the checksum */ | ||
557 | skb_trim(skb, len-2); | ||
558 | |||
559 | /* TODO: Other drivers call ieee20154_rx_irqsafe() here (eg: cc2040, | ||
560 | * also from a workqueue). I think irqsafe is not necessary here. | ||
561 | * Can someone confirm? */ | ||
562 | ieee802154_rx_irqsafe(devrec->dev, skb, lqi); | ||
563 | |||
564 | dev_dbg(printdev(devrec), "RX Handled\n"); | ||
565 | |||
566 | out: | ||
567 | /* Turn back on reception of packets off the air. */ | ||
568 | ret = read_short_reg(devrec, REG_BBREG1, &val); | ||
569 | if (ret) | ||
570 | return ret; | ||
571 | val &= ~0x4; /* Clear RXDECINV */ | ||
572 | write_short_reg(devrec, REG_BBREG1, val); | ||
573 | |||
574 | return ret; | ||
575 | } | ||
576 | |||
577 | static struct ieee802154_ops mrf24j40_ops = { | ||
578 | .owner = THIS_MODULE, | ||
579 | .xmit = mrf24j40_tx, | ||
580 | .ed = mrf24j40_ed, | ||
581 | .start = mrf24j40_start, | ||
582 | .stop = mrf24j40_stop, | ||
583 | .set_channel = mrf24j40_set_channel, | ||
584 | .set_hw_addr_filt = mrf24j40_filter, | ||
585 | }; | ||
586 | |||
587 | static irqreturn_t mrf24j40_isr(int irq, void *data) | ||
588 | { | ||
589 | struct mrf24j40 *devrec = data; | ||
590 | |||
591 | disable_irq_nosync(irq); | ||
592 | |||
593 | schedule_work(&devrec->irqwork); | ||
594 | |||
595 | return IRQ_HANDLED; | ||
596 | } | ||
597 | |||
598 | static void mrf24j40_isrwork(struct work_struct *work) | ||
599 | { | ||
600 | struct mrf24j40 *devrec = container_of(work, struct mrf24j40, irqwork); | ||
601 | u8 intstat; | ||
602 | int ret; | ||
603 | |||
604 | /* Read the interrupt status */ | ||
605 | ret = read_short_reg(devrec, REG_INTSTAT, &intstat); | ||
606 | if (ret) | ||
607 | goto out; | ||
608 | |||
609 | /* Check for TX complete */ | ||
610 | if (intstat & 0x1) | ||
611 | complete(&devrec->tx_complete); | ||
612 | |||
613 | /* Check for Rx */ | ||
614 | if (intstat & 0x8) | ||
615 | mrf24j40_handle_rx(devrec); | ||
616 | |||
617 | out: | ||
618 | enable_irq(devrec->spi->irq); | ||
619 | } | ||
620 | |||
621 | static int __devinit mrf24j40_probe(struct spi_device *spi) | ||
622 | { | ||
623 | int ret = -ENOMEM; | ||
624 | u8 val; | ||
625 | struct mrf24j40 *devrec; | ||
626 | |||
627 | printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq); | ||
628 | |||
629 | devrec = kzalloc(sizeof(struct mrf24j40), GFP_KERNEL); | ||
630 | if (!devrec) | ||
631 | goto err_devrec; | ||
632 | devrec->buf = kzalloc(3, GFP_KERNEL); | ||
633 | if (!devrec->buf) | ||
634 | goto err_buf; | ||
635 | |||
636 | spi->mode = SPI_MODE_0; /* TODO: Is this appropriate for right here? */ | ||
637 | if (spi->max_speed_hz > MAX_SPI_SPEED_HZ) | ||
638 | spi->max_speed_hz = MAX_SPI_SPEED_HZ; | ||
639 | |||
640 | mutex_init(&devrec->buffer_mutex); | ||
641 | init_completion(&devrec->tx_complete); | ||
642 | INIT_WORK(&devrec->irqwork, mrf24j40_isrwork); | ||
643 | devrec->spi = spi; | ||
644 | dev_set_drvdata(&spi->dev, devrec); | ||
645 | |||
646 | /* Register with the 802154 subsystem */ | ||
647 | |||
648 | devrec->dev = ieee802154_alloc_device(0, &mrf24j40_ops); | ||
649 | if (!devrec->dev) | ||
650 | goto err_alloc_dev; | ||
651 | |||
652 | devrec->dev->priv = devrec; | ||
653 | devrec->dev->parent = &devrec->spi->dev; | ||
654 | devrec->dev->phy->channels_supported[0] = CHANNEL_MASK; | ||
655 | devrec->dev->flags = IEEE802154_HW_OMIT_CKSUM|IEEE802154_HW_AACK; | ||
656 | |||
657 | dev_dbg(printdev(devrec), "registered mrf24j40\n"); | ||
658 | ret = ieee802154_register_device(devrec->dev); | ||
659 | if (ret) | ||
660 | goto err_register_device; | ||
661 | |||
662 | /* Initialize the device. | ||
663 | From datasheet section 3.2: Initialization. */ | ||
664 | write_short_reg(devrec, REG_SOFTRST, 0x07); | ||
665 | write_short_reg(devrec, REG_PACON2, 0x98); | ||
666 | write_short_reg(devrec, REG_TXSTBL, 0x95); | ||
667 | write_long_reg(devrec, REG_RFCON0, 0x03); | ||
668 | write_long_reg(devrec, REG_RFCON1, 0x01); | ||
669 | write_long_reg(devrec, REG_RFCON2, 0x80); | ||
670 | write_long_reg(devrec, REG_RFCON6, 0x90); | ||
671 | write_long_reg(devrec, REG_RFCON7, 0x80); | ||
672 | write_long_reg(devrec, REG_RFCON8, 0x10); | ||
673 | write_long_reg(devrec, REG_SLPCON1, 0x21); | ||
674 | write_short_reg(devrec, REG_BBREG2, 0x80); | ||
675 | write_short_reg(devrec, REG_CCAEDTH, 0x60); | ||
676 | write_short_reg(devrec, REG_BBREG6, 0x40); | ||
677 | write_short_reg(devrec, REG_RFCTL, 0x04); | ||
678 | write_short_reg(devrec, REG_RFCTL, 0x0); | ||
679 | udelay(192); | ||
680 | |||
681 | /* Set RX Mode. RXMCR<1:0>: 0x0 normal, 0x1 promisc, 0x2 error */ | ||
682 | ret = read_short_reg(devrec, REG_RXMCR, &val); | ||
683 | if (ret) | ||
684 | goto err_read_reg; | ||
685 | val &= ~0x3; /* Clear RX mode (normal) */ | ||
686 | write_short_reg(devrec, REG_RXMCR, val); | ||
687 | |||
688 | ret = request_irq(spi->irq, | ||
689 | mrf24j40_isr, | ||
690 | IRQF_TRIGGER_FALLING, | ||
691 | dev_name(&spi->dev), | ||
692 | devrec); | ||
693 | |||
694 | if (ret) { | ||
695 | dev_err(printdev(devrec), "Unable to get IRQ"); | ||
696 | goto err_irq; | ||
697 | } | ||
698 | |||
699 | return 0; | ||
700 | |||
701 | err_irq: | ||
702 | err_read_reg: | ||
703 | ieee802154_unregister_device(devrec->dev); | ||
704 | err_register_device: | ||
705 | ieee802154_free_device(devrec->dev); | ||
706 | err_alloc_dev: | ||
707 | kfree(devrec->buf); | ||
708 | err_buf: | ||
709 | kfree(devrec); | ||
710 | err_devrec: | ||
711 | return ret; | ||
712 | } | ||
713 | |||
714 | static int __devexit mrf24j40_remove(struct spi_device *spi) | ||
715 | { | ||
716 | struct mrf24j40 *devrec = dev_get_drvdata(&spi->dev); | ||
717 | |||
718 | dev_dbg(printdev(devrec), "remove\n"); | ||
719 | |||
720 | free_irq(spi->irq, devrec); | ||
721 | flush_work_sync(&devrec->irqwork); /* TODO: Is this the right call? */ | ||
722 | ieee802154_unregister_device(devrec->dev); | ||
723 | ieee802154_free_device(devrec->dev); | ||
724 | /* TODO: Will ieee802154_free_device() wait until ->xmit() is | ||
725 | * complete? */ | ||
726 | |||
727 | /* Clean up the SPI stuff. */ | ||
728 | dev_set_drvdata(&spi->dev, NULL); | ||
729 | kfree(devrec->buf); | ||
730 | kfree(devrec); | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static const struct spi_device_id mrf24j40_ids[] = { | ||
735 | { "mrf24j40", 0 }, | ||
736 | { "mrf24j40ma", 0 }, | ||
737 | { }, | ||
738 | }; | ||
739 | MODULE_DEVICE_TABLE(spi, mrf24j40_ids); | ||
740 | |||
741 | static struct spi_driver mrf24j40_driver = { | ||
742 | .driver = { | ||
743 | .name = "mrf24j40", | ||
744 | .bus = &spi_bus_type, | ||
745 | .owner = THIS_MODULE, | ||
746 | }, | ||
747 | .id_table = mrf24j40_ids, | ||
748 | .probe = mrf24j40_probe, | ||
749 | .remove = __devexit_p(mrf24j40_remove), | ||
750 | }; | ||
751 | |||
752 | static int __init mrf24j40_init(void) | ||
753 | { | ||
754 | return spi_register_driver(&mrf24j40_driver); | ||
755 | } | ||
756 | |||
757 | static void __exit mrf24j40_exit(void) | ||
758 | { | ||
759 | spi_unregister_driver(&mrf24j40_driver); | ||
760 | } | ||
761 | |||
762 | module_init(mrf24j40_init); | ||
763 | module_exit(mrf24j40_exit); | ||
764 | |||
765 | MODULE_LICENSE("GPL"); | ||
766 | MODULE_AUTHOR("Alan Ott"); | ||
767 | MODULE_DESCRIPTION("MRF24J40 SPI 802.15.4 Controller Driver"); | ||