Root/
Source at commit 846338826bb4971daa49c454d6c34f366d0f66fe created 12 years 8 months ago. By Werner Almesberger, atusb: use MODULE_AUTHOR according to include/linux/module.h; added myself | |
---|---|
1 | /* |
2 | * atusb - SPI host look-alike for ATSUB |
3 | * |
4 | * Copyright (c) 2011 Richard Sharpe <realrichardsharpe@gmail.com> |
5 | * Copyright (c) 2011 Stefan Schmidt <stefan@datenfreihafen.org> |
6 | * Copyright (c) 2011 Werner Almesberger <werner@almesberger.net> |
7 | * |
8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License as |
10 | * published by the Free Software Foundation, version 2 |
11 | * |
12 | */ |
13 | |
14 | /* |
15 | * - implement more robust interrupt synchronization |
16 | * - check URB killing in atusb_disconnect for races |
17 | * - switch from bulk to interrupt endpoint |
18 | * - implement buffer read without extra copy |
19 | * - harmonize indentation style |
20 | * - mv atusb.c ../ieee802.15.4/spi_atusb.c, or maybe atrf_atusb.c or such |
21 | * - check module load/unload |
22 | * - review dev_* severity levels |
23 | */ |
24 | |
25 | #include <linux/kernel.h> |
26 | #include <linux/module.h> |
27 | #include <linux/platform_device.h> |
28 | #include <linux/jiffies.h> |
29 | #include <linux/timer.h> |
30 | #include <linux/interrupt.h> |
31 | #include <linux/usb.h> |
32 | #include <linux/spi/spi.h> |
33 | #include <linux/spi/at86rf230.h> |
34 | |
35 | #include "../ieee802154/at86rf230.h" /* dirty */ |
36 | |
37 | |
38 | #define SYNC_TIMEOUT_MS 50 /* assume interrupt has been synced after |
39 | waiting this long */ |
40 | |
41 | #define VENDOR_ID 0x20b7 |
42 | #define PRODUCT_ID 0x1540 |
43 | |
44 | /* The devices we work with */ |
45 | static const struct usb_device_id atusb_device_table[] = { |
46 | { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, |
47 | { }, |
48 | }; |
49 | MODULE_DEVICE_TABLE(usb, atusb_device_table); |
50 | |
51 | #define ATUSB_BUILD_SIZE 256 |
52 | struct atusb_local { |
53 | struct usb_device * udev; |
54 | /* The interface to the RF part info, if applicable */ |
55 | uint8_t ep0_atusb_major; |
56 | uint8_t ep0_atusb_minor; |
57 | uint8_t atusb_hw_type; |
58 | struct spi_master *master; |
59 | int slave_irq; |
60 | struct urb *irq_urb; |
61 | uint8_t irq_buf; /* receive irq serial here*/ |
62 | uint8_t irq_seen; /* last irq serial from bulk */ |
63 | uint8_t irq_sync; /* last irq serial from WRITE2_SYNC */ |
64 | struct tasklet_struct task; /* interrupt delivery tasklet */ |
65 | struct timer_list timer; /* delay, for interrupt synch */ |
66 | struct at86rf230_platform_data platform_data; |
67 | /* copy platform_data so that we can adapt .reset_data */ |
68 | struct spi_device *spi; |
69 | // unsigned char buffer[3]; |
70 | unsigned char buffer[260]; /* XXL, just in case */ |
71 | struct spi_message *msg; |
72 | }; |
73 | |
74 | /* Commands to our device. Make sure this is synced with the firmware */ |
75 | enum atspi_requests { |
76 | ATUSB_ID = 0x00, /* system status/control grp */ |
77 | ATUSB_BUILD, |
78 | ATUSB_RESET, |
79 | ATUSB_RF_RESET = 0x10, /* debug/test group */ |
80 | ATUSB_POLL_INT, |
81 | ATUSB_TEST, /* atusb-sil only */ |
82 | ATUSB_TIMER, |
83 | ATUSB_GPIO, |
84 | ATUSB_SLP_TR, |
85 | ATUSB_GPIO_CLEANUP, |
86 | ATUSB_REG_WRITE = 0x20, /* transceiver group */ |
87 | ATUSB_REG_READ, |
88 | ATUSB_BUF_WRITE, |
89 | ATUSB_BUF_READ, |
90 | ATUSB_SRAM_WRITE, |
91 | ATUSB_SRAM_READ, |
92 | ATUSB_SPI_WRITE = 0x30, /* SPI group */ |
93 | ATUSB_SPI_READ1, |
94 | ATUSB_SPI_READ2, |
95 | ATUSB_SPI_WRITE2_SYNC, |
96 | }; |
97 | |
98 | /* |
99 | * Direction bRequest wValue wIndex wLength |
100 | * |
101 | * ->host ATUSB_ID - - 3 |
102 | * ->host ATUSB_BUILD - - #bytes |
103 | * host-> ATUSB_RESET - - 0 |
104 | * |
105 | * host-> ATUSB_RF_RESET - - 0 |
106 | * ->host ATUSB_POLL_INT - - 1 |
107 | * host-> ATUSB_TEST - - 0 |
108 | * ->host ATUSB_TIMER - - #bytes (6) |
109 | * ->host ATUSB_GPIO dir+data mask+p# 3 |
110 | * host-> ATUSB_SLP_TR - - 0 |
111 | * host-> ATUSB_GPIO_CLEANUP - - 0 |
112 | * |
113 | * host-> ATUSB_REG_WRITE value addr 0 |
114 | * ->host ATUSB_REG_READ - addr 1 |
115 | * host-> ATUSB_BUF_WRITE - - #bytes |
116 | * ->host ATUSB_BUF_READ - - #bytes |
117 | * host-> ATUSB_SRAM_WRITE - addr #bytes |
118 | * ->host ATUSB_SRAM_READ - addr #bytes |
119 | * |
120 | * host-> ATUSB_SPI_WRITE byte0 byte1 #bytes |
121 | * ->host ATUSB_SPI_READ1 byte0 - #bytes |
122 | * ->host ATUSB_SPI_READ2 byte0 byte1 #bytes |
123 | * ->host ATUSB_SPI_WRITE2_SYNC byte0 byte1 0/1 |
124 | */ |
125 | |
126 | #define ATUSB_FROM_DEV (USB_TYPE_VENDOR | USB_DIR_IN) |
127 | #define ATUSB_TO_DEV (USB_TYPE_VENDOR | USB_DIR_OUT) |
128 | |
129 | |
130 | /* ----- Control transfers ------------------------------------------------- */ |
131 | |
132 | |
133 | static int atusb_async_errchk(struct urb *urb) |
134 | { |
135 | struct atusb_local *atusb = urb->context; |
136 | struct spi_message *msg = atusb->msg; |
137 | struct usb_device *dev = atusb->udev; |
138 | |
139 | if (!urb->status) { |
140 | dev_dbg(&dev->dev, "atusb_async_errchk OK len %d\n", |
141 | urb->actual_length); |
142 | return 0; |
143 | } |
144 | |
145 | if (urb->status != -ENOENT && urb->status != -ECONNRESET && |
146 | urb->status != -ESHUTDOWN) |
147 | dev_info(&dev->dev, "atusb_async_errchk FAIL error %d\n", |
148 | urb->status); |
149 | |
150 | msg->actual_length = 0; |
151 | |
152 | return urb->status; |
153 | } |
154 | |
155 | static void atusb_async_finish(struct urb *urb) |
156 | { |
157 | struct atusb_local *atusb = urb->context; |
158 | struct spi_message *msg = atusb->msg; |
159 | |
160 | msg->status = urb->status; |
161 | msg->complete(msg->context); |
162 | |
163 | kfree(urb->setup_packet); |
164 | usb_free_urb(urb); |
165 | } |
166 | |
167 | static void atusb_ctrl_cb(struct urb *urb) |
168 | { |
169 | atusb_async_errchk(urb); |
170 | atusb_async_finish(urb); |
171 | } |
172 | |
173 | static void atusb_timer(unsigned long data) |
174 | { |
175 | struct urb *urb = (void *) data; |
176 | |
177 | dev_warn(&urb->dev->dev, "atusb_timer\n"); |
178 | atusb_async_finish(urb); |
179 | } |
180 | |
181 | static void atusb_ctrl_cb_sync(struct urb *urb) |
182 | { |
183 | struct atusb_local *atusb = urb->context; |
184 | |
185 | /* @@@ needs locking/atomic */ |
186 | if (atusb_async_errchk(urb) || atusb->irq_sync == atusb->irq_seen) { |
187 | atusb_async_finish(urb); |
188 | return; |
189 | } |
190 | |
191 | BUG_ON(timer_pending(&atusb->timer)); |
192 | atusb->timer.expires = jiffies+msecs_to_jiffies(SYNC_TIMEOUT_MS); |
193 | atusb->timer.data = (unsigned long) urb; |
194 | add_timer(&atusb->timer); |
195 | } |
196 | |
197 | static void atusb_read_fb_cb(struct urb *urb) |
198 | { |
199 | struct atusb_local *atusb = urb->context; |
200 | struct spi_message *msg = atusb->msg; |
201 | const struct spi_transfer *xfer; |
202 | uint8_t *rx; |
203 | |
204 | if (!atusb_async_errchk(urb)) { |
205 | BUG_ON(!urb->actual_length); |
206 | |
207 | xfer = list_first_entry(&msg->transfers, struct spi_transfer, |
208 | transfer_list); |
209 | rx = xfer->rx_buf; |
210 | rx[1] = atusb->buffer[0]; |
211 | |
212 | xfer = list_entry(xfer->transfer_list.next, |
213 | struct spi_transfer, transfer_list); |
214 | memcpy(xfer->rx_buf, atusb->buffer+1, urb->actual_length-1); |
215 | } |
216 | |
217 | atusb_async_finish(urb); |
218 | } |
219 | |
220 | static int submit_control_msg(struct atusb_local *atusb, |
221 | __u8 request, __u8 requesttype, __u16 value, __u16 index, |
222 | void *data, __u16 size, usb_complete_t complete_fn, void *context) |
223 | { |
224 | struct usb_device *dev = atusb->udev; |
225 | struct usb_ctrlrequest *req; |
226 | struct urb *urb; |
227 | int retval = -ENOMEM; |
228 | |
229 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); |
230 | if (!req) |
231 | return -ENOMEM; |
232 | |
233 | req->bRequest = request; |
234 | req->bRequestType = requesttype; |
235 | req->wValue = cpu_to_le16(value); |
236 | req->wIndex = cpu_to_le16(index); |
237 | req->wLength = cpu_to_le16(size); |
238 | |
239 | urb = usb_alloc_urb(0, GFP_KERNEL); |
240 | if (!urb) |
241 | goto out_nourb; |
242 | |
243 | usb_fill_control_urb(urb, dev, |
244 | requesttype == ATUSB_FROM_DEV ? |
245 | usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0), |
246 | (unsigned char *) req, data, size, complete_fn, context); |
247 | |
248 | retval = usb_submit_urb(urb, GFP_KERNEL); |
249 | if (!retval) |
250 | return 0; |
251 | dev_warn(&dev->dev, "failed submitting read urb, error %d", |
252 | retval); |
253 | retval = retval == -ENOMEM ? retval : -EIO; |
254 | |
255 | usb_free_urb(urb); |
256 | out_nourb: |
257 | kfree(req); |
258 | |
259 | return retval; |
260 | } |
261 | |
262 | |
263 | /* ----- SPI transfers ----------------------------------------------------- */ |
264 | |
265 | |
266 | static int atusb_read1(struct atusb_local *atusb, |
267 | uint8_t tx, uint8_t *rx, int len) |
268 | { |
269 | dev_dbg(&atusb->udev->dev, "atusb_read1: tx = 0x%x\n", tx); |
270 | return submit_control_msg(atusb, |
271 | ATUSB_SPI_READ1, ATUSB_FROM_DEV, tx, 0, |
272 | rx, 1, atusb_ctrl_cb, atusb); |
273 | } |
274 | |
275 | static int atusb_read_fb(struct atusb_local *atusb, |
276 | uint8_t tx, uint8_t *rx0, uint8_t *rx, int len) |
277 | { |
278 | dev_dbg(&atusb->udev->dev, "atusb_read_fb: tx = 0x%x\n", tx); |
279 | return submit_control_msg(atusb, |
280 | ATUSB_SPI_READ1, ATUSB_FROM_DEV, tx, 0, |
281 | atusb->buffer, len+1, atusb_read_fb_cb, atusb); |
282 | } |
283 | |
284 | static int atusb_write(struct atusb_local *atusb, |
285 | uint8_t tx0, uint8_t tx1, const uint8_t *tx, int len) |
286 | { |
287 | dev_dbg(&atusb->udev->dev, |
288 | "atusb_write: tx0 = 0x%x tx1 = 0x%x\n", tx0, tx1); |
289 | |
290 | /* |
291 | * The AT86RF230 driver sometimes requires a transceiver state |
292 | * transition to be an interrupt barrier. This is the case after |
293 | * writing FORCE_TX_ON to the TRX_CMD field in the TRX_STATE register. |
294 | * |
295 | * Since there is no other means of notification, we just decode the |
296 | * transfer and do a bit of pattern matching. |
297 | */ |
298 | if (tx0 == (CMD_REG | CMD_WRITE | RG_TRX_STATE) && |
299 | (tx1 & 0x1f) == STATE_FORCE_TX_ON) |
300 | return submit_control_msg(atusb, |
301 | ATUSB_SPI_WRITE2_SYNC, ATUSB_FROM_DEV, tx0, tx1, |
302 | &atusb->irq_sync, 1, atusb_ctrl_cb_sync, atusb); |
303 | else |
304 | return submit_control_msg(atusb, |
305 | ATUSB_SPI_WRITE, ATUSB_TO_DEV, tx0, tx1, |
306 | (uint8_t *) tx, len, atusb_ctrl_cb, atusb); |
307 | } |
308 | |
309 | static int atusb_transfer(struct spi_device *spi, struct spi_message *msg) |
310 | { |
311 | struct atusb_local *atusb = spi_master_get_devdata(spi->master); |
312 | struct spi_transfer *xfer; |
313 | struct spi_transfer *x[2]; |
314 | int n; |
315 | const uint8_t *tx; |
316 | uint8_t *rx; |
317 | int len; |
318 | int retval = 0; |
319 | |
320 | if (unlikely(list_empty(&msg->transfers))) { |
321 | dev_err(&atusb->udev->dev, "transfer is empty\n"); |
322 | return -EINVAL; |
323 | } |
324 | |
325 | atusb->msg = msg; |
326 | |
327 | /* Classify the request */ |
328 | n = 0; |
329 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { |
330 | if (n == ARRAY_SIZE(x)) { |
331 | dev_err(&atusb->udev->dev, "too many transfers\n"); |
332 | return -EINVAL; |
333 | } |
334 | x[n] = xfer; |
335 | n++; |
336 | } |
337 | |
338 | tx = x[0]->tx_buf; |
339 | rx = x[0]->rx_buf; |
340 | len = x[0]->len; |
341 | |
342 | msg->actual_length = len; |
343 | |
344 | if (!tx || len != 2) |
345 | goto bad_req; |
346 | if (n == 1) { |
347 | if (rx) { |
348 | dev_dbg(&atusb->udev->dev, "read 1\n"); |
349 | retval = atusb_read1(atusb, tx[0], rx+1, len-1); |
350 | } else { |
351 | dev_dbg(&atusb->udev->dev, "write 2\n"); |
352 | /* |
353 | * Don't take our clock away !! ;-) |
354 | */ |
355 | if (tx[0] == (CMD_REG | CMD_WRITE | RG_TRX_CTRL_0)) { |
356 | msg->status = 0; |
357 | msg->complete(msg->context); |
358 | } else { |
359 | retval = atusb_write(atusb, |
360 | tx[0], tx[1], NULL, 0); |
361 | } |
362 | } |
363 | } else { |
364 | if (x[0]->rx_buf) { |
365 | if (x[1]->tx_buf || !x[1]->rx_buf) |
366 | goto bad_req; |
367 | dev_dbg(&atusb->udev->dev, "read 1+\n"); |
368 | retval = atusb_read_fb(atusb, tx[0], rx+1, |
369 | x[1]->rx_buf, x[1]->len); |
370 | } else { |
371 | if (!x[1]->tx_buf ||x[1]->rx_buf) |
372 | goto bad_req; |
373 | dev_dbg(&atusb->udev->dev, "write 2+n\n"); |
374 | retval = atusb_write(atusb, tx[0], tx[1], |
375 | x[1]->tx_buf, x[1]->len); |
376 | } |
377 | } |
378 | return retval; |
379 | |
380 | bad_req: |
381 | dev_err(&atusb->udev->dev, "unrecognized request:\n"); |
382 | list_for_each_entry(xfer, &msg->transfers, transfer_list) |
383 | dev_err(&atusb->udev->dev, "%stx %srx len %u\n", |
384 | xfer->tx_buf ? "" : "!", xfer->rx_buf ? " " : "!", |
385 | xfer->len); |
386 | return -EINVAL; |
387 | } |
388 | |
389 | static int atusb_setup(struct spi_device *spi) |
390 | { |
391 | return 0; |
392 | } |
393 | |
394 | |
395 | /* ----- Interrupt handling ------------------------------------------------ */ |
396 | |
397 | |
398 | static void atusb_tasklet(unsigned long data) |
399 | { |
400 | struct atusb_local *atusb = (void *) data; |
401 | |
402 | generic_handle_irq(atusb->slave_irq); |
403 | } |
404 | |
405 | static void atusb_irq(struct urb *urb) |
406 | { |
407 | struct atusb_local *atusb = urb->context; |
408 | |
409 | dev_dbg(&urb->dev->dev, "atusb_irq (%d), seen %d sync %d\n", |
410 | urb->status, atusb->irq_buf, atusb->irq_sync); |
411 | if (!urb->status) { |
412 | atusb->irq_seen = atusb->irq_buf; |
413 | if (atusb->irq_sync == atusb->irq_seen && |
414 | try_to_del_timer_sync(&atusb->timer) == 1) |
415 | atusb_async_finish((struct urb *) atusb->timer.data); |
416 | } |
417 | usb_free_urb(urb); |
418 | atusb->irq_urb = NULL; |
419 | tasklet_schedule(&atusb->task); |
420 | } |
421 | |
422 | static int atusb_arm_interrupt(struct atusb_local *atusb) |
423 | { |
424 | struct usb_device *dev = atusb->udev; |
425 | struct urb *urb; |
426 | int retval = -ENOMEM; |
427 | |
428 | BUG_ON(atusb->irq_urb); |
429 | |
430 | dev_vdbg(&dev->dev, "atusb_arm_interrupt\n"); |
431 | urb = usb_alloc_urb(0, GFP_KERNEL); |
432 | if (!urb) { |
433 | dev_err(&dev->dev, |
434 | "atusb_arm_interrupt: usb_alloc_urb failed\n"); |
435 | return -ENOMEM; |
436 | } |
437 | |
438 | usb_fill_bulk_urb(urb, dev, usb_rcvbulkpipe(dev, 1), |
439 | &atusb->irq_buf, 1, atusb_irq, atusb); |
440 | atusb->irq_urb = urb; |
441 | retval = usb_submit_urb(urb, GFP_KERNEL); |
442 | if (!retval) |
443 | return 0; |
444 | |
445 | dev_err(&dev->dev, "failed submitting bulk urb, error %d\n", retval); |
446 | retval = retval == -ENOMEM ? retval : -EIO; |
447 | |
448 | usb_free_urb(urb); |
449 | |
450 | return retval; |
451 | } |
452 | |
453 | static void atusb_irq_mask(struct irq_data *data) |
454 | { |
455 | struct atusb_local *atusb = irq_data_get_irq_chip_data(data); |
456 | |
457 | dev_vdbg(&atusb->udev->dev, "atusb_irq_mask\n"); |
458 | tasklet_disable_nosync(&atusb->task); |
459 | } |
460 | |
461 | static void atusb_irq_unmask(struct irq_data *data) |
462 | { |
463 | struct atusb_local *atusb = irq_data_get_irq_chip_data(data); |
464 | |
465 | dev_vdbg(&atusb->udev->dev, "atusb_irq_unmask\n"); |
466 | tasklet_enable(&atusb->task); |
467 | } |
468 | |
469 | static void atusb_irq_ack(struct irq_data *data) |
470 | { |
471 | struct atusb_local *atusb = irq_data_get_irq_chip_data(data); |
472 | |
473 | dev_vdbg(&atusb->udev->dev, "atusb_irq_ack\n"); |
474 | atusb_arm_interrupt(atusb); |
475 | } |
476 | |
477 | static struct irq_chip atusb_irq_chip = { |
478 | .name = "atusb-slave", |
479 | .irq_mask = atusb_irq_mask, |
480 | .irq_unmask = atusb_irq_unmask, |
481 | .irq_ack = atusb_irq_ack, |
482 | }; |
483 | |
484 | |
485 | /* ----- Transceiver reset ------------------------------------------------- */ |
486 | |
487 | |
488 | static void atusb_reset(void *reset_data) |
489 | { |
490 | int retval; |
491 | struct atusb_local *atusb = reset_data; |
492 | |
493 | retval = usb_control_msg(atusb->udev, |
494 | usb_rcvctrlpipe(atusb->udev, 0), |
495 | ATUSB_RF_RESET, ATUSB_TO_DEV, 0, 0, |
496 | NULL, 0, 1000); |
497 | if (retval < 0) { |
498 | dev_err(&atusb->udev->dev, |
499 | "%s: error doing reset retval = %d\n", |
500 | __func__, retval); |
501 | } |
502 | } |
503 | |
504 | |
505 | /* ----- Firmware version information -------------------------------------- */ |
506 | |
507 | |
508 | static int atusb_get_and_show_revision(struct atusb_local *atusb) |
509 | { |
510 | struct usb_device *dev = atusb->udev; |
511 | int retval; |
512 | |
513 | /* Get a couple of the ATMega Firmware values */ |
514 | retval = usb_control_msg(dev, |
515 | usb_rcvctrlpipe(dev, 0), |
516 | ATUSB_ID, ATUSB_FROM_DEV, 0, 0, |
517 | atusb->buffer, 3, 1000); |
518 | if (retval < 0) { |
519 | dev_info(&dev->dev, |
520 | "failed submitting urb for ATUSB_ID, error %d\n", retval); |
521 | return retval == -ENOMEM ? retval : -EIO; |
522 | } |
523 | |
524 | atusb->ep0_atusb_major = atusb->buffer[0]; |
525 | atusb->ep0_atusb_minor = atusb->buffer[1]; |
526 | atusb->atusb_hw_type = atusb->buffer[2]; |
527 | dev_info(&dev->dev, |
528 | "Firmware: major: %u, minor: %u, hardware type: %u\n", |
529 | atusb->ep0_atusb_major, atusb->ep0_atusb_minor, |
530 | atusb->atusb_hw_type); |
531 | |
532 | return 0; |
533 | } |
534 | |
535 | static int atusb_get_and_show_build(struct atusb_local *atusb) |
536 | { |
537 | struct usb_device *dev = atusb->udev; |
538 | char build[ATUSB_BUILD_SIZE+1]; |
539 | int retval; |
540 | |
541 | retval = usb_control_msg(dev, |
542 | usb_rcvctrlpipe(atusb->udev, 0), |
543 | ATUSB_BUILD, ATUSB_FROM_DEV, 0, 0, |
544 | build, ATUSB_BUILD_SIZE, 1000); |
545 | if (retval < 0) { |
546 | dev_err(&dev->dev, |
547 | "failed submitting urb for ATUSB_BUILD, error %d\n", |
548 | retval); |
549 | return retval == -ENOMEM ? retval : -EIO; |
550 | } |
551 | |
552 | build[retval] = 0; |
553 | dev_info(&dev->dev, "Firmware: build %s\n", build); |
554 | |
555 | return 0; |
556 | } |
557 | |
558 | |
559 | /* ----- Setup ------------------------------------------------------------- */ |
560 | |
561 | |
562 | struct at86rf230_platform_data at86rf230_platform_data = { |
563 | .rstn = -1, |
564 | .slp_tr = -1, |
565 | .dig2 = -1, |
566 | .reset = atusb_reset, |
567 | /* set .reset_data later */ |
568 | }; |
569 | |
570 | static int atusb_probe(struct usb_interface *interface, |
571 | const struct usb_device_id *id) |
572 | { |
573 | struct spi_board_info board_info = { |
574 | .modalias = "at86rf230", |
575 | /* set .irq later */ |
576 | .chip_select = 0, |
577 | .bus_num = -1, |
578 | .max_speed_hz = 8 * 1000 * 1000, |
579 | }; |
580 | |
581 | struct usb_device *udev = interface_to_usbdev(interface); |
582 | struct atusb_local *atusb = NULL; |
583 | struct spi_master *master; |
584 | int retval; |
585 | |
586 | /* |
587 | * Ignore all interfaces used for DFU, i.e., everything while in the |
588 | * boot loader, and interface #1 when in the application. |
589 | */ |
590 | if (interface->cur_altsetting->desc.bInterfaceClass != |
591 | USB_CLASS_VENDOR_SPEC) { |
592 | dev_dbg(&udev->dev, |
593 | "Ignoring interface with class 0x%02x\n", |
594 | interface->cur_altsetting->desc.bInterfaceClass); |
595 | return -ENODEV; |
596 | } |
597 | |
598 | master = spi_alloc_master(&udev->dev, sizeof(*atusb)); |
599 | if (!master) |
600 | return -ENOMEM; |
601 | |
602 | atusb = spi_master_get_devdata(master); |
603 | |
604 | atusb->udev = usb_get_dev(udev); |
605 | usb_set_intfdata(interface, atusb); |
606 | |
607 | atusb->master = spi_master_get(master); |
608 | |
609 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
610 | master->bus_num = -1; |
611 | master->num_chipselect = 1; |
612 | master->setup = atusb_setup; |
613 | master->transfer = atusb_transfer; |
614 | |
615 | atusb->slave_irq = irq_alloc_desc(numa_node_id()); |
616 | if (atusb->slave_irq < 0) { |
617 | dev_err(&udev->dev, "can't allocate slave irq\n"); |
618 | retval = -ENXIO; |
619 | goto err_free; |
620 | } |
621 | |
622 | set_irq_chip_data(atusb->slave_irq, atusb); |
623 | set_irq_chip_and_handler(atusb->slave_irq, &atusb_irq_chip, |
624 | handle_level_irq); |
625 | |
626 | /* FIXME prepare USB IRQ */ |
627 | |
628 | retval = spi_register_master(master); |
629 | if (retval < 0) { |
630 | dev_err(&udev->dev, "can't register spi master\n"); |
631 | goto err_slave_irq; |
632 | } |
633 | |
634 | atusb->platform_data = at86rf230_platform_data; |
635 | atusb->platform_data.reset_data = atusb; |
636 | board_info.platform_data = &atusb->platform_data; |
637 | board_info.irq = atusb->slave_irq; |
638 | |
639 | init_timer(&atusb->timer); |
640 | atusb->timer.function = atusb_timer; |
641 | |
642 | tasklet_init(&atusb->task, atusb_tasklet, (unsigned long) atusb); |
643 | tasklet_disable(&atusb->task); |
644 | atusb_arm_interrupt(atusb); |
645 | |
646 | if (atusb_get_and_show_revision(atusb) < 0) |
647 | goto err_master; |
648 | if (atusb_get_and_show_build(atusb) < 0) |
649 | goto err_master; |
650 | |
651 | atusb->spi = spi_new_device(master, &board_info); |
652 | if (!atusb->spi) { |
653 | dev_err(&udev->dev, "can't create new device for %s\n", |
654 | board_info.modalias); |
655 | goto err_master; |
656 | } |
657 | |
658 | dev_info(&atusb->spi->dev, |
659 | "ATUSB ready for mischief (IRQ %d)\n", board_info.irq); |
660 | |
661 | return 0; |
662 | |
663 | err_master: |
664 | /* |
665 | * If we come here from a partially successful driver initialization, |
666 | * we don't really know how much it has done. In particular, it may |
667 | * have triggered an interrupt and thus removed the interrupt URB and |
668 | * maybe scheduled the tasklet. |
669 | */ |
670 | tasklet_disable(&atusb->task); |
671 | if (atusb->irq_urb) |
672 | usb_kill_urb(atusb->irq_urb); |
673 | spi_master_put(atusb->master); |
674 | err_slave_irq: |
675 | set_irq_chained_handler(atusb->slave_irq, NULL); |
676 | set_irq_chip_data(atusb->slave_irq, NULL); |
677 | irq_free_desc(atusb->slave_irq); |
678 | err_free: |
679 | return retval; |
680 | } |
681 | |
682 | static void atusb_disconnect(struct usb_interface *interface) |
683 | { |
684 | struct atusb_local *atusb = usb_get_intfdata(interface); |
685 | struct spi_master *master = atusb->master; |
686 | |
687 | tasklet_disable(&atusb->task); |
688 | /* @@@ this needs some extra protecion - wa */ |
689 | if (atusb->irq_urb) |
690 | usb_kill_urb(atusb->irq_urb); |
691 | |
692 | BUG_ON(timer_pending(&atusb->timer)); |
693 | |
694 | usb_set_intfdata(interface, NULL); |
695 | usb_put_dev(atusb->udev); |
696 | |
697 | spi_dev_put(atusb->spi); |
698 | |
699 | spi_unregister_master(master); |
700 | |
701 | set_irq_chained_handler(atusb->slave_irq, NULL); |
702 | set_irq_chip_data(atusb->slave_irq, NULL); |
703 | irq_free_desc(atusb->slave_irq); |
704 | |
705 | spi_master_put(master); |
706 | } |
707 | |
708 | void atusb_release(struct device *dev) |
709 | { |
710 | return; |
711 | } |
712 | |
713 | static struct usb_driver atusb_driver = { |
714 | .name = "atusb_ben-wpan", |
715 | .probe = atusb_probe, |
716 | .disconnect = atusb_disconnect, |
717 | .id_table = atusb_device_table, |
718 | }; |
719 | |
720 | static struct platform_device atusb_device = { |
721 | .name = "spi_atusb", |
722 | .id = -1, |
723 | .dev.release = atusb_release, |
724 | }; |
725 | |
726 | static int __init atusb_init(void) |
727 | { |
728 | int retval; |
729 | |
730 | retval = platform_device_register(&atusb_device); |
731 | if (retval) |
732 | return retval; |
733 | |
734 | return usb_register(&atusb_driver); |
735 | } |
736 | |
737 | static void __exit atusb_exit(void) |
738 | { |
739 | usb_deregister(&atusb_driver); |
740 | platform_device_unregister(&atusb_device); |
741 | } |
742 | |
743 | module_init (atusb_init); |
744 | module_exit (atusb_exit); |
745 | |
746 | MODULE_AUTHOR("Richard Sharpe <realrichardsharpe@gmail.com>"); |
747 | MODULE_AUTHOR("Stefan Schmidt <stefan@datenfreihafen.org>"); |
748 | MODULE_AUTHOR("Werner Almesberger <werner@almesberger.net>"); |
749 | MODULE_DESCRIPTION("ATUSB ben-wpan Driver"); |
750 | MODULE_LICENSE("GPL"); |
751 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9