move files to files-2.6.30, to ease newer kernel integration
[openwrt/openwrt.git] / target / linux / brcm63xx / files-2.6.30 / drivers / usb / host / ohci-bcm63xx.c
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7 */
8
9 #include <linux/init.h>
10 #include <linux/clk.h>
11 #include <linux/platform_device.h>
12 #include <bcm63xx_cpu.h>
13 #include <bcm63xx_regs.h>
14 #include <bcm63xx_io.h>
15
16 static struct clk *usb_host_clock;
17
18 static int __devinit ohci_bcm63xx_start(struct usb_hcd *hcd)
19 {
20 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
21 int ret;
22
23 ret = ohci_init(ohci);
24 if (ret < 0)
25 return ret;
26
27 /* FIXME: autodetected port 2 is shared with USB slave */
28
29 ret = ohci_run(ohci);
30 if (ret < 0) {
31 err("can't start %s", hcd->self.bus_name);
32 ohci_stop(hcd);
33 return ret;
34 }
35 return 0;
36 }
37
38 static const struct hc_driver ohci_bcm63xx_hc_driver = {
39 .description = hcd_name,
40 .product_desc = "BCM63XX integrated OHCI controller",
41 .hcd_priv_size = sizeof(struct ohci_hcd),
42
43 .irq = ohci_irq,
44 .flags = HCD_USB11 | HCD_MEMORY,
45 .start = ohci_bcm63xx_start,
46 .stop = ohci_stop,
47 .shutdown = ohci_shutdown,
48 .urb_enqueue = ohci_urb_enqueue,
49 .urb_dequeue = ohci_urb_dequeue,
50 .endpoint_disable = ohci_endpoint_disable,
51 .get_frame_number = ohci_get_frame,
52 .hub_status_data = ohci_hub_status_data,
53 .hub_control = ohci_hub_control,
54 .start_port_reset = ohci_start_port_reset,
55 };
56
57 static int __devinit ohci_hcd_bcm63xx_drv_probe(struct platform_device *pdev)
58 {
59 struct resource *res_mem, *res_irq;
60 struct usb_hcd *hcd;
61 struct ohci_hcd *ohci;
62 u32 reg;
63 int ret;
64
65 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
66 res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
67 if (!res_mem || !res_irq)
68 return -ENODEV;
69
70 if (BCMCPU_IS_6348()) {
71 struct clk *clk;
72 /* enable USB host clock */
73 clk = clk_get(&pdev->dev, "usbh");
74 if (IS_ERR(clk))
75 return -ENODEV;
76
77 clk_enable(clk);
78 usb_host_clock = clk;
79 bcm_rset_writel(RSET_OHCI_PRIV, 0, OHCI_PRIV_REG);
80
81 } else if (BCMCPU_IS_6358()) {
82 reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_REG);
83 reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
84 reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
85 bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_REG);
86 /* don't ask... */
87 bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020, USBH_PRIV_TEST_REG);
88 } else
89 return 0;
90
91 hcd = usb_create_hcd(&ohci_bcm63xx_hc_driver, &pdev->dev, "bcm63xx");
92 if (!hcd)
93 return -ENOMEM;
94 hcd->rsrc_start = res_mem->start;
95 hcd->rsrc_len = res_mem->end - res_mem->start + 1;
96
97 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
98 pr_debug("request_mem_region failed\n");
99 ret = -EBUSY;
100 goto out;
101 }
102
103 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
104 if (!hcd->regs) {
105 pr_debug("ioremap failed\n");
106 ret = -EIO;
107 goto out1;
108 }
109
110 ohci = hcd_to_ohci(hcd);
111 ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC |
112 OHCI_QUIRK_FRAME_NO;
113 ohci_hcd_init(ohci);
114
115 ret = usb_add_hcd(hcd, res_irq->start, IRQF_DISABLED);
116 if (ret)
117 goto out2;
118
119 platform_set_drvdata(pdev, hcd);
120 return 0;
121
122 out2:
123 iounmap(hcd->regs);
124 out1:
125 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
126 out:
127 usb_put_hcd(hcd);
128 return ret;
129 }
130
131 static int __devexit ohci_hcd_bcm63xx_drv_remove(struct platform_device *pdev)
132 {
133 struct usb_hcd *hcd;
134
135 hcd = platform_get_drvdata(pdev);
136 usb_remove_hcd(hcd);
137 iounmap(hcd->regs);
138 usb_put_hcd(hcd);
139 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
140 if (usb_host_clock) {
141 clk_disable(usb_host_clock);
142 clk_put(usb_host_clock);
143 }
144 platform_set_drvdata(pdev, NULL);
145 return 0;
146 }
147
148 static struct platform_driver ohci_hcd_bcm63xx_driver = {
149 .probe = ohci_hcd_bcm63xx_drv_probe,
150 .remove = __devexit_p(ohci_hcd_bcm63xx_drv_remove),
151 .shutdown = usb_hcd_platform_shutdown,
152 .driver = {
153 .name = "bcm63xx_ohci",
154 .owner = THIS_MODULE,
155 .bus = &platform_bus_type
156 },
157 };
158
159 MODULE_ALIAS("platform:bcm63xx_ohci");