Linux-libre 3.7.6-gnu1
[librecmc/linux-libre.git] / drivers / usb / host / ohci-cns3xxx.c
1 /*
2  * Copyright 2008 Cavium Networks
3  *
4  * This file is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License, Version 2, as
6  * published by the Free Software Foundation.
7  */
8
9 #include <linux/platform_device.h>
10 #include <linux/atomic.h>
11 #include <mach/cns3xxx.h>
12 #include <mach/pm.h>
13
14 static int __devinit
15 cns3xxx_ohci_start(struct usb_hcd *hcd)
16 {
17         struct ohci_hcd *ohci = hcd_to_ohci(hcd);
18         int ret;
19
20         /*
21          * EHCI and OHCI share the same clock and power,
22          * resetting twice would cause the 1st controller been reset.
23          * Therefore only do power up  at the first up device, and
24          * power down at the last down device.
25          *
26          * Set USB AHB INCR length to 16
27          */
28         if (atomic_inc_return(&usb_pwr_ref) == 1) {
29                 cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB);
30                 cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
31                 cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST);
32                 __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)),
33                         MISC_CHIP_CONFIG_REG);
34         }
35
36         ret = ohci_init(ohci);
37         if (ret < 0)
38                 return ret;
39
40         ohci->num_ports = 1;
41
42         ret = ohci_run(ohci);
43         if (ret < 0) {
44                 dev_err(hcd->self.controller, "can't start %s\n",
45                         hcd->self.bus_name);
46                 ohci_stop(hcd);
47                 return ret;
48         }
49         return 0;
50 }
51
52 static const struct hc_driver cns3xxx_ohci_hc_driver = {
53         .description            = hcd_name,
54         .product_desc           = "CNS3XXX OHCI Host controller",
55         .hcd_priv_size          = sizeof(struct ohci_hcd),
56         .irq                    = ohci_irq,
57         .flags                  = HCD_USB11 | HCD_MEMORY,
58         .start                  = cns3xxx_ohci_start,
59         .stop                   = ohci_stop,
60         .shutdown               = ohci_shutdown,
61         .urb_enqueue            = ohci_urb_enqueue,
62         .urb_dequeue            = ohci_urb_dequeue,
63         .endpoint_disable       = ohci_endpoint_disable,
64         .get_frame_number       = ohci_get_frame,
65         .hub_status_data        = ohci_hub_status_data,
66         .hub_control            = ohci_hub_control,
67 #ifdef CONFIG_PM
68         .bus_suspend            = ohci_bus_suspend,
69         .bus_resume             = ohci_bus_resume,
70 #endif
71         .start_port_reset       = ohci_start_port_reset,
72 };
73
74 static int cns3xxx_ohci_probe(struct platform_device *pdev)
75 {
76         struct device *dev = &pdev->dev;
77         struct usb_hcd *hcd;
78         const struct hc_driver *driver = &cns3xxx_ohci_hc_driver;
79         struct resource *res;
80         int irq;
81         int retval;
82
83         if (usb_disabled())
84                 return -ENODEV;
85
86         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
87         if (!res) {
88                 dev_err(dev, "Found HC with no IRQ.\n");
89                 return -ENODEV;
90         }
91         irq = res->start;
92
93         hcd = usb_create_hcd(driver, dev, dev_name(dev));
94         if (!hcd)
95                 return -ENOMEM;
96
97         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
98         if (!res) {
99                 dev_err(dev, "Found HC with no register addr.\n");
100                 retval = -ENODEV;
101                 goto err1;
102         }
103         hcd->rsrc_start = res->start;
104         hcd->rsrc_len = resource_size(res);
105
106         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
107                         driver->description)) {
108                 dev_dbg(dev, "controller already in use\n");
109                 retval = -EBUSY;
110                 goto err1;
111         }
112
113         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
114         if (!hcd->regs) {
115                 dev_dbg(dev, "error mapping memory\n");
116                 retval = -EFAULT;
117                 goto err2;
118         }
119
120         ohci_hcd_init(hcd_to_ohci(hcd));
121
122         retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
123         if (retval == 0)
124                 return retval;
125
126         iounmap(hcd->regs);
127 err2:
128         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
129 err1:
130         usb_put_hcd(hcd);
131         return retval;
132 }
133
134 static int cns3xxx_ohci_remove(struct platform_device *pdev)
135 {
136         struct usb_hcd *hcd = platform_get_drvdata(pdev);
137
138         usb_remove_hcd(hcd);
139         iounmap(hcd->regs);
140         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
141
142         /*
143          * EHCI and OHCI share the same clock and power,
144          * resetting twice would cause the 1st controller been reset.
145          * Therefore only do power up  at the first up device, and
146          * power down at the last down device.
147          */
148         if (atomic_dec_return(&usb_pwr_ref) == 0)
149                 cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
150
151         usb_put_hcd(hcd);
152
153         platform_set_drvdata(pdev, NULL);
154
155         return 0;
156 }
157
158 MODULE_ALIAS("platform:cns3xxx-ohci");
159
160 static struct platform_driver ohci_hcd_cns3xxx_driver = {
161         .probe = cns3xxx_ohci_probe,
162         .remove = cns3xxx_ohci_remove,
163         .driver = {
164                 .name = "cns3xxx-ohci",
165         },
166 };