Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
  3 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License as published by the
  7 * Free Software Foundation; either version 2 of the License, or (at your
  8 * option) any later version.
  9 *
 10 * This program is distributed in the hope that it will be useful, but
 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 12 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13 * for more details.
 14 *
 15 * You should have received a copy of the GNU General Public License
 16 * along with this program; if not, write to the Free Software Foundation,
 17 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 18 */
 19
 
 
 
 20#include <linux/platform_device.h>
 21#include <linux/clk.h>
 22#include <linux/delay.h>
 23#include <linux/usb/otg.h>
 24#include <linux/usb/ulpi.h>
 25#include <linux/slab.h>
 
 
 
 
 26
 27#include <mach/hardware.h>
 28#include <mach/mxc_ehci.h>
 29
 30#include <asm/mach-types.h>
 31
 32#define ULPI_VIEWPORT_OFFSET	0x170
 33
 34struct ehci_mxc_priv {
 35	struct clk *usbclk, *ahbclk, *phy1clk;
 36	struct usb_hcd *hcd;
 37};
 38
 39/* called during probe() after chip reset completes */
 40static int ehci_mxc_setup(struct usb_hcd *hcd)
 41{
 42	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 43	int retval;
 44
 45	dbg_hcs_params(ehci, "reset");
 46	dbg_hcc_params(ehci, "reset");
 47
 48	/* cache this readonly data; minimize chip reads */
 49	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 50
 51	hcd->has_tt = 1;
 52
 53	retval = ehci_halt(ehci);
 54	if (retval)
 55		return retval;
 56
 57	/* data structure init */
 58	retval = ehci_init(hcd);
 59	if (retval)
 60		return retval;
 61
 62	ehci->sbrn = 0x20;
 63
 64	ehci_reset(ehci);
 65
 66	ehci_port_power(ehci, 0);
 67	return 0;
 68}
 69
 70static const struct hc_driver ehci_mxc_hc_driver = {
 71	.description = hcd_name,
 72	.product_desc = "Freescale On-Chip EHCI Host Controller",
 73	.hcd_priv_size = sizeof(struct ehci_hcd),
 74
 75	/*
 76	 * generic hardware linkage
 77	 */
 78	.irq = ehci_irq,
 79	.flags = HCD_USB2 | HCD_MEMORY,
 80
 81	/*
 82	 * basic lifecycle operations
 83	 */
 84	.reset = ehci_mxc_setup,
 85	.start = ehci_run,
 86	.stop = ehci_stop,
 87	.shutdown = ehci_shutdown,
 88
 89	/*
 90	 * managing i/o requests and associated device resources
 91	 */
 92	.urb_enqueue = ehci_urb_enqueue,
 93	.urb_dequeue = ehci_urb_dequeue,
 94	.endpoint_disable = ehci_endpoint_disable,
 95	.endpoint_reset = ehci_endpoint_reset,
 96
 97	/*
 98	 * scheduling support
 99	 */
100	.get_frame_number = ehci_get_frame,
101
102	/*
103	 * root hub support
104	 */
105	.hub_status_data = ehci_hub_status_data,
106	.hub_control = ehci_hub_control,
107	.bus_suspend = ehci_bus_suspend,
108	.bus_resume = ehci_bus_resume,
109	.relinquish_port = ehci_relinquish_port,
110	.port_handed_over = ehci_port_handed_over,
111
112	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
113};
114
115static int ehci_mxc_drv_probe(struct platform_device *pdev)
116{
117	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
118	struct usb_hcd *hcd;
119	struct resource *res;
120	int irq, ret;
121	unsigned int flags;
122	struct ehci_mxc_priv *priv;
123	struct device *dev = &pdev->dev;
124	struct ehci_hcd *ehci;
125
126	dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
127
128	if (!pdata) {
129		dev_err(dev, "No platform data given, bailing out.\n");
130		return -EINVAL;
131	}
132
133	irq = platform_get_irq(pdev, 0);
134
135	hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
136	if (!hcd)
137		return -ENOMEM;
138
139	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
140	if (!priv) {
141		ret = -ENOMEM;
142		goto err_alloc;
143	}
144
145	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
146	if (!res) {
147		dev_err(dev, "Found HC with no register addr. Check setup!\n");
148		ret = -ENODEV;
149		goto err_get_resource;
150	}
151
152	hcd->rsrc_start = res->start;
153	hcd->rsrc_len = resource_size(res);
154
155	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
156		dev_dbg(dev, "controller already in use\n");
157		ret = -EBUSY;
158		goto err_request_mem;
159	}
160
161	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
162	if (!hcd->regs) {
163		dev_err(dev, "error mapping memory\n");
164		ret = -EFAULT;
165		goto err_ioremap;
166	}
167
168	/* enable clocks */
169	priv->usbclk = clk_get(dev, "usb");
170	if (IS_ERR(priv->usbclk)) {
171		ret = PTR_ERR(priv->usbclk);
172		goto err_clk;
173	}
174	clk_enable(priv->usbclk);
175
176	if (!cpu_is_mx35() && !cpu_is_mx25()) {
177		priv->ahbclk = clk_get(dev, "usb_ahb");
178		if (IS_ERR(priv->ahbclk)) {
179			ret = PTR_ERR(priv->ahbclk);
180			goto err_clk_ahb;
181		}
182		clk_enable(priv->ahbclk);
183	}
 
184
185	/* "dr" device has its own clock on i.MX51 */
186	if (cpu_is_mx51() && (pdev->id == 0)) {
187		priv->phy1clk = clk_get(dev, "usb_phy1");
188		if (IS_ERR(priv->phy1clk)) {
189			ret = PTR_ERR(priv->phy1clk);
190			goto err_clk_phy;
191		}
192		clk_enable(priv->phy1clk);
193	}
194
195
196	/* call platform specific init function */
197	if (pdata->init) {
198		ret = pdata->init(pdev);
199		if (ret) {
200			dev_err(dev, "platform init failed\n");
201			goto err_init;
202		}
203		/* platforms need some time to settle changed IO settings */
204		mdelay(10);
205	}
206
207	ehci = hcd_to_ehci(hcd);
208
209	/* EHCI registers start at offset 0x100 */
210	ehci->caps = hcd->regs + 0x100;
211	ehci->regs = hcd->regs + 0x100 +
212		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
213
214	/* set up the PORTSCx register */
215	ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
216
217	/* is this really needed? */
218	msleep(10);
219
220	/* Initialize the transceiver */
221	if (pdata->otg) {
222		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
223		ret = otg_init(pdata->otg);
224		if (ret) {
225			dev_err(dev, "unable to init transceiver, probably missing\n");
226			ret = -ENODEV;
227			goto err_add;
228		}
229		ret = otg_set_vbus(pdata->otg, 1);
230		if (ret) {
231			dev_err(dev, "unable to enable vbus on transceiver\n");
232			goto err_add;
233		}
234	}
235
236	priv->hcd = hcd;
237	platform_set_drvdata(pdev, priv);
238
239	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
240	if (ret)
241		goto err_add;
242
243	if (pdata->otg) {
244		/*
245		 * efikamx and efikasb have some hardware bug which is
246		 * preventing usb to work unless CHRGVBUS is set.
247		 * It's in violation of USB specs
248		 */
249		if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
250			flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
251			flags |= ULPI_OTG_CTRL_CHRGVBUS;
252			ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
253			if (ret) {
254				dev_err(dev, "unable to set CHRVBUS\n");
255				goto err_add;
256			}
257		}
258	}
259
260	return 0;
261
262err_add:
263	if (pdata && pdata->exit)
264		pdata->exit(pdev);
265err_init:
266	if (priv->phy1clk) {
267		clk_disable(priv->phy1clk);
268		clk_put(priv->phy1clk);
269	}
270err_clk_phy:
271	if (priv->ahbclk) {
272		clk_disable(priv->ahbclk);
273		clk_put(priv->ahbclk);
274	}
275err_clk_ahb:
276	clk_disable(priv->usbclk);
277	clk_put(priv->usbclk);
278err_clk:
279	iounmap(hcd->regs);
280err_ioremap:
281	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
282err_request_mem:
283err_get_resource:
284	kfree(priv);
285err_alloc:
286	usb_put_hcd(hcd);
287	return ret;
288}
289
290static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
291{
292	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
293	struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
294	struct usb_hcd *hcd = priv->hcd;
 
 
 
295
296	if (pdata && pdata->exit)
297		pdata->exit(pdev);
298
299	if (pdata->otg)
300		otg_shutdown(pdata->otg);
301
302	usb_remove_hcd(hcd);
303	iounmap(hcd->regs);
304	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
305	usb_put_hcd(hcd);
306	platform_set_drvdata(pdev, NULL);
307
308	clk_disable(priv->usbclk);
309	clk_put(priv->usbclk);
310	if (priv->ahbclk) {
311		clk_disable(priv->ahbclk);
312		clk_put(priv->ahbclk);
313	}
314	if (priv->phy1clk) {
315		clk_disable(priv->phy1clk);
316		clk_put(priv->phy1clk);
317	}
318
319	kfree(priv);
 
320
 
321	return 0;
322}
323
324static void ehci_mxc_drv_shutdown(struct platform_device *pdev)
325{
326	struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
327	struct usb_hcd *hcd = priv->hcd;
328
329	if (hcd->driver->shutdown)
330		hcd->driver->shutdown(hcd);
331}
332
333MODULE_ALIAS("platform:mxc-ehci");
334
335static struct platform_driver ehci_mxc_driver = {
336	.probe = ehci_mxc_drv_probe,
337	.remove = __exit_p(ehci_mxc_drv_remove),
338	.shutdown = ehci_mxc_drv_shutdown,
339	.driver = {
340		   .name = "mxc-ehci",
341	},
342};
v4.17
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
  4 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  5 */
  6
  7#include <linux/kernel.h>
  8#include <linux/module.h>
  9#include <linux/io.h>
 10#include <linux/platform_device.h>
 11#include <linux/clk.h>
 12#include <linux/delay.h>
 13#include <linux/usb/otg.h>
 14#include <linux/usb/ulpi.h>
 15#include <linux/slab.h>
 16#include <linux/usb.h>
 17#include <linux/usb/hcd.h>
 18#include <linux/platform_data/usb-ehci-mxc.h>
 19#include "ehci.h"
 20
 21#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
 
 22
 23static const char hcd_name[] = "ehci-mxc";
 24
 25#define ULPI_VIEWPORT_OFFSET	0x170
 26
 27struct ehci_mxc_priv {
 28	struct clk *usbclk, *ahbclk, *phyclk;
 
 29};
 30
 31static struct hc_driver __read_mostly ehci_mxc_hc_driver;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 32
 33static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = {
 34	.extra_priv_size =	sizeof(struct ehci_mxc_priv),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 35};
 36
 37static int ehci_mxc_drv_probe(struct platform_device *pdev)
 38{
 39	struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
 40	struct usb_hcd *hcd;
 41	struct resource *res;
 42	int irq, ret;
 
 43	struct ehci_mxc_priv *priv;
 44	struct device *dev = &pdev->dev;
 45	struct ehci_hcd *ehci;
 46
 
 
 47	if (!pdata) {
 48		dev_err(dev, "No platform data given, bailing out.\n");
 49		return -EINVAL;
 50	}
 51
 52	irq = platform_get_irq(pdev, 0);
 53
 54	hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
 55	if (!hcd)
 56		return -ENOMEM;
 57
 
 
 
 
 
 
 58	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 59	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
 60	if (IS_ERR(hcd->regs)) {
 61		ret = PTR_ERR(hcd->regs);
 62		goto err_alloc;
 63	}
 
 64	hcd->rsrc_start = res->start;
 65	hcd->rsrc_len = resource_size(res);
 66
 67	hcd->has_tt = 1;
 68	ehci = hcd_to_ehci(hcd);
 69	priv = (struct ehci_mxc_priv *) ehci->priv;
 
 
 
 
 
 
 
 
 
 70
 71	/* enable clocks */
 72	priv->usbclk = devm_clk_get(&pdev->dev, "ipg");
 73	if (IS_ERR(priv->usbclk)) {
 74		ret = PTR_ERR(priv->usbclk);
 75		goto err_alloc;
 76	}
 77	clk_prepare_enable(priv->usbclk);
 78
 79	priv->ahbclk = devm_clk_get(&pdev->dev, "ahb");
 80	if (IS_ERR(priv->ahbclk)) {
 81		ret = PTR_ERR(priv->ahbclk);
 82		goto err_clk_ahb;
 
 
 
 83	}
 84	clk_prepare_enable(priv->ahbclk);
 85
 86	/* "dr" device has its own clock on i.MX51 */
 87	priv->phyclk = devm_clk_get(&pdev->dev, "phy");
 88	if (IS_ERR(priv->phyclk))
 89		priv->phyclk = NULL;
 90	if (priv->phyclk)
 91		clk_prepare_enable(priv->phyclk);
 
 
 
 92
 93
 94	/* call platform specific init function */
 95	if (pdata->init) {
 96		ret = pdata->init(pdev);
 97		if (ret) {
 98			dev_err(dev, "platform init failed\n");
 99			goto err_init;
100		}
101		/* platforms need some time to settle changed IO settings */
102		mdelay(10);
103	}
104
 
 
105	/* EHCI registers start at offset 0x100 */
106	ehci->caps = hcd->regs + 0x100;
107	ehci->regs = hcd->regs + 0x100 +
108		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
109
110	/* set up the PORTSCx register */
111	ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
112
113	/* is this really needed? */
114	msleep(10);
115
116	/* Initialize the transceiver */
117	if (pdata->otg) {
118		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
119		ret = usb_phy_init(pdata->otg);
120		if (ret) {
121			dev_err(dev, "unable to init transceiver, probably missing\n");
122			ret = -ENODEV;
123			goto err_add;
124		}
125		ret = otg_set_vbus(pdata->otg->otg, 1);
126		if (ret) {
127			dev_err(dev, "unable to enable vbus on transceiver\n");
128			goto err_add;
129		}
130	}
131
132	platform_set_drvdata(pdev, hcd);
 
133
134	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
135	if (ret)
136		goto err_add;
137
138	device_wakeup_enable(hcd->self.controller);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139	return 0;
140
141err_add:
142	if (pdata && pdata->exit)
143		pdata->exit(pdev);
144err_init:
145	if (priv->phyclk)
146		clk_disable_unprepare(priv->phyclk);
147
148	clk_disable_unprepare(priv->ahbclk);
 
 
 
 
 
149err_clk_ahb:
150	clk_disable_unprepare(priv->usbclk);
 
 
 
 
 
 
 
 
151err_alloc:
152	usb_put_hcd(hcd);
153	return ret;
154}
155
156static int ehci_mxc_drv_remove(struct platform_device *pdev)
157{
158	struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
159	struct usb_hcd *hcd = platform_get_drvdata(pdev);
160	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
161	struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
162
163	usb_remove_hcd(hcd);
164
165	if (pdata && pdata->exit)
166		pdata->exit(pdev);
167
168	if (pdata && pdata->otg)
169		usb_phy_shutdown(pdata->otg);
170
171	clk_disable_unprepare(priv->usbclk);
172	clk_disable_unprepare(priv->ahbclk);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
174	if (priv->phyclk)
175		clk_disable_unprepare(priv->phyclk);
176
177	usb_put_hcd(hcd);
178	return 0;
179}
180
 
 
 
 
 
 
 
 
 
181MODULE_ALIAS("platform:mxc-ehci");
182
183static struct platform_driver ehci_mxc_driver = {
184	.probe = ehci_mxc_drv_probe,
185	.remove = ehci_mxc_drv_remove,
186	.shutdown = usb_hcd_platform_shutdown,
187	.driver = {
188		   .name = "mxc-ehci",
189	},
190};
191
192static int __init ehci_mxc_init(void)
193{
194	if (usb_disabled())
195		return -ENODEV;
196
197	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
198
199	ehci_init_driver(&ehci_mxc_hc_driver, &ehci_mxc_overrides);
200	return platform_driver_register(&ehci_mxc_driver);
201}
202module_init(ehci_mxc_init);
203
204static void __exit ehci_mxc_cleanup(void)
205{
206	platform_driver_unregister(&ehci_mxc_driver);
207}
208module_exit(ehci_mxc_cleanup);
209
210MODULE_DESCRIPTION(DRIVER_DESC);
211MODULE_AUTHOR("Sascha Hauer");
212MODULE_LICENSE("GPL");