1/*
2 * OHCI HCD for Netlogic XLS processors.
3 *
4 * (C) Copyright 2011 Netlogic Microsystems Inc.
5 *
6 *  Based on ohci-au1xxx.c, and other Linux OHCI drivers.
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License.  See the file COPYING in the main directory of this archive for
10 * more details.
11 */
12
13#include <linux/platform_device.h>
14#include <linux/signal.h>
15
16static int ohci_xls_probe_internal(const struct hc_driver *driver,
17			struct platform_device *dev)
18{
19	struct resource *res;
20	struct usb_hcd *hcd;
21	int retval, irq;
22
23	/* Get our IRQ from an earlier registered Platform Resource */
24	irq = platform_get_irq(dev, 0);
25	if (irq < 0) {
26		dev_err(&dev->dev, "Found HC with no IRQ\n");
27		return -ENODEV;
28	}
29
30	/* Get our Memory Handle */
31	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
32	if (!res) {
33		dev_err(&dev->dev, "MMIO Handle incorrect!\n");
34		return -ENODEV;
35	}
36
37	hcd = usb_create_hcd(driver, &dev->dev, "XLS");
38	if (!hcd) {
39		retval = -ENOMEM;
40		goto err1;
41	}
42	hcd->rsrc_start = res->start;
43	hcd->rsrc_len = resource_size(res);
44
45	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
46			driver->description)) {
47		dev_dbg(&dev->dev, "Controller already in use\n");
48		retval = -EBUSY;
49		goto err2;
50	}
51
52	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
53	if (hcd->regs == NULL) {
54		dev_dbg(&dev->dev, "error mapping memory\n");
55		retval = -EFAULT;
56		goto err3;
57	}
58
59	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
60	if (retval != 0)
61		goto err4;
62	return retval;
63
64err4:
65	iounmap(hcd->regs);
66err3:
67	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
68err2:
69	usb_put_hcd(hcd);
70err1:
71	dev_err(&dev->dev, "init fail, %d\n", retval);
72	return retval;
73}
74
75static int ohci_xls_reset(struct usb_hcd *hcd)
76{
77	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
78
79	ohci_hcd_init(ohci);
80	return ohci_init(ohci);
81}
82
83static int __devinit ohci_xls_start(struct usb_hcd *hcd)
84{
85	struct ohci_hcd *ohci;
86	int ret;
87
88	ohci = hcd_to_ohci(hcd);
89	ret = ohci_run(ohci);
90	if (ret < 0) {
91		err("can't start %s", hcd->self.bus_name);
92		ohci_stop(hcd);
93		return ret;
94	}
95	return 0;
96}
97
98static struct hc_driver ohci_xls_hc_driver = {
99	.description	= hcd_name,
100	.product_desc	= "XLS OHCI Host Controller",
101	.hcd_priv_size	= sizeof(struct ohci_hcd),
102	.irq		= ohci_irq,
103	.flags		= HCD_MEMORY | HCD_USB11,
104	.reset		= ohci_xls_reset,
105	.start		= ohci_xls_start,
106	.stop		= ohci_stop,
107	.shutdown	= ohci_shutdown,
108	.urb_enqueue	= ohci_urb_enqueue,
109	.urb_dequeue	= ohci_urb_dequeue,
110	.endpoint_disable = ohci_endpoint_disable,
111	.get_frame_number = ohci_get_frame,
112	.hub_status_data = ohci_hub_status_data,
113	.hub_control	= ohci_hub_control,
114#ifdef CONFIG_PM
115	.bus_suspend	= ohci_bus_suspend,
116	.bus_resume	= ohci_bus_resume,
117#endif
118	.start_port_reset = ohci_start_port_reset,
119};
120
121static int ohci_xls_probe(struct platform_device *dev)
122{
123	int ret;
124
125	pr_debug("In ohci_xls_probe");
126	if (usb_disabled())
127		return -ENODEV;
128	ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev);
129	return ret;
130}
131
132static int ohci_xls_remove(struct platform_device *dev)
133{
134	struct usb_hcd *hcd = platform_get_drvdata(dev);
135
136	usb_remove_hcd(hcd);
137	iounmap(hcd->regs);
138	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
139	usb_put_hcd(hcd);
140	return 0;
141}
142
143static struct platform_driver ohci_xls_driver = {
144	.probe		= ohci_xls_probe,
145	.remove		= ohci_xls_remove,
146	.shutdown	= usb_hcd_platform_shutdown,
147	.driver		= {
148		.name	= "ohci-xls-0",
149		.owner	= THIS_MODULE,
150	},
151};
152