diff options
author | Anatolij Gustschin <agust@denx.de> | 2011-04-18 16:02:00 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-02 19:59:38 -0400 |
commit | 83722bc9430424de1614ff31696f73a40b3d81a9 (patch) | |
tree | 4ff0ffe40e080ee03b9ede04b3e943b79335335f /drivers/usb/host | |
parent | 0807c500a1a6d7fa20cbd7bbe7fea14a66112463 (diff) |
USB: extend ehci-fsl and fsl_udc_core driver for OTG operation
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Li Yang <leoli@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 66 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 4 |
3 files changed, 78 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index caf3d4ac42bd..623732a312dd 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c | |||
@@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, | |||
117 | 117 | ||
118 | pdata->regs = hcd->regs; | 118 | pdata->regs = hcd->regs; |
119 | 119 | ||
120 | if (pdata->power_budget) | ||
121 | hcd->power_budget = pdata->power_budget; | ||
122 | |||
120 | /* | 123 | /* |
121 | * do platform specific init: check the clock, grab/config pins, etc. | 124 | * do platform specific init: check the clock, grab/config pins, etc. |
122 | */ | 125 | */ |
@@ -134,6 +137,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, | |||
134 | retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); | 137 | retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); |
135 | if (retval != 0) | 138 | if (retval != 0) |
136 | goto err4; | 139 | goto err4; |
140 | |||
141 | #ifdef CONFIG_USB_OTG | ||
142 | if (pdata->operating_mode == FSL_USB2_DR_OTG) { | ||
143 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
144 | |||
145 | ehci->transceiver = otg_get_transceiver(); | ||
146 | dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n", | ||
147 | hcd, ehci, ehci->transceiver); | ||
148 | |||
149 | if (ehci->transceiver) { | ||
150 | retval = otg_set_host(ehci->transceiver, | ||
151 | &ehci_to_hcd(ehci)->self); | ||
152 | if (retval) { | ||
153 | if (ehci->transceiver) | ||
154 | put_device(ehci->transceiver->dev); | ||
155 | goto err4; | ||
156 | } | ||
157 | } else { | ||
158 | dev_err(&pdev->dev, "can't find transceiver\n"); | ||
159 | retval = -ENODEV; | ||
160 | goto err4; | ||
161 | } | ||
162 | } | ||
163 | #endif | ||
137 | return retval; | 164 | return retval; |
138 | 165 | ||
139 | err4: | 166 | err4: |
@@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, | |||
164 | struct platform_device *pdev) | 191 | struct platform_device *pdev) |
165 | { | 192 | { |
166 | struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; | 193 | struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; |
194 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
195 | |||
196 | if (ehci->transceiver) { | ||
197 | otg_set_host(ehci->transceiver, NULL); | ||
198 | put_device(ehci->transceiver->dev); | ||
199 | } | ||
167 | 200 | ||
168 | usb_remove_hcd(hcd); | 201 | usb_remove_hcd(hcd); |
169 | 202 | ||
@@ -544,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = { | |||
544 | #define EHCI_FSL_PM_OPS NULL | 577 | #define EHCI_FSL_PM_OPS NULL |
545 | #endif /* CONFIG_PM */ | 578 | #endif /* CONFIG_PM */ |
546 | 579 | ||
580 | #ifdef CONFIG_USB_OTG | ||
581 | static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) | ||
582 | { | ||
583 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
584 | u32 status; | ||
585 | |||
586 | if (!port) | ||
587 | return -EINVAL; | ||
588 | |||
589 | port--; | ||
590 | |||
591 | /* start port reset before HNP protocol time out */ | ||
592 | status = readl(&ehci->regs->port_status[port]); | ||
593 | if (!(status & PORT_CONNECT)) | ||
594 | return -ENODEV; | ||
595 | |||
596 | /* khubd will finish the reset later */ | ||
597 | if (ehci_is_TDI(ehci)) { | ||
598 | writel(PORT_RESET | | ||
599 | (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)), | ||
600 | &ehci->regs->port_status[port]); | ||
601 | } else { | ||
602 | writel(PORT_RESET, &ehci->regs->port_status[port]); | ||
603 | } | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | #else | ||
608 | #define ehci_start_port_reset NULL | ||
609 | #endif /* CONFIG_USB_OTG */ | ||
610 | |||
611 | |||
547 | static const struct hc_driver ehci_fsl_hc_driver = { | 612 | static const struct hc_driver ehci_fsl_hc_driver = { |
548 | .description = hcd_name, | 613 | .description = hcd_name, |
549 | .product_desc = "Freescale On-Chip EHCI Host Controller", | 614 | .product_desc = "Freescale On-Chip EHCI Host Controller", |
@@ -583,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { | |||
583 | .hub_control = ehci_hub_control, | 648 | .hub_control = ehci_hub_control, |
584 | .bus_suspend = ehci_bus_suspend, | 649 | .bus_suspend = ehci_bus_suspend, |
585 | .bus_resume = ehci_bus_resume, | 650 | .bus_resume = ehci_bus_resume, |
651 | .start_port_reset = ehci_start_port_reset, | ||
586 | .relinquish_port = ehci_relinquish_port, | 652 | .relinquish_port = ehci_relinquish_port, |
587 | .port_handed_over = ehci_port_handed_over, | 653 | .port_handed_over = ehci_port_handed_over, |
588 | 654 | ||
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 1a21799195af..ea6184bf48d0 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -27,6 +27,7 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | /*-------------------------------------------------------------------------*/ | 29 | /*-------------------------------------------------------------------------*/ |
30 | #include <linux/usb/otg.h> | ||
30 | 31 | ||
31 | #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) | 32 | #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) |
32 | 33 | ||
@@ -801,6 +802,13 @@ static int ehci_hub_control ( | |||
801 | goto error; | 802 | goto error; |
802 | if (ehci->no_selective_suspend) | 803 | if (ehci->no_selective_suspend) |
803 | break; | 804 | break; |
805 | #ifdef CONFIG_USB_OTG | ||
806 | if ((hcd->self.otg_port == (wIndex + 1)) | ||
807 | && hcd->self.b_hnp_enable) { | ||
808 | otg_start_hnp(ehci->transceiver); | ||
809 | break; | ||
810 | } | ||
811 | #endif | ||
804 | if (!(temp & PORT_SUSPEND)) | 812 | if (!(temp & PORT_SUSPEND)) |
805 | break; | 813 | break; |
806 | if ((temp & PORT_PE) == 0) | 814 | if ((temp & PORT_PE) == 0) |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 168f1a88c4d0..e9ba8e252489 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -161,6 +161,10 @@ struct ehci_hcd { /* one per controller */ | |||
161 | #ifdef DEBUG | 161 | #ifdef DEBUG |
162 | struct dentry *debug_dir; | 162 | struct dentry *debug_dir; |
163 | #endif | 163 | #endif |
164 | /* | ||
165 | * OTG controllers and transceivers need software interaction | ||
166 | */ | ||
167 | struct otg_transceiver *transceiver; | ||
164 | }; | 168 | }; |
165 | 169 | ||
166 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 170 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |