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 
cns3xxx_ehci_init(struct usb_hcd * hcd)14 static int cns3xxx_ehci_init(struct usb_hcd *hcd)
15 {
16 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
17 	int retval;
18 
19 	/*
20 	 * EHCI and OHCI share the same clock and power,
21 	 * resetting twice would cause the 1st controller been reset.
22 	 * Therefore only do power up  at the first up device, and
23 	 * power down at the last down device.
24 	 *
25 	 * Set USB AHB INCR length to 16
26 	 */
27 	if (atomic_inc_return(&usb_pwr_ref) == 1) {
28 		cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB);
29 		cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
30 		cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST);
31 		__raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)),
32 			MISC_CHIP_CONFIG_REG);
33 	}
34 
35 	ehci->caps = hcd->regs;
36 	ehci->regs = hcd->regs
37 		+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
38 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
39 
40 	hcd->has_tt = 0;
41 	ehci_reset(ehci);
42 
43 	retval = ehci_init(hcd);
44 	if (retval)
45 		return retval;
46 
47 	ehci_port_power(ehci, 0);
48 
49 	return retval;
50 }
51 
52 static const struct hc_driver cns3xxx_ehci_hc_driver = {
53 	.description		= hcd_name,
54 	.product_desc		= "CNS3XXX EHCI Host Controller",
55 	.hcd_priv_size		= sizeof(struct ehci_hcd),
56 	.irq			= ehci_irq,
57 	.flags			= HCD_MEMORY | HCD_USB2,
58 	.reset			= cns3xxx_ehci_init,
59 	.start			= ehci_run,
60 	.stop			= ehci_stop,
61 	.shutdown		= ehci_shutdown,
62 	.urb_enqueue		= ehci_urb_enqueue,
63 	.urb_dequeue		= ehci_urb_dequeue,
64 	.endpoint_disable	= ehci_endpoint_disable,
65 	.endpoint_reset		= ehci_endpoint_reset,
66 	.get_frame_number	= ehci_get_frame,
67 	.hub_status_data	= ehci_hub_status_data,
68 	.hub_control		= ehci_hub_control,
69 #ifdef CONFIG_PM
70 	.bus_suspend		= ehci_bus_suspend,
71 	.bus_resume		= ehci_bus_resume,
72 #endif
73 	.relinquish_port	= ehci_relinquish_port,
74 	.port_handed_over	= ehci_port_handed_over,
75 
76 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
77 };
78 
cns3xxx_ehci_probe(struct platform_device * pdev)79 static int cns3xxx_ehci_probe(struct platform_device *pdev)
80 {
81 	struct device *dev = &pdev->dev;
82 	struct usb_hcd *hcd;
83 	const struct hc_driver *driver = &cns3xxx_ehci_hc_driver;
84 	struct resource *res;
85 	int irq;
86 	int retval;
87 
88 	if (usb_disabled())
89 		return -ENODEV;
90 
91 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
92 	if (!res) {
93 		dev_err(dev, "Found HC with no IRQ.\n");
94 		return -ENODEV;
95 	}
96 	irq = res->start;
97 
98 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
99 	if (!hcd)
100 		return -ENOMEM;
101 
102 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
103 	if (!res) {
104 		dev_err(dev, "Found HC with no register addr.\n");
105 		retval = -ENODEV;
106 		goto err1;
107 	}
108 
109 	hcd->rsrc_start = res->start;
110 	hcd->rsrc_len = resource_size(res);
111 
112 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
113 				driver->description)) {
114 		dev_dbg(dev, "controller already in use\n");
115 		retval = -EBUSY;
116 		goto err1;
117 	}
118 
119 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
120 	if (hcd->regs == NULL) {
121 		dev_dbg(dev, "error mapping memory\n");
122 		retval = -EFAULT;
123 		goto err2;
124 	}
125 
126 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
127 	if (retval == 0)
128 		return retval;
129 
130 	iounmap(hcd->regs);
131 err2:
132 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
133 err1:
134 	usb_put_hcd(hcd);
135 
136 	return retval;
137 }
138 
cns3xxx_ehci_remove(struct platform_device * pdev)139 static int cns3xxx_ehci_remove(struct platform_device *pdev)
140 {
141 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
142 
143 	usb_remove_hcd(hcd);
144 	iounmap(hcd->regs);
145 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
146 
147 	/*
148 	 * EHCI and OHCI share the same clock and power,
149 	 * resetting twice would cause the 1st controller been reset.
150 	 * Therefore only do power up  at the first up device, and
151 	 * power down at the last down device.
152 	 */
153 	if (atomic_dec_return(&usb_pwr_ref) == 0)
154 		cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
155 
156 	usb_put_hcd(hcd);
157 
158 	platform_set_drvdata(pdev, NULL);
159 
160 	return 0;
161 }
162 
163 MODULE_ALIAS("platform:cns3xxx-ehci");
164 
165 static struct platform_driver cns3xxx_ehci_driver = {
166 	.probe = cns3xxx_ehci_probe,
167 	.remove = cns3xxx_ehci_remove,
168 	.driver = {
169 		.name = "cns3xxx-ehci",
170 	},
171 };
172