diff options
author | Harro Haan <hrhaan@gmail.com> | 2010-03-01 12:01:56 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-06-16 18:00:00 -0400 |
commit | 4f4c5e36e7cd26c9b5bf89d66caeee5fc3d75362 (patch) | |
tree | 55a751f86e75d5f8e59b9a0dc610e701dba74917 /drivers/usb/gadget/at91_udc.c | |
parent | 7e27d6e778cd87b6f2415515d7127eba53fe5d02 (diff) |
ARM: 5967/1: at91_udc.c use spinlocks instead of local_irq_xxx
The locking code of this driver is reworked for preempt-rt.
For more info see:
http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100203/09cdb3b4/attachment.el
http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100203/3ad44e30/attachment.el
First applied: "at91_udc HW glitch"
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5966/1
Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/usb/gadget/at91_udc.c')
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 139 |
1 files changed, 93 insertions, 46 deletions
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index eaa79c8a9b8c..fd6a7577ad25 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c | |||
@@ -77,10 +77,10 @@ static const char driver_name [] = "at91_udc"; | |||
77 | static const char ep0name[] = "ep0"; | 77 | static const char ep0name[] = "ep0"; |
78 | 78 | ||
79 | 79 | ||
80 | #define at91_udp_read(dev, reg) \ | 80 | #define at91_udp_read(udc, reg) \ |
81 | __raw_readl((dev)->udp_baseaddr + (reg)) | 81 | __raw_readl((udc)->udp_baseaddr + (reg)) |
82 | #define at91_udp_write(dev, reg, val) \ | 82 | #define at91_udp_write(udc, reg, val) \ |
83 | __raw_writel((val), (dev)->udp_baseaddr + (reg)) | 83 | __raw_writel((val), (udc)->udp_baseaddr + (reg)) |
84 | 84 | ||
85 | /*-------------------------------------------------------------------------*/ | 85 | /*-------------------------------------------------------------------------*/ |
86 | 86 | ||
@@ -102,8 +102,9 @@ static void proc_ep_show(struct seq_file *s, struct at91_ep *ep) | |||
102 | u32 csr; | 102 | u32 csr; |
103 | struct at91_request *req; | 103 | struct at91_request *req; |
104 | unsigned long flags; | 104 | unsigned long flags; |
105 | struct at91_udc *udc = ep->udc; | ||
105 | 106 | ||
106 | local_irq_save(flags); | 107 | spin_lock_irqsave(&udc->lock, flags); |
107 | 108 | ||
108 | csr = __raw_readl(ep->creg); | 109 | csr = __raw_readl(ep->creg); |
109 | 110 | ||
@@ -147,7 +148,7 @@ static void proc_ep_show(struct seq_file *s, struct at91_ep *ep) | |||
147 | &req->req, length, | 148 | &req->req, length, |
148 | req->req.length, req->req.buf); | 149 | req->req.length, req->req.buf); |
149 | } | 150 | } |
150 | local_irq_restore(flags); | 151 | spin_unlock_irqrestore(&udc->lock, flags); |
151 | } | 152 | } |
152 | 153 | ||
153 | static void proc_irq_show(struct seq_file *s, const char *label, u32 mask) | 154 | static void proc_irq_show(struct seq_file *s, const char *label, u32 mask) |
@@ -272,7 +273,9 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status) | |||
272 | VDBG("%s done %p, status %d\n", ep->ep.name, req, status); | 273 | VDBG("%s done %p, status %d\n", ep->ep.name, req, status); |
273 | 274 | ||
274 | ep->stopped = 1; | 275 | ep->stopped = 1; |
276 | spin_unlock(&udc->lock); | ||
275 | req->req.complete(&ep->ep, &req->req); | 277 | req->req.complete(&ep->ep, &req->req); |
278 | spin_lock(&udc->lock); | ||
276 | ep->stopped = stopped; | 279 | ep->stopped = stopped; |
277 | 280 | ||
278 | /* ep0 is always ready; other endpoints need a non-empty queue */ | 281 | /* ep0 is always ready; other endpoints need a non-empty queue */ |
@@ -472,7 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep, | |||
472 | const struct usb_endpoint_descriptor *desc) | 475 | const struct usb_endpoint_descriptor *desc) |
473 | { | 476 | { |
474 | struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); | 477 | struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); |
475 | struct at91_udc *dev = ep->udc; | 478 | struct at91_udc *udc = ep->udc; |
476 | u16 maxpacket; | 479 | u16 maxpacket; |
477 | u32 tmp; | 480 | u32 tmp; |
478 | unsigned long flags; | 481 | unsigned long flags; |
@@ -487,7 +490,7 @@ static int at91_ep_enable(struct usb_ep *_ep, | |||
487 | return -EINVAL; | 490 | return -EINVAL; |
488 | } | 491 | } |
489 | 492 | ||
490 | if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { | 493 | if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { |
491 | DBG("bogus device state\n"); | 494 | DBG("bogus device state\n"); |
492 | return -ESHUTDOWN; | 495 | return -ESHUTDOWN; |
493 | } | 496 | } |
@@ -521,7 +524,7 @@ bogus_max: | |||
521 | } | 524 | } |
522 | 525 | ||
523 | ok: | 526 | ok: |
524 | local_irq_save(flags); | 527 | spin_lock_irqsave(&udc->lock, flags); |
525 | 528 | ||
526 | /* initialize endpoint to match this descriptor */ | 529 | /* initialize endpoint to match this descriptor */ |
527 | ep->is_in = usb_endpoint_dir_in(desc); | 530 | ep->is_in = usb_endpoint_dir_in(desc); |
@@ -540,10 +543,10 @@ ok: | |||
540 | * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, | 543 | * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, |
541 | * since endpoint resets don't reset hw pingpong state. | 544 | * since endpoint resets don't reset hw pingpong state. |
542 | */ | 545 | */ |
543 | at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask); | 546 | at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); |
544 | at91_udp_write(dev, AT91_UDP_RST_EP, 0); | 547 | at91_udp_write(udc, AT91_UDP_RST_EP, 0); |
545 | 548 | ||
546 | local_irq_restore(flags); | 549 | spin_unlock_irqrestore(&udc->lock, flags); |
547 | return 0; | 550 | return 0; |
548 | } | 551 | } |
549 | 552 | ||
@@ -556,7 +559,7 @@ static int at91_ep_disable (struct usb_ep * _ep) | |||
556 | if (ep == &ep->udc->ep[0]) | 559 | if (ep == &ep->udc->ep[0]) |
557 | return -EINVAL; | 560 | return -EINVAL; |
558 | 561 | ||
559 | local_irq_save(flags); | 562 | spin_lock_irqsave(&udc->lock, flags); |
560 | 563 | ||
561 | nuke(ep, -ESHUTDOWN); | 564 | nuke(ep, -ESHUTDOWN); |
562 | 565 | ||
@@ -571,7 +574,7 @@ static int at91_ep_disable (struct usb_ep * _ep) | |||
571 | __raw_writel(0, ep->creg); | 574 | __raw_writel(0, ep->creg); |
572 | } | 575 | } |
573 | 576 | ||
574 | local_irq_restore(flags); | 577 | spin_unlock_irqrestore(&udc->lock, flags); |
575 | return 0; | 578 | return 0; |
576 | } | 579 | } |
577 | 580 | ||
@@ -607,7 +610,7 @@ static int at91_ep_queue(struct usb_ep *_ep, | |||
607 | { | 610 | { |
608 | struct at91_request *req; | 611 | struct at91_request *req; |
609 | struct at91_ep *ep; | 612 | struct at91_ep *ep; |
610 | struct at91_udc *dev; | 613 | struct at91_udc *udc; |
611 | int status; | 614 | int status; |
612 | unsigned long flags; | 615 | unsigned long flags; |
613 | 616 | ||
@@ -625,9 +628,9 @@ static int at91_ep_queue(struct usb_ep *_ep, | |||
625 | return -EINVAL; | 628 | return -EINVAL; |
626 | } | 629 | } |
627 | 630 | ||
628 | dev = ep->udc; | 631 | udc = ep->udc; |
629 | 632 | ||
630 | if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { | 633 | if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { |
631 | DBG("invalid device\n"); | 634 | DBG("invalid device\n"); |
632 | return -EINVAL; | 635 | return -EINVAL; |
633 | } | 636 | } |
@@ -635,7 +638,7 @@ static int at91_ep_queue(struct usb_ep *_ep, | |||
635 | _req->status = -EINPROGRESS; | 638 | _req->status = -EINPROGRESS; |
636 | _req->actual = 0; | 639 | _req->actual = 0; |
637 | 640 | ||
638 | local_irq_save(flags); | 641 | spin_lock_irqsave(&udc->lock, flags); |
639 | 642 | ||
640 | /* try to kickstart any empty and idle queue */ | 643 | /* try to kickstart any empty and idle queue */ |
641 | if (list_empty(&ep->queue) && !ep->stopped) { | 644 | if (list_empty(&ep->queue) && !ep->stopped) { |
@@ -653,7 +656,7 @@ static int at91_ep_queue(struct usb_ep *_ep, | |||
653 | if (is_ep0) { | 656 | if (is_ep0) { |
654 | u32 tmp; | 657 | u32 tmp; |
655 | 658 | ||
656 | if (!dev->req_pending) { | 659 | if (!udc->req_pending) { |
657 | status = -EINVAL; | 660 | status = -EINVAL; |
658 | goto done; | 661 | goto done; |
659 | } | 662 | } |
@@ -662,11 +665,11 @@ static int at91_ep_queue(struct usb_ep *_ep, | |||
662 | * defer changing CONFG until after the gadget driver | 665 | * defer changing CONFG until after the gadget driver |
663 | * reconfigures the endpoints. | 666 | * reconfigures the endpoints. |
664 | */ | 667 | */ |
665 | if (dev->wait_for_config_ack) { | 668 | if (udc->wait_for_config_ack) { |
666 | tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT); | 669 | tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); |
667 | tmp ^= AT91_UDP_CONFG; | 670 | tmp ^= AT91_UDP_CONFG; |
668 | VDBG("toggle config\n"); | 671 | VDBG("toggle config\n"); |
669 | at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp); | 672 | at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); |
670 | } | 673 | } |
671 | if (req->req.length == 0) { | 674 | if (req->req.length == 0) { |
672 | ep0_in_status: | 675 | ep0_in_status: |
@@ -676,7 +679,7 @@ ep0_in_status: | |||
676 | tmp &= ~SET_FX; | 679 | tmp &= ~SET_FX; |
677 | tmp |= CLR_FX | AT91_UDP_TXPKTRDY; | 680 | tmp |= CLR_FX | AT91_UDP_TXPKTRDY; |
678 | __raw_writel(tmp, ep->creg); | 681 | __raw_writel(tmp, ep->creg); |
679 | dev->req_pending = 0; | 682 | udc->req_pending = 0; |
680 | goto done; | 683 | goto done; |
681 | } | 684 | } |
682 | } | 685 | } |
@@ -695,31 +698,40 @@ ep0_in_status: | |||
695 | 698 | ||
696 | if (req && !status) { | 699 | if (req && !status) { |
697 | list_add_tail (&req->queue, &ep->queue); | 700 | list_add_tail (&req->queue, &ep->queue); |
698 | at91_udp_write(dev, AT91_UDP_IER, ep->int_mask); | 701 | at91_udp_write(udc, AT91_UDP_IER, ep->int_mask); |
699 | } | 702 | } |
700 | done: | 703 | done: |
701 | local_irq_restore(flags); | 704 | spin_unlock_irqrestore(&udc->lock, flags); |
702 | return (status < 0) ? status : 0; | 705 | return (status < 0) ? status : 0; |
703 | } | 706 | } |
704 | 707 | ||
705 | static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) | 708 | static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) |
706 | { | 709 | { |
707 | struct at91_ep *ep; | 710 | struct at91_ep *ep; |
708 | struct at91_request *req; | 711 | struct at91_request *req; |
712 | unsigned long flags; | ||
713 | struct at91_udc *udc; | ||
709 | 714 | ||
710 | ep = container_of(_ep, struct at91_ep, ep); | 715 | ep = container_of(_ep, struct at91_ep, ep); |
711 | if (!_ep || ep->ep.name == ep0name) | 716 | if (!_ep || ep->ep.name == ep0name) |
712 | return -EINVAL; | 717 | return -EINVAL; |
713 | 718 | ||
719 | udc = ep->udc; | ||
720 | |||
721 | spin_lock_irqsave(&udc->lock, flags); | ||
722 | |||
714 | /* make sure it's actually queued on this endpoint */ | 723 | /* make sure it's actually queued on this endpoint */ |
715 | list_for_each_entry (req, &ep->queue, queue) { | 724 | list_for_each_entry (req, &ep->queue, queue) { |
716 | if (&req->req == _req) | 725 | if (&req->req == _req) |
717 | break; | 726 | break; |
718 | } | 727 | } |
719 | if (&req->req != _req) | 728 | if (&req->req != _req) { |
729 | spin_unlock_irqrestore(&udc->lock, flags); | ||
720 | return -EINVAL; | 730 | return -EINVAL; |
731 | } | ||
721 | 732 | ||
722 | done(ep, req, -ECONNRESET); | 733 | done(ep, req, -ECONNRESET); |
734 | spin_unlock_irqrestore(&udc->lock, flags); | ||
723 | return 0; | 735 | return 0; |
724 | } | 736 | } |
725 | 737 | ||
@@ -736,7 +748,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) | |||
736 | return -EINVAL; | 748 | return -EINVAL; |
737 | 749 | ||
738 | creg = ep->creg; | 750 | creg = ep->creg; |
739 | local_irq_save(flags); | 751 | spin_lock_irqsave(&udc->lock, flags); |
740 | 752 | ||
741 | csr = __raw_readl(creg); | 753 | csr = __raw_readl(creg); |
742 | 754 | ||
@@ -761,7 +773,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) | |||
761 | __raw_writel(csr, creg); | 773 | __raw_writel(csr, creg); |
762 | } | 774 | } |
763 | 775 | ||
764 | local_irq_restore(flags); | 776 | spin_unlock_irqrestore(&udc->lock, flags); |
765 | return status; | 777 | return status; |
766 | } | 778 | } |
767 | 779 | ||
@@ -795,7 +807,7 @@ static int at91_wakeup(struct usb_gadget *gadget) | |||
795 | unsigned long flags; | 807 | unsigned long flags; |
796 | 808 | ||
797 | DBG("%s\n", __func__ ); | 809 | DBG("%s\n", __func__ ); |
798 | local_irq_save(flags); | 810 | spin_lock_irqsave(&udc->lock, flags); |
799 | 811 | ||
800 | if (!udc->clocked || !udc->suspended) | 812 | if (!udc->clocked || !udc->suspended) |
801 | goto done; | 813 | goto done; |
@@ -809,7 +821,7 @@ static int at91_wakeup(struct usb_gadget *gadget) | |||
809 | at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); | 821 | at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); |
810 | 822 | ||
811 | done: | 823 | done: |
812 | local_irq_restore(flags); | 824 | spin_unlock_irqrestore(&udc->lock, flags); |
813 | return status; | 825 | return status; |
814 | } | 826 | } |
815 | 827 | ||
@@ -851,8 +863,11 @@ static void stop_activity(struct at91_udc *udc) | |||
851 | ep->stopped = 1; | 863 | ep->stopped = 1; |
852 | nuke(ep, -ESHUTDOWN); | 864 | nuke(ep, -ESHUTDOWN); |
853 | } | 865 | } |
854 | if (driver) | 866 | if (driver) { |
867 | spin_unlock(&udc->lock); | ||
855 | driver->disconnect(&udc->gadget); | 868 | driver->disconnect(&udc->gadget); |
869 | spin_lock(&udc->lock); | ||
870 | } | ||
856 | 871 | ||
857 | udc_reinit(udc); | 872 | udc_reinit(udc); |
858 | } | 873 | } |
@@ -935,13 +950,13 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active) | |||
935 | unsigned long flags; | 950 | unsigned long flags; |
936 | 951 | ||
937 | // VDBG("vbus %s\n", is_active ? "on" : "off"); | 952 | // VDBG("vbus %s\n", is_active ? "on" : "off"); |
938 | local_irq_save(flags); | 953 | spin_lock_irqsave(&udc->lock, flags); |
939 | udc->vbus = (is_active != 0); | 954 | udc->vbus = (is_active != 0); |
940 | if (udc->driver) | 955 | if (udc->driver) |
941 | pullup(udc, is_active); | 956 | pullup(udc, is_active); |
942 | else | 957 | else |
943 | pullup(udc, 0); | 958 | pullup(udc, 0); |
944 | local_irq_restore(flags); | 959 | spin_unlock_irqrestore(&udc->lock, flags); |
945 | return 0; | 960 | return 0; |
946 | } | 961 | } |
947 | 962 | ||
@@ -950,10 +965,10 @@ static int at91_pullup(struct usb_gadget *gadget, int is_on) | |||
950 | struct at91_udc *udc = to_udc(gadget); | 965 | struct at91_udc *udc = to_udc(gadget); |
951 | unsigned long flags; | 966 | unsigned long flags; |
952 | 967 | ||
953 | local_irq_save(flags); | 968 | spin_lock_irqsave(&udc->lock, flags); |
954 | udc->enabled = is_on = !!is_on; | 969 | udc->enabled = is_on = !!is_on; |
955 | pullup(udc, is_on); | 970 | pullup(udc, is_on); |
956 | local_irq_restore(flags); | 971 | spin_unlock_irqrestore(&udc->lock, flags); |
957 | return 0; | 972 | return 0; |
958 | } | 973 | } |
959 | 974 | ||
@@ -962,9 +977,9 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) | |||
962 | struct at91_udc *udc = to_udc(gadget); | 977 | struct at91_udc *udc = to_udc(gadget); |
963 | unsigned long flags; | 978 | unsigned long flags; |
964 | 979 | ||
965 | local_irq_save(flags); | 980 | spin_lock_irqsave(&udc->lock, flags); |
966 | udc->selfpowered = (is_on != 0); | 981 | udc->selfpowered = (is_on != 0); |
967 | local_irq_restore(flags); | 982 | spin_unlock_irqrestore(&udc->lock, flags); |
968 | return 0; | 983 | return 0; |
969 | } | 984 | } |
970 | 985 | ||
@@ -1226,8 +1241,11 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | |||
1226 | #undef w_length | 1241 | #undef w_length |
1227 | 1242 | ||
1228 | /* pass request up to the gadget driver */ | 1243 | /* pass request up to the gadget driver */ |
1229 | if (udc->driver) | 1244 | if (udc->driver) { |
1245 | spin_unlock(&udc->lock); | ||
1230 | status = udc->driver->setup(&udc->gadget, &pkt.r); | 1246 | status = udc->driver->setup(&udc->gadget, &pkt.r); |
1247 | spin_lock(&udc->lock); | ||
1248 | } | ||
1231 | else | 1249 | else |
1232 | status = -ENODEV; | 1250 | status = -ENODEV; |
1233 | if (status < 0) { | 1251 | if (status < 0) { |
@@ -1378,6 +1396,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) | |||
1378 | struct at91_udc *udc = _udc; | 1396 | struct at91_udc *udc = _udc; |
1379 | u32 rescans = 5; | 1397 | u32 rescans = 5; |
1380 | int disable_clock = 0; | 1398 | int disable_clock = 0; |
1399 | unsigned long flags; | ||
1400 | |||
1401 | spin_lock_irqsave(&udc->lock, flags); | ||
1381 | 1402 | ||
1382 | if (!udc->clocked) { | 1403 | if (!udc->clocked) { |
1383 | clk_on(udc); | 1404 | clk_on(udc); |
@@ -1433,8 +1454,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) | |||
1433 | * and then into standby to avoid drawing more than | 1454 | * and then into standby to avoid drawing more than |
1434 | * 500uA power (2500uA for some high-power configs). | 1455 | * 500uA power (2500uA for some high-power configs). |
1435 | */ | 1456 | */ |
1436 | if (udc->driver && udc->driver->suspend) | 1457 | if (udc->driver && udc->driver->suspend) { |
1458 | spin_unlock(&udc->lock); | ||
1437 | udc->driver->suspend(&udc->gadget); | 1459 | udc->driver->suspend(&udc->gadget); |
1460 | spin_lock(&udc->lock); | ||
1461 | } | ||
1438 | 1462 | ||
1439 | /* host initiated resume */ | 1463 | /* host initiated resume */ |
1440 | } else if (status & AT91_UDP_RXRSM) { | 1464 | } else if (status & AT91_UDP_RXRSM) { |
@@ -1451,8 +1475,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) | |||
1451 | * would normally want to switch out of slow clock | 1475 | * would normally want to switch out of slow clock |
1452 | * mode into normal mode. | 1476 | * mode into normal mode. |
1453 | */ | 1477 | */ |
1454 | if (udc->driver && udc->driver->resume) | 1478 | if (udc->driver && udc->driver->resume) { |
1479 | spin_unlock(&udc->lock); | ||
1455 | udc->driver->resume(&udc->gadget); | 1480 | udc->driver->resume(&udc->gadget); |
1481 | spin_lock(&udc->lock); | ||
1482 | } | ||
1456 | 1483 | ||
1457 | /* endpoint IRQs are cleared by handling them */ | 1484 | /* endpoint IRQs are cleared by handling them */ |
1458 | } else { | 1485 | } else { |
@@ -1474,6 +1501,8 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) | |||
1474 | if (disable_clock) | 1501 | if (disable_clock) |
1475 | clk_off(udc); | 1502 | clk_off(udc); |
1476 | 1503 | ||
1504 | spin_unlock_irqrestore(&udc->lock, flags); | ||
1505 | |||
1477 | return IRQ_HANDLED; | 1506 | return IRQ_HANDLED; |
1478 | } | 1507 | } |
1479 | 1508 | ||
@@ -1574,6 +1603,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
1574 | { | 1603 | { |
1575 | struct at91_udc *udc = &controller; | 1604 | struct at91_udc *udc = &controller; |
1576 | int retval; | 1605 | int retval; |
1606 | unsigned long flags; | ||
1577 | 1607 | ||
1578 | if (!driver | 1608 | if (!driver |
1579 | || driver->speed < USB_SPEED_FULL | 1609 | || driver->speed < USB_SPEED_FULL |
@@ -1605,9 +1635,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
1605 | return retval; | 1635 | return retval; |
1606 | } | 1636 | } |
1607 | 1637 | ||
1608 | local_irq_disable(); | 1638 | spin_lock_irqsave(&udc->lock, flags); |
1609 | pullup(udc, 1); | 1639 | pullup(udc, 1); |
1610 | local_irq_enable(); | 1640 | spin_unlock_irqrestore(&udc->lock, flags); |
1611 | 1641 | ||
1612 | DBG("bound to %s\n", driver->driver.name); | 1642 | DBG("bound to %s\n", driver->driver.name); |
1613 | return 0; | 1643 | return 0; |
@@ -1617,15 +1647,16 @@ EXPORT_SYMBOL (usb_gadget_register_driver); | |||
1617 | int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) | 1647 | int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) |
1618 | { | 1648 | { |
1619 | struct at91_udc *udc = &controller; | 1649 | struct at91_udc *udc = &controller; |
1650 | unsigned long flags; | ||
1620 | 1651 | ||
1621 | if (!driver || driver != udc->driver || !driver->unbind) | 1652 | if (!driver || driver != udc->driver || !driver->unbind) |
1622 | return -EINVAL; | 1653 | return -EINVAL; |
1623 | 1654 | ||
1624 | local_irq_disable(); | 1655 | spin_lock_irqsave(&udc->lock, flags); |
1625 | udc->enabled = 0; | 1656 | udc->enabled = 0; |
1626 | at91_udp_write(udc, AT91_UDP_IDR, ~0); | 1657 | at91_udp_write(udc, AT91_UDP_IDR, ~0); |
1627 | pullup(udc, 0); | 1658 | pullup(udc, 0); |
1628 | local_irq_enable(); | 1659 | spin_unlock_irqrestore(&udc->lock, flags); |
1629 | 1660 | ||
1630 | driver->unbind(&udc->gadget); | 1661 | driver->unbind(&udc->gadget); |
1631 | udc->gadget.dev.driver = NULL; | 1662 | udc->gadget.dev.driver = NULL; |
@@ -1641,8 +1672,13 @@ EXPORT_SYMBOL (usb_gadget_unregister_driver); | |||
1641 | 1672 | ||
1642 | static void at91udc_shutdown(struct platform_device *dev) | 1673 | static void at91udc_shutdown(struct platform_device *dev) |
1643 | { | 1674 | { |
1675 | struct at91_udc *udc = platform_get_drvdata(dev); | ||
1676 | unsigned long flags; | ||
1677 | |||
1644 | /* force disconnect on reboot */ | 1678 | /* force disconnect on reboot */ |
1679 | spin_lock_irqsave(&udc->lock, flags); | ||
1645 | pullup(platform_get_drvdata(dev), 0); | 1680 | pullup(platform_get_drvdata(dev), 0); |
1681 | spin_unlock_irqrestore(&udc->lock, flags); | ||
1646 | } | 1682 | } |
1647 | 1683 | ||
1648 | static int __init at91udc_probe(struct platform_device *pdev) | 1684 | static int __init at91udc_probe(struct platform_device *pdev) |
@@ -1683,6 +1719,7 @@ static int __init at91udc_probe(struct platform_device *pdev) | |||
1683 | udc->board = *(struct at91_udc_data *) dev->platform_data; | 1719 | udc->board = *(struct at91_udc_data *) dev->platform_data; |
1684 | udc->pdev = pdev; | 1720 | udc->pdev = pdev; |
1685 | udc->enabled = 0; | 1721 | udc->enabled = 0; |
1722 | spin_lock_init(&udc->lock); | ||
1686 | 1723 | ||
1687 | /* rm9200 needs manual D+ pullup; off by default */ | 1724 | /* rm9200 needs manual D+ pullup; off by default */ |
1688 | if (cpu_is_at91rm9200()) { | 1725 | if (cpu_is_at91rm9200()) { |
@@ -1804,13 +1841,16 @@ static int __exit at91udc_remove(struct platform_device *pdev) | |||
1804 | { | 1841 | { |
1805 | struct at91_udc *udc = platform_get_drvdata(pdev); | 1842 | struct at91_udc *udc = platform_get_drvdata(pdev); |
1806 | struct resource *res; | 1843 | struct resource *res; |
1844 | unsigned long flags; | ||
1807 | 1845 | ||
1808 | DBG("remove\n"); | 1846 | DBG("remove\n"); |
1809 | 1847 | ||
1810 | if (udc->driver) | 1848 | if (udc->driver) |
1811 | return -EBUSY; | 1849 | return -EBUSY; |
1812 | 1850 | ||
1851 | spin_lock_irqsave(&udc->lock, flags); | ||
1813 | pullup(udc, 0); | 1852 | pullup(udc, 0); |
1853 | spin_unlock_irqrestore(&udc->lock, flags); | ||
1814 | 1854 | ||
1815 | device_init_wakeup(&pdev->dev, 0); | 1855 | device_init_wakeup(&pdev->dev, 0); |
1816 | remove_debug_file(udc); | 1856 | remove_debug_file(udc); |
@@ -1840,6 +1880,7 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
1840 | { | 1880 | { |
1841 | struct at91_udc *udc = platform_get_drvdata(pdev); | 1881 | struct at91_udc *udc = platform_get_drvdata(pdev); |
1842 | int wake = udc->driver && device_may_wakeup(&pdev->dev); | 1882 | int wake = udc->driver && device_may_wakeup(&pdev->dev); |
1883 | unsigned long flags; | ||
1843 | 1884 | ||
1844 | /* Unless we can act normally to the host (letting it wake us up | 1885 | /* Unless we can act normally to the host (letting it wake us up |
1845 | * whenever it has work for us) force disconnect. Wakeup requires | 1886 | * whenever it has work for us) force disconnect. Wakeup requires |
@@ -1849,8 +1890,10 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
1849 | if ((!udc->suspended && udc->addr) | 1890 | if ((!udc->suspended && udc->addr) |
1850 | || !wake | 1891 | || !wake |
1851 | || at91_suspend_entering_slow_clock()) { | 1892 | || at91_suspend_entering_slow_clock()) { |
1893 | spin_lock_irqsave(&udc->lock, flags); | ||
1852 | pullup(udc, 0); | 1894 | pullup(udc, 0); |
1853 | wake = 0; | 1895 | wake = 0; |
1896 | spin_unlock_irqrestore(&udc->lock, flags); | ||
1854 | } else | 1897 | } else |
1855 | enable_irq_wake(udc->udp_irq); | 1898 | enable_irq_wake(udc->udp_irq); |
1856 | 1899 | ||
@@ -1863,6 +1906,7 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
1863 | static int at91udc_resume(struct platform_device *pdev) | 1906 | static int at91udc_resume(struct platform_device *pdev) |
1864 | { | 1907 | { |
1865 | struct at91_udc *udc = platform_get_drvdata(pdev); | 1908 | struct at91_udc *udc = platform_get_drvdata(pdev); |
1909 | unsigned long flags; | ||
1866 | 1910 | ||
1867 | if (udc->board.vbus_pin > 0 && udc->active_suspend) | 1911 | if (udc->board.vbus_pin > 0 && udc->active_suspend) |
1868 | disable_irq_wake(udc->board.vbus_pin); | 1912 | disable_irq_wake(udc->board.vbus_pin); |
@@ -1870,8 +1914,11 @@ static int at91udc_resume(struct platform_device *pdev) | |||
1870 | /* maybe reconnect to host; if so, clocks on */ | 1914 | /* maybe reconnect to host; if so, clocks on */ |
1871 | if (udc->active_suspend) | 1915 | if (udc->active_suspend) |
1872 | disable_irq_wake(udc->udp_irq); | 1916 | disable_irq_wake(udc->udp_irq); |
1873 | else | 1917 | else { |
1918 | spin_lock_irqsave(&udc->lock, flags); | ||
1874 | pullup(udc, 1); | 1919 | pullup(udc, 1); |
1920 | spin_unlock_irqrestore(&udc->lock, flags); | ||
1921 | } | ||
1875 | return 0; | 1922 | return 0; |
1876 | } | 1923 | } |
1877 | #else | 1924 | #else |