| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright 2012 Freescale Semiconductor, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The code contained herein is licensed under the GNU General Public | 
					
						
							|  |  |  |  * License. You may obtain a copy of the GNU General Public License | 
					
						
							|  |  |  |  * Version 2 or later at the following locations: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * http://www.opensource.org/licenses/gpl-license.html
 | 
					
						
							|  |  |  |  * http://www.gnu.org/copyleft/gpl.html
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/of_platform.h>
 | 
					
						
							|  |  |  | #include <linux/clk.h>
 | 
					
						
							|  |  |  | #include <linux/err.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | #include <linux/delay.h>
 | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-24 14:46:36 +03:00
										 |  |  | #include "ci_hdrc_imx.h"
 | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | #define MX25_USB_PHY_CTRL_OFFSET	0x08
 | 
					
						
							|  |  |  | #define MX25_BM_EXTERNAL_VBUS_DIVIDER	BIT(23)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-23 15:56:36 +08:00
										 |  |  | #define MX25_EHCI_INTERFACE_SINGLE_UNI	(2 << 0)
 | 
					
						
							|  |  |  | #define MX25_EHCI_INTERFACE_DIFF_UNI	(0 << 0)
 | 
					
						
							|  |  |  | #define MX25_EHCI_INTERFACE_MASK	(0xf)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MX25_OTG_SIC_SHIFT		29
 | 
					
						
							|  |  |  | #define MX25_OTG_SIC_MASK		(0x3 << MX25_OTG_SIC_SHIFT)
 | 
					
						
							|  |  |  | #define MX25_OTG_PM_BIT			BIT(24)
 | 
					
						
							|  |  |  | #define MX25_OTG_PP_BIT			BIT(11)
 | 
					
						
							|  |  |  | #define MX25_OTG_OCPOL_BIT		BIT(3)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MX25_H1_SIC_SHIFT		21
 | 
					
						
							|  |  |  | #define MX25_H1_SIC_MASK		(0x3 << MX25_H1_SIC_SHIFT)
 | 
					
						
							|  |  |  | #define MX25_H1_PP_BIT			BIT(18)
 | 
					
						
							|  |  |  | #define MX25_H1_PM_BIT			BIT(16)
 | 
					
						
							|  |  |  | #define MX25_H1_IPPUE_UP_BIT		BIT(7)
 | 
					
						
							|  |  |  | #define MX25_H1_IPPUE_DOWN_BIT		BIT(6)
 | 
					
						
							|  |  |  | #define MX25_H1_TLL_BIT			BIT(5)
 | 
					
						
							|  |  |  | #define MX25_H1_USBTE_BIT		BIT(4)
 | 
					
						
							|  |  |  | #define MX25_H1_OCPOL_BIT		BIT(2)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-06 16:35:14 +08:00
										 |  |  | #define MX27_H1_PM_BIT			BIT(8)
 | 
					
						
							|  |  |  | #define MX27_H2_PM_BIT			BIT(16)
 | 
					
						
							|  |  |  | #define MX27_OTG_PM_BIT			BIT(24)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | #define MX53_USB_OTG_PHY_CTRL_0_OFFSET	0x08
 | 
					
						
							| 
									
										
										
										
											2014-05-04 09:24:39 +08:00
										 |  |  | #define MX53_USB_OTG_PHY_CTRL_1_OFFSET	0x0c
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | #define MX53_USB_UH2_CTRL_OFFSET	0x14
 | 
					
						
							|  |  |  | #define MX53_USB_UH3_CTRL_OFFSET	0x18
 | 
					
						
							|  |  |  | #define MX53_BM_OVER_CUR_DIS_H1		BIT(5)
 | 
					
						
							|  |  |  | #define MX53_BM_OVER_CUR_DIS_OTG	BIT(8)
 | 
					
						
							|  |  |  | #define MX53_BM_OVER_CUR_DIS_UHx	BIT(30)
 | 
					
						
							| 
									
										
										
										
											2014-05-04 09:24:39 +08:00
										 |  |  | #define MX53_USB_PHYCTRL1_PLLDIV_MASK	0x3
 | 
					
						
							|  |  |  | #define MX53_USB_PLL_DIV_24_MHZ		0x01
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:59 +02:00
										 |  |  | #define MX6_BM_OVER_CUR_DIS		BIT(7)
 | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | #define VF610_OVER_CUR_DIS		BIT(7)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | struct usbmisc_ops { | 
					
						
							|  |  |  | 	/* It's called once when probe a usb device */ | 
					
						
							|  |  |  | 	int (*init)(struct imx_usbmisc_data *data); | 
					
						
							|  |  |  | 	/* It's called once after adding a usb device */ | 
					
						
							|  |  |  | 	int (*post)(struct imx_usbmisc_data *data); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | struct imx_usbmisc { | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	void __iomem *base; | 
					
						
							|  |  |  | 	spinlock_t lock; | 
					
						
							|  |  |  | 	struct clk *clk; | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:59 +02:00
										 |  |  | 	const struct usbmisc_ops *ops; | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-23 15:56:36 +08:00
										 |  |  | static int usbmisc_imx25_init(struct imx_usbmisc_data *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							| 
									
										
										
										
											2014-04-23 15:56:36 +08:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 val = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (data->index > 1) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 	switch (data->index) { | 
					
						
							|  |  |  | 	case 0: | 
					
						
							|  |  |  | 		val = readl(usbmisc->base); | 
					
						
							|  |  |  | 		val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); | 
					
						
							|  |  |  | 		val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; | 
					
						
							|  |  |  | 		val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); | 
					
						
							|  |  |  | 		writel(val, usbmisc->base); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		val = readl(usbmisc->base); | 
					
						
							|  |  |  | 		val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT |  MX25_H1_IPPUE_UP_BIT); | 
					
						
							|  |  |  | 		val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; | 
					
						
							|  |  |  | 		val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | | 
					
						
							|  |  |  | 			MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		writel(val, usbmisc->base); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | static int usbmisc_imx25_post(struct imx_usbmisc_data *data) | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | 	void __iomem *reg; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (data->index > 2) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (data->evdo) { | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | 		spin_lock_irqsave(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 		val = readl(reg); | 
					
						
							|  |  |  | 		writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 		usleep_range(5000, 10000); /* needed to stabilize voltage */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-06 16:35:14 +08:00
										 |  |  | static int usbmisc_imx27_init(struct imx_usbmisc_data *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							| 
									
										
										
										
											2013-12-06 16:35:14 +08:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (data->index) { | 
					
						
							|  |  |  | 	case 0: | 
					
						
							|  |  |  | 		val = MX27_OTG_PM_BIT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		val = MX27_H1_PM_BIT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 2: | 
					
						
							|  |  |  | 		val = MX27_H2_PM_BIT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 	if (data->disable_oc) | 
					
						
							|  |  |  | 		val = readl(usbmisc->base) | val; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		val = readl(usbmisc->base) & ~val; | 
					
						
							|  |  |  | 	writel(val, usbmisc->base); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | static int usbmisc_imx53_init(struct imx_usbmisc_data *data) | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | 	void __iomem *reg = NULL; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 val = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (data->index > 3) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-04 09:24:39 +08:00
										 |  |  | 	/* Select a 24 MHz reference clock for the PHY  */ | 
					
						
							|  |  |  | 	reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET; | 
					
						
							|  |  |  | 	val = readl(reg); | 
					
						
							|  |  |  | 	val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK; | 
					
						
							|  |  |  | 	val |= MX53_USB_PLL_DIV_24_MHZ; | 
					
						
							|  |  |  | 	writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (data->disable_oc) { | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | 		spin_lock_irqsave(&usbmisc->lock, flags); | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 		switch (data->index) { | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | 		case 0: | 
					
						
							|  |  |  | 			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; | 
					
						
							|  |  |  | 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; | 
					
						
							|  |  |  | 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; | 
					
						
							|  |  |  | 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 3: | 
					
						
							|  |  |  | 			reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; | 
					
						
							|  |  |  | 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (reg && val) | 
					
						
							|  |  |  | 			writel(val, reg); | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 reg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (data->index > 3) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (data->disable_oc) { | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 		spin_lock_irqsave(&usbmisc->lock, flags); | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 		reg = readl(usbmisc->base + data->index * 4); | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:59 +02:00
										 |  |  | 		writel(reg | MX6_BM_OVER_CUR_DIS, | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 			usbmisc->base + data->index * 4); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 		spin_unlock_irqrestore(&usbmisc->lock, flags); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | static int usbmisc_vf610_init(struct imx_usbmisc_data *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							|  |  |  | 	u32 reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Vybrid only has one misc register set, but in two different | 
					
						
							|  |  |  | 	 * areas. These is reflected in two instances of this driver. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (data->index >= 1) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (data->disable_oc) { | 
					
						
							|  |  |  | 		reg = readl(usbmisc->base); | 
					
						
							|  |  |  | 		writel(reg | VF610_OVER_CUR_DIS, usbmisc->base); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | static const struct usbmisc_ops imx25_usbmisc_ops = { | 
					
						
							| 
									
										
										
										
											2014-04-23 15:56:36 +08:00
										 |  |  | 	.init = usbmisc_imx25_init, | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | 	.post = usbmisc_imx25_post, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-06 16:35:14 +08:00
										 |  |  | static const struct usbmisc_ops imx27_usbmisc_ops = { | 
					
						
							|  |  |  | 	.init = usbmisc_imx27_init, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | static const struct usbmisc_ops imx53_usbmisc_ops = { | 
					
						
							|  |  |  | 	.init = usbmisc_imx53_init, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | static const struct usbmisc_ops imx6q_usbmisc_ops = { | 
					
						
							|  |  |  | 	.init = usbmisc_imx6q_init, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | static const struct usbmisc_ops vf610_usbmisc_ops = { | 
					
						
							|  |  |  | 	.init = usbmisc_vf610_init, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | int imx_usbmisc_init(struct imx_usbmisc_data *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (!usbmisc->ops->init) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	return usbmisc->ops->init(data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(imx_usbmisc_init); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int imx_usbmisc_init_post(struct imx_usbmisc_data *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 12:44:16 +03:00
										 |  |  | 	if (!usbmisc->ops->post) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	return usbmisc->ops->post(data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | static const struct of_device_id usbmisc_imx_dt_ids[] = { | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:01 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,imx25-usbmisc", | 
					
						
							|  |  |  | 		.data = &imx25_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2014-04-23 15:56:36 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,imx35-usbmisc", | 
					
						
							|  |  |  | 		.data = &imx25_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-12-06 16:35:14 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,imx27-usbmisc", | 
					
						
							|  |  |  | 		.data = &imx27_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-12-06 16:35:15 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,imx51-usbmisc", | 
					
						
							|  |  |  | 		.data = &imx53_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-03-30 12:54:00 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,imx53-usbmisc", | 
					
						
							|  |  |  | 		.data = &imx53_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:59 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,imx6q-usbmisc", | 
					
						
							|  |  |  | 		.data = &imx6q_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "fsl,vf610-usbmisc", | 
					
						
							|  |  |  | 		.data = &vf610_usbmisc_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	{ /* sentinel */ } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2013-06-20 23:33:25 +02:00
										 |  |  | MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | static int usbmisc_imx_probe(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct resource	*res; | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | 	struct imx_usbmisc *data; | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:59 +02:00
										 |  |  | 	struct of_device_id *tmp_dev; | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!data) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_init(&data->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
					
						
							| 
									
										
										
										
											2013-01-21 11:09:22 +01:00
										 |  |  | 	data->base = devm_ioremap_resource(&pdev->dev, res); | 
					
						
							|  |  |  | 	if (IS_ERR(data->base)) | 
					
						
							|  |  |  | 		return PTR_ERR(data->base); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data->clk = devm_clk_get(&pdev->dev, NULL); | 
					
						
							|  |  |  | 	if (IS_ERR(data->clk)) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, | 
					
						
							|  |  |  | 			"failed to get clock, err=%ld\n", PTR_ERR(data->clk)); | 
					
						
							|  |  |  | 		return PTR_ERR(data->clk); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = clk_prepare_enable(data->clk); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, | 
					
						
							|  |  |  | 			"clk_prepare_enable failed, err=%d\n", ret); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:59 +02:00
										 |  |  | 	tmp_dev = (struct of_device_id *) | 
					
						
							|  |  |  | 		of_match_device(usbmisc_imx_dt_ids, &pdev->dev); | 
					
						
							|  |  |  | 	data->ops = (const struct usbmisc_ops *)tmp_dev->data; | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	platform_set_drvdata(pdev, data); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | static int usbmisc_imx_remove(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-22 08:14:15 +08:00
										 |  |  | 	struct imx_usbmisc *usbmisc = dev_get_drvdata(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	clk_disable_unprepare(usbmisc->clk); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | static struct platform_driver usbmisc_imx_driver = { | 
					
						
							|  |  |  | 	.probe = usbmisc_imx_probe, | 
					
						
							|  |  |  | 	.remove = usbmisc_imx_remove, | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	.driver = { | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | 		.name = "usbmisc_imx", | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 		.owner = THIS_MODULE, | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | 		.of_match_table = usbmisc_imx_dt_ids, | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 	 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 17:59:59 +03:00
										 |  |  | module_platform_driver(usbmisc_imx_driver); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | MODULE_ALIAS("platform:usbmisc-imx"); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | MODULE_LICENSE("GPL v2"); | 
					
						
							| 
									
										
										
										
											2013-03-30 12:53:56 +02:00
										 |  |  | MODULE_DESCRIPTION("driver for imx usb non-core registers"); | 
					
						
							| 
									
										
										
										
											2012-09-12 14:58:05 +03:00
										 |  |  | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); |