Date: | 2011-07-07 01:12:03 (12 years 8 months ago) |
---|---|
Author: | Werner Almesberger |
Commit: | eb1a51efda953658df691c467a6b1249e54c5dd8 |
Message: | atusb: implement interrupt synchronization via a 10 ms delay timer Writes to TRX_STATE may have to act as interrupt barriers. Since we currently have no direct means for ensuring that host and atusb are synchronized, we simply wait 10 ms, which should be sufficient to receive any pending bulk data. Moved the TRX_STATE change detection logic from atusb_transfer to atusb_write and implemented the delay via a timer. Signed-off-by: Werner Almesberger <werner@almesberger.net> |
Files: |
drivers/spi/atusb.c (7 diffs) |
Change Details
drivers/spi/atusb.c | ||
---|---|---|
18 | 18 | #include <linux/kernel.h> |
19 | 19 | #include <linux/module.h> |
20 | 20 | #include <linux/platform_device.h> |
21 | #include <linux/jiffies.h> | |
22 | #include <linux/timer.h> | |
21 | 23 | #include <linux/interrupt.h> |
22 | 24 | #include <linux/usb.h> |
23 | 25 | #include <linux/spi/spi.h> |
... | ... | |
47 | 49 | struct urb *irq_urb; |
48 | 50 | uint8_t irq_buf; /* scratch space */ |
49 | 51 | struct tasklet_struct task; /* interrupt delivery tasklet */ |
52 | struct timer_list timer; /* delay, for interrupt synch */ | |
50 | 53 | struct at86rf230_platform_data platform_data; |
51 | 54 | /* copy platform_data so that we can adapt .reset_data */ |
52 | 55 | struct spi_device *spi; |
... | ... | |
152 | 155 | atusb_async_finish(urb); |
153 | 156 | } |
154 | 157 | |
158 | static void atusb_timer(unsigned long data) | |
159 | { | |
160 | struct urb *urb = (void *) data; | |
161 | ||
162 | printk(KERN_INFO "atusb_timer\n"); | |
163 | atusb_async_finish(urb); | |
164 | } | |
165 | ||
166 | static void atusb_ctrl_cb_delayed(struct urb *urb) | |
167 | { | |
168 | struct atusb_local *atusb = urb->context; | |
169 | ||
170 | if (atusb_async_errchk(urb)) | |
171 | atusb_async_finish(urb); | |
172 | else { | |
173 | BUG_ON(timer_pending(&atusb->timer)); | |
174 | atusb->timer.expires = jiffies+msecs_to_jiffies(10); | |
175 | atusb->timer.data = (unsigned long) urb; | |
176 | add_timer(&atusb->timer); | |
177 | } | |
178 | } | |
179 | ||
155 | 180 | static void atusb_read_fb_cb(struct urb *urb) |
156 | 181 | { |
157 | 182 | struct atusb_local *atusb = urb->context; |
... | ... | |
242 | 267 | static int atusb_write(struct atusb_local *atusb, |
243 | 268 | uint8_t tx0, uint8_t tx1, const uint8_t *tx, int len) |
244 | 269 | { |
270 | usb_complete_t cb = atusb_ctrl_cb; | |
271 | ||
245 | 272 | dev_info(&atusb->udev->dev, "atusb_write: tx[0] = 0x%x\n", tx0); |
246 | 273 | dev_info(&atusb->udev->dev, "atusb_write: tx[1] = 0x%x\n", tx1); |
274 | ||
275 | /* | |
276 | * The AT86RF230 driver sometimes requires a transceiver state | |
277 | * transition to be an interrupt barrier. This is the case after | |
278 | * writing FORCE_TX_ON to the TRX_CMD field in the TRX_STATE register. | |
279 | * | |
280 | * Since there is no other means of notification, we just decode the | |
281 | * transfer and do a bit of pattern matching. | |
282 | */ | |
283 | if (tx0 == (CMD_REG | CMD_WRITE | RG_TRX_STATE) && | |
284 | (tx1 & 0x1f) == STATE_FORCE_TX_ON) | |
285 | cb = atusb_ctrl_cb_delayed; | |
286 | ||
247 | 287 | return submit_control_msg(atusb, |
248 | 288 | ATUSB_SPI_WRITE, ATUSB_TO_DEV, tx0, tx1, |
249 | (uint8_t *) tx, len, atusb_ctrl_cb, atusb); | |
289 | (uint8_t *) tx, len, cb, atusb); | |
250 | 290 | } |
251 | 291 | |
252 | 292 | static int atusb_transfer(struct spi_device *spi, struct spi_message *msg) |
... | ... | |
318 | 358 | x[1]->tx_buf, x[1]->len); |
319 | 359 | } |
320 | 360 | } |
321 | #if 0 | |
322 | /* | |
323 | * The AT86RF230 driver sometimes requires a transceiver state | |
324 | * transition to be an interrupt barrier. This is the case after | |
325 | * writing FORCE_TX_ON to the TRX_CMD field in the TRX_STATE register. | |
326 | * | |
327 | * Since there is no other means of notification, we just decode the | |
328 | * transfer and do a bit of pattern matching. | |
329 | */ | |
330 | xfer = list_first_entry(&msg->transfers, struct spi_transfer, | |
331 | transfer_list); | |
332 | tx = xfer->tx_buf; | |
333 | if (tx && xfer->len == 2 && | |
334 | tx[0] == (CMD_REG | CMD_WRITE | RG_TRX_STATE) && | |
335 | (tx[1] & 0x1f) == STATE_FORCE_TX_ON) | |
336 | synchronize_irq(atusb->gpio_irq); | |
337 | #endif | |
338 | 361 | return retval; |
339 | 362 | |
340 | 363 | bad_req: |
... | ... | |
588 | 611 | board_info.platform_data = &atusb->platform_data; |
589 | 612 | board_info.irq = atusb->slave_irq; |
590 | 613 | |
614 | init_timer(&atusb->timer); | |
615 | atusb->timer.function = atusb_timer; | |
616 | ||
591 | 617 | tasklet_init(&atusb->task, atusb_tasklet, (unsigned long) atusb); |
592 | 618 | tasklet_disable(&atusb->task); |
593 | 619 | atusb_arm_interrupt(atusb); |
... | ... | |
638 | 664 | if (atusb->irq_urb) |
639 | 665 | usb_kill_urb(atusb->irq_urb); |
640 | 666 | |
667 | BUG_ON(timer_pending(&atusb->timer)); | |
668 | ||
641 | 669 | usb_set_intfdata(interface, NULL); |
642 | 670 | usb_put_dev(atusb->udev); |
643 | 671 |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
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