Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright 2012 Freescale Semiconductor, Inc.
  3 *
  4 * The code contained herein is licensed under the GNU General Public
  5 * License. You may obtain a copy of the GNU General Public License
  6 * Version 2 or later at the following locations:
  7 *
  8 * http://www.opensource.org/licenses/gpl-license.html
  9 * http://www.gnu.org/copyleft/gpl.html
 10 */
 11
 12#include <linux/module.h>
 13#include <linux/of_platform.h>
 14#include <linux/err.h>
 15#include <linux/io.h>
 16#include <linux/delay.h>
 17
 18#include "ci_hdrc_imx.h"
 19
 20#define MX25_USB_PHY_CTRL_OFFSET	0x08
 21#define MX25_BM_EXTERNAL_VBUS_DIVIDER	BIT(23)
 22
 23#define MX25_EHCI_INTERFACE_SINGLE_UNI	(2 << 0)
 24#define MX25_EHCI_INTERFACE_DIFF_UNI	(0 << 0)
 25#define MX25_EHCI_INTERFACE_MASK	(0xf)
 26
 27#define MX25_OTG_SIC_SHIFT		29
 28#define MX25_OTG_SIC_MASK		(0x3 << MX25_OTG_SIC_SHIFT)
 29#define MX25_OTG_PM_BIT			BIT(24)
 30#define MX25_OTG_PP_BIT			BIT(11)
 31#define MX25_OTG_OCPOL_BIT		BIT(3)
 32
 33#define MX25_H1_SIC_SHIFT		21
 34#define MX25_H1_SIC_MASK		(0x3 << MX25_H1_SIC_SHIFT)
 35#define MX25_H1_PP_BIT			BIT(18)
 36#define MX25_H1_PM_BIT			BIT(16)
 37#define MX25_H1_IPPUE_UP_BIT		BIT(7)
 38#define MX25_H1_IPPUE_DOWN_BIT		BIT(6)
 39#define MX25_H1_TLL_BIT			BIT(5)
 40#define MX25_H1_USBTE_BIT		BIT(4)
 41#define MX25_H1_OCPOL_BIT		BIT(2)
 42
 43#define MX27_H1_PM_BIT			BIT(8)
 44#define MX27_H2_PM_BIT			BIT(16)
 45#define MX27_OTG_PM_BIT			BIT(24)
 46
 47#define MX53_USB_OTG_PHY_CTRL_0_OFFSET	0x08
 48#define MX53_USB_OTG_PHY_CTRL_1_OFFSET	0x0c
 49#define MX53_USB_CTRL_1_OFFSET	        0x10
 50#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK (0x11 << 2)
 51#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI BIT(2)
 52#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK (0x11 << 6)
 53#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI BIT(6)
 54#define MX53_USB_UH2_CTRL_OFFSET	0x14
 55#define MX53_USB_UH3_CTRL_OFFSET	0x18
 56#define MX53_USB_CLKONOFF_CTRL_OFFSET	0x24
 57#define MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF BIT(21)
 58#define MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF BIT(22)
 59#define MX53_BM_OVER_CUR_DIS_H1		BIT(5)
 60#define MX53_BM_OVER_CUR_DIS_OTG	BIT(8)
 61#define MX53_BM_OVER_CUR_DIS_UHx	BIT(30)
 62#define MX53_USB_CTRL_1_UH2_ULPI_EN	BIT(26)
 63#define MX53_USB_CTRL_1_UH3_ULPI_EN	BIT(27)
 64#define MX53_USB_UHx_CTRL_WAKE_UP_EN	BIT(7)
 65#define MX53_USB_UHx_CTRL_ULPI_INT_EN	BIT(8)
 66#define MX53_USB_PHYCTRL1_PLLDIV_MASK	0x3
 67#define MX53_USB_PLL_DIV_24_MHZ		0x01
 68
 69#define MX6_BM_NON_BURST_SETTING	BIT(1)
 70#define MX6_BM_OVER_CUR_DIS		BIT(7)
 71#define MX6_BM_OVER_CUR_POLARITY	BIT(8)
 72#define MX6_BM_WAKEUP_ENABLE		BIT(10)
 73#define MX6_BM_ID_WAKEUP		BIT(16)
 74#define MX6_BM_VBUS_WAKEUP		BIT(17)
 75#define MX6SX_BM_DPDM_WAKEUP_EN		BIT(29)
 76#define MX6_BM_WAKEUP_INTR		BIT(31)
 77#define MX6_USB_OTG1_PHY_CTRL		0x18
 78/* For imx6dql, it is host-only controller, for later imx6, it is otg's */
 79#define MX6_USB_OTG2_PHY_CTRL		0x1c
 80#define MX6SX_USB_VBUS_WAKEUP_SOURCE(v)	(v << 8)
 81#define MX6SX_USB_VBUS_WAKEUP_SOURCE_VBUS	MX6SX_USB_VBUS_WAKEUP_SOURCE(0)
 82#define MX6SX_USB_VBUS_WAKEUP_SOURCE_AVALID	MX6SX_USB_VBUS_WAKEUP_SOURCE(1)
 83#define MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID	MX6SX_USB_VBUS_WAKEUP_SOURCE(2)
 84#define MX6SX_USB_VBUS_WAKEUP_SOURCE_SESS_END	MX6SX_USB_VBUS_WAKEUP_SOURCE(3)
 85
 86#define VF610_OVER_CUR_DIS		BIT(7)
 87
 88#define MX7D_USBNC_USB_CTRL2		0x4
 89#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK	0x3
 90#define MX7D_USB_VBUS_WAKEUP_SOURCE(v)		(v << 0)
 91#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS	MX7D_USB_VBUS_WAKEUP_SOURCE(0)
 92#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID	MX7D_USB_VBUS_WAKEUP_SOURCE(1)
 93#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID	MX7D_USB_VBUS_WAKEUP_SOURCE(2)
 94#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END	MX7D_USB_VBUS_WAKEUP_SOURCE(3)
 95
 96struct usbmisc_ops {
 97	/* It's called once when probe a usb device */
 98	int (*init)(struct imx_usbmisc_data *data);
 99	/* It's called once after adding a usb device */
100	int (*post)(struct imx_usbmisc_data *data);
101	/* It's called when we need to enable/disable usb wakeup */
102	int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled);
103};
104
105struct imx_usbmisc {
106	void __iomem *base;
107	spinlock_t lock;
108	const struct usbmisc_ops *ops;
109};
110
111static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
112{
113	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
114	unsigned long flags;
115	u32 val = 0;
116
117	if (data->index > 1)
118		return -EINVAL;
119
120	spin_lock_irqsave(&usbmisc->lock, flags);
121	switch (data->index) {
122	case 0:
123		val = readl(usbmisc->base);
124		val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT);
125		val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
126		val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT);
127		writel(val, usbmisc->base);
128		break;
129	case 1:
130		val = readl(usbmisc->base);
131		val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT |  MX25_H1_IPPUE_UP_BIT);
132		val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
133		val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
134			MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT);
135
136		writel(val, usbmisc->base);
137
138		break;
139	}
140	spin_unlock_irqrestore(&usbmisc->lock, flags);
141
142	return 0;
143}
144
145static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
146{
147	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
148	void __iomem *reg;
149	unsigned long flags;
150	u32 val;
151
152	if (data->index > 2)
153		return -EINVAL;
154
155	if (data->evdo) {
156		spin_lock_irqsave(&usbmisc->lock, flags);
157		reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
158		val = readl(reg);
159		writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
160		spin_unlock_irqrestore(&usbmisc->lock, flags);
161		usleep_range(5000, 10000); /* needed to stabilize voltage */
162	}
163
164	return 0;
165}
166
167static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
168{
169	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
170	unsigned long flags;
171	u32 val;
172
173	switch (data->index) {
174	case 0:
175		val = MX27_OTG_PM_BIT;
176		break;
177	case 1:
178		val = MX27_H1_PM_BIT;
179		break;
180	case 2:
181		val = MX27_H2_PM_BIT;
182		break;
183	default:
184		return -EINVAL;
185	}
186
187	spin_lock_irqsave(&usbmisc->lock, flags);
188	if (data->disable_oc)
189		val = readl(usbmisc->base) | val;
190	else
191		val = readl(usbmisc->base) & ~val;
192	writel(val, usbmisc->base);
193	spin_unlock_irqrestore(&usbmisc->lock, flags);
194
195	return 0;
196}
197
198static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
199{
200	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
201	void __iomem *reg = NULL;
202	unsigned long flags;
203	u32 val = 0;
204
205	if (data->index > 3)
206		return -EINVAL;
207
208	/* Select a 24 MHz reference clock for the PHY  */
209	val = readl(usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
210	val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
211	val |= MX53_USB_PLL_DIV_24_MHZ;
212	writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
213
214	spin_lock_irqsave(&usbmisc->lock, flags);
215
216	switch (data->index) {
217	case 0:
218		if (data->disable_oc) {
219			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
220			val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
221			writel(val, reg);
222		}
223		break;
224	case 1:
225		if (data->disable_oc) {
226			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
227			val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
228			writel(val, reg);
229		}
230		break;
231	case 2:
232		if (data->ulpi) {
233			/* set USBH2 into ULPI-mode. */
234			reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
235			val = readl(reg) | MX53_USB_CTRL_1_UH2_ULPI_EN;
236			/* select ULPI clock */
237			val &= ~MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK;
238			val |= MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI;
239			writel(val, reg);
240			/* Set interrupt wake up enable */
241			reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
242			val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
243				| MX53_USB_UHx_CTRL_ULPI_INT_EN;
244			writel(val, reg);
245			/* Disable internal 60Mhz clock */
246			reg = usbmisc->base + MX53_USB_CLKONOFF_CTRL_OFFSET;
247			val = readl(reg) | MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF;
248			writel(val, reg);
249		}
250		if (data->disable_oc) {
251			reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
252			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
253			writel(val, reg);
254		}
255		break;
256	case 3:
257		if (data->ulpi) {
258			/* set USBH3 into ULPI-mode. */
259			reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
260			val = readl(reg) | MX53_USB_CTRL_1_UH3_ULPI_EN;
261			/* select ULPI clock */
262			val &= ~MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK;
263			val |= MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI;
264			writel(val, reg);
265			/* Set interrupt wake up enable */
266			reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
267			val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
268				| MX53_USB_UHx_CTRL_ULPI_INT_EN;
269			writel(val, reg);
270			/* Disable internal 60Mhz clock */
271			reg = usbmisc->base + MX53_USB_CLKONOFF_CTRL_OFFSET;
272			val = readl(reg) | MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF;
273			writel(val, reg);
274		}
275		if (data->disable_oc) {
276			reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
277			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
278			writel(val, reg);
279		}
280		break;
281	}
282
283	spin_unlock_irqrestore(&usbmisc->lock, flags);
284
285	return 0;
286}
287
288static int usbmisc_imx6q_set_wakeup
289	(struct imx_usbmisc_data *data, bool enabled)
290{
291	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
292	unsigned long flags;
293	u32 val;
294	u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
295		MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
296	int ret = 0;
297
298	if (data->index > 3)
299		return -EINVAL;
300
301	spin_lock_irqsave(&usbmisc->lock, flags);
302	val = readl(usbmisc->base + data->index * 4);
303	if (enabled) {
304		val |= wakeup_setting;
305		writel(val, usbmisc->base + data->index * 4);
306	} else {
307		if (val & MX6_BM_WAKEUP_INTR)
308			pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
309		val &= ~wakeup_setting;
310		writel(val, usbmisc->base + data->index * 4);
311	}
312	spin_unlock_irqrestore(&usbmisc->lock, flags);
313
314	return ret;
315}
316
317static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
318{
319	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
320	unsigned long flags;
321	u32 reg;
322
323	if (data->index > 3)
324		return -EINVAL;
325
326	spin_lock_irqsave(&usbmisc->lock, flags);
327
328	reg = readl(usbmisc->base + data->index * 4);
329	if (data->disable_oc) {
330		reg |= MX6_BM_OVER_CUR_DIS;
331	} else if (data->oc_polarity == 1) {
332		/* High active */
333		reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
334	}
335	writel(reg, usbmisc->base + data->index * 4);
336
337	/* SoC non-burst setting */
338	reg = readl(usbmisc->base + data->index * 4);
339	writel(reg | MX6_BM_NON_BURST_SETTING,
340			usbmisc->base + data->index * 4);
341
342	spin_unlock_irqrestore(&usbmisc->lock, flags);
343
344	usbmisc_imx6q_set_wakeup(data, false);
345
346	return 0;
347}
348
349static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data)
350{
351	void __iomem *reg = NULL;
352	unsigned long flags;
353	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
354	u32 val;
355
356	usbmisc_imx6q_init(data);
357
358	if (data->index == 0 || data->index == 1) {
359		reg = usbmisc->base + MX6_USB_OTG1_PHY_CTRL + data->index * 4;
360		spin_lock_irqsave(&usbmisc->lock, flags);
361		/* Set vbus wakeup source as bvalid */
362		val = readl(reg);
363		writel(val | MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID, reg);
364		/*
365		 * Disable dp/dm wakeup in device mode when vbus is
366		 * not there.
367		 */
368		val = readl(usbmisc->base + data->index * 4);
369		writel(val & ~MX6SX_BM_DPDM_WAKEUP_EN,
370			usbmisc->base + data->index * 4);
371		spin_unlock_irqrestore(&usbmisc->lock, flags);
372	}
373
374	return 0;
375}
376
377static int usbmisc_vf610_init(struct imx_usbmisc_data *data)
378{
379	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
380	u32 reg;
381
382	/*
383	 * Vybrid only has one misc register set, but in two different
384	 * areas. These is reflected in two instances of this driver.
385	 */
386	if (data->index >= 1)
387		return -EINVAL;
388
389	if (data->disable_oc) {
390		reg = readl(usbmisc->base);
391		writel(reg | VF610_OVER_CUR_DIS, usbmisc->base);
392	}
393
394	return 0;
395}
396
397static int usbmisc_imx7d_set_wakeup
398	(struct imx_usbmisc_data *data, bool enabled)
399{
400	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
401	unsigned long flags;
402	u32 val;
403	u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
404		MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
405
406	spin_lock_irqsave(&usbmisc->lock, flags);
407	val = readl(usbmisc->base);
408	if (enabled) {
409		writel(val | wakeup_setting, usbmisc->base);
410	} else {
411		if (val & MX6_BM_WAKEUP_INTR)
412			dev_dbg(data->dev, "wakeup int\n");
413		writel(val & ~wakeup_setting, usbmisc->base);
414	}
415	spin_unlock_irqrestore(&usbmisc->lock, flags);
416
417	return 0;
418}
419
420static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
421{
422	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
423	unsigned long flags;
424	u32 reg;
425
426	if (data->index >= 1)
427		return -EINVAL;
428
429	spin_lock_irqsave(&usbmisc->lock, flags);
430	reg = readl(usbmisc->base);
431	if (data->disable_oc) {
432		reg |= MX6_BM_OVER_CUR_DIS;
433	} else if (data->oc_polarity == 1) {
434		/* High active */
435		reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
436	}
437	writel(reg, usbmisc->base);
438
439	reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
440	reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
441	writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
442		 usbmisc->base + MX7D_USBNC_USB_CTRL2);
443	spin_unlock_irqrestore(&usbmisc->lock, flags);
444
445	usbmisc_imx7d_set_wakeup(data, false);
446
447	return 0;
448}
449
450static const struct usbmisc_ops imx25_usbmisc_ops = {
451	.init = usbmisc_imx25_init,
452	.post = usbmisc_imx25_post,
453};
454
455static const struct usbmisc_ops imx27_usbmisc_ops = {
456	.init = usbmisc_imx27_init,
457};
458
459static const struct usbmisc_ops imx53_usbmisc_ops = {
460	.init = usbmisc_imx53_init,
461};
462
463static const struct usbmisc_ops imx6q_usbmisc_ops = {
464	.set_wakeup = usbmisc_imx6q_set_wakeup,
465	.init = usbmisc_imx6q_init,
466};
467
468static const struct usbmisc_ops vf610_usbmisc_ops = {
469	.init = usbmisc_vf610_init,
470};
471
472static const struct usbmisc_ops imx6sx_usbmisc_ops = {
473	.set_wakeup = usbmisc_imx6q_set_wakeup,
474	.init = usbmisc_imx6sx_init,
475};
476
477static const struct usbmisc_ops imx7d_usbmisc_ops = {
478	.init = usbmisc_imx7d_init,
479	.set_wakeup = usbmisc_imx7d_set_wakeup,
480};
481
482int imx_usbmisc_init(struct imx_usbmisc_data *data)
483{
484	struct imx_usbmisc *usbmisc;
485
486	if (!data)
487		return 0;
488
489	usbmisc = dev_get_drvdata(data->dev);
490	if (!usbmisc->ops->init)
491		return 0;
492	return usbmisc->ops->init(data);
493}
494EXPORT_SYMBOL_GPL(imx_usbmisc_init);
495
496int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
497{
498	struct imx_usbmisc *usbmisc;
499
500	if (!data)
501		return 0;
502
503	usbmisc = dev_get_drvdata(data->dev);
504	if (!usbmisc->ops->post)
505		return 0;
506	return usbmisc->ops->post(data);
507}
508EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
509
510int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
511{
512	struct imx_usbmisc *usbmisc;
513
514	if (!data)
515		return 0;
516
517	usbmisc = dev_get_drvdata(data->dev);
518	if (!usbmisc->ops->set_wakeup)
519		return 0;
520	return usbmisc->ops->set_wakeup(data, enabled);
521}
522EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
523
524static const struct of_device_id usbmisc_imx_dt_ids[] = {
525	{
526		.compatible = "fsl,imx25-usbmisc",
527		.data = &imx25_usbmisc_ops,
528	},
529	{
530		.compatible = "fsl,imx35-usbmisc",
531		.data = &imx25_usbmisc_ops,
532	},
533	{
534		.compatible = "fsl,imx27-usbmisc",
535		.data = &imx27_usbmisc_ops,
536	},
537	{
538		.compatible = "fsl,imx51-usbmisc",
539		.data = &imx53_usbmisc_ops,
540	},
541	{
542		.compatible = "fsl,imx53-usbmisc",
543		.data = &imx53_usbmisc_ops,
544	},
545	{
546		.compatible = "fsl,imx6q-usbmisc",
547		.data = &imx6q_usbmisc_ops,
548	},
549	{
550		.compatible = "fsl,vf610-usbmisc",
551		.data = &vf610_usbmisc_ops,
552	},
553	{
554		.compatible = "fsl,imx6sx-usbmisc",
555		.data = &imx6sx_usbmisc_ops,
556	},
557	{
558		.compatible = "fsl,imx6ul-usbmisc",
559		.data = &imx6sx_usbmisc_ops,
560	},
561	{
562		.compatible = "fsl,imx7d-usbmisc",
563		.data = &imx7d_usbmisc_ops,
564	},
565	{ /* sentinel */ }
566};
567MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
568
569static int usbmisc_imx_probe(struct platform_device *pdev)
570{
571	struct resource	*res;
572	struct imx_usbmisc *data;
573	const struct of_device_id *of_id;
574
575	of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
576	if (!of_id)
577		return -ENODEV;
578
579	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
580	if (!data)
581		return -ENOMEM;
582
583	spin_lock_init(&data->lock);
584
585	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
586	data->base = devm_ioremap_resource(&pdev->dev, res);
587	if (IS_ERR(data->base))
588		return PTR_ERR(data->base);
589
590	data->ops = (const struct usbmisc_ops *)of_id->data;
591	platform_set_drvdata(pdev, data);
592
593	return 0;
594}
595
596static int usbmisc_imx_remove(struct platform_device *pdev)
597{
598	return 0;
599}
600
601static struct platform_driver usbmisc_imx_driver = {
602	.probe = usbmisc_imx_probe,
603	.remove = usbmisc_imx_remove,
604	.driver = {
605		.name = "usbmisc_imx",
606		.of_match_table = usbmisc_imx_dt_ids,
607	 },
608};
609
610module_platform_driver(usbmisc_imx_driver);
611
612MODULE_ALIAS("platform:usbmisc-imx");
613MODULE_LICENSE("GPL v2");
614MODULE_DESCRIPTION("driver for imx usb non-core registers");
615MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");