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/clk.h>
15 #include <linux/err.h>
16 #include <linux/io.h>
17 #include <linux/delay.h>
18 
19 #include "ci_hdrc_imx.h"
20 
21 #define MX25_USB_PHY_CTRL_OFFSET	0x08
22 #define MX25_BM_EXTERNAL_VBUS_DIVIDER	BIT(23)
23 
24 #define MX25_EHCI_INTERFACE_SINGLE_UNI	(2 << 0)
25 #define MX25_EHCI_INTERFACE_DIFF_UNI	(0 << 0)
26 #define MX25_EHCI_INTERFACE_MASK	(0xf)
27 
28 #define MX25_OTG_SIC_SHIFT		29
29 #define MX25_OTG_SIC_MASK		(0x3 << MX25_OTG_SIC_SHIFT)
30 #define MX25_OTG_PM_BIT			BIT(24)
31 #define MX25_OTG_PP_BIT			BIT(11)
32 #define MX25_OTG_OCPOL_BIT		BIT(3)
33 
34 #define MX25_H1_SIC_SHIFT		21
35 #define MX25_H1_SIC_MASK		(0x3 << MX25_H1_SIC_SHIFT)
36 #define MX25_H1_PP_BIT			BIT(18)
37 #define MX25_H1_PM_BIT			BIT(16)
38 #define MX25_H1_IPPUE_UP_BIT		BIT(7)
39 #define MX25_H1_IPPUE_DOWN_BIT		BIT(6)
40 #define MX25_H1_TLL_BIT			BIT(5)
41 #define MX25_H1_USBTE_BIT		BIT(4)
42 #define MX25_H1_OCPOL_BIT		BIT(2)
43 
44 #define MX27_H1_PM_BIT			BIT(8)
45 #define MX27_H2_PM_BIT			BIT(16)
46 #define MX27_OTG_PM_BIT			BIT(24)
47 
48 #define MX53_USB_OTG_PHY_CTRL_0_OFFSET	0x08
49 #define MX53_USB_OTG_PHY_CTRL_1_OFFSET	0x0c
50 #define MX53_USB_UH2_CTRL_OFFSET	0x14
51 #define MX53_USB_UH3_CTRL_OFFSET	0x18
52 #define MX53_BM_OVER_CUR_DIS_H1		BIT(5)
53 #define MX53_BM_OVER_CUR_DIS_OTG	BIT(8)
54 #define MX53_BM_OVER_CUR_DIS_UHx	BIT(30)
55 #define MX53_USB_PHYCTRL1_PLLDIV_MASK	0x3
56 #define MX53_USB_PLL_DIV_24_MHZ		0x01
57 
58 #define MX6_BM_OVER_CUR_DIS		BIT(7)
59 
60 struct usbmisc_ops {
61 	/* It's called once when probe a usb device */
62 	int (*init)(struct imx_usbmisc_data *data);
63 	/* It's called once after adding a usb device */
64 	int (*post)(struct imx_usbmisc_data *data);
65 };
66 
67 struct imx_usbmisc {
68 	void __iomem *base;
69 	spinlock_t lock;
70 	struct clk *clk;
71 	const struct usbmisc_ops *ops;
72 };
73 
74 static struct imx_usbmisc *usbmisc;
75 
76 static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
77 {
78 	unsigned long flags;
79 	u32 val = 0;
80 
81 	if (data->index > 1)
82 		return -EINVAL;
83 
84 	spin_lock_irqsave(&usbmisc->lock, flags);
85 	switch (data->index) {
86 	case 0:
87 		val = readl(usbmisc->base);
88 		val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT);
89 		val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
90 		val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT);
91 		writel(val, usbmisc->base);
92 		break;
93 	case 1:
94 		val = readl(usbmisc->base);
95 		val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT |  MX25_H1_IPPUE_UP_BIT);
96 		val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
97 		val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
98 			MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT);
99 
100 		writel(val, usbmisc->base);
101 
102 		break;
103 	}
104 	spin_unlock_irqrestore(&usbmisc->lock, flags);
105 
106 	return 0;
107 }
108 
109 static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
110 {
111 	void __iomem *reg;
112 	unsigned long flags;
113 	u32 val;
114 
115 	if (data->index > 2)
116 		return -EINVAL;
117 
118 	reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
119 
120 	if (data->evdo) {
121 		spin_lock_irqsave(&usbmisc->lock, flags);
122 		val = readl(reg);
123 		writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
124 		spin_unlock_irqrestore(&usbmisc->lock, flags);
125 		usleep_range(5000, 10000); /* needed to stabilize voltage */
126 	}
127 
128 	return 0;
129 }
130 
131 static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
132 {
133 	unsigned long flags;
134 	u32 val;
135 
136 	switch (data->index) {
137 	case 0:
138 		val = MX27_OTG_PM_BIT;
139 		break;
140 	case 1:
141 		val = MX27_H1_PM_BIT;
142 		break;
143 	case 2:
144 		val = MX27_H2_PM_BIT;
145 		break;
146 	default:
147 		return -EINVAL;
148 	};
149 
150 	spin_lock_irqsave(&usbmisc->lock, flags);
151 	if (data->disable_oc)
152 		val = readl(usbmisc->base) | val;
153 	else
154 		val = readl(usbmisc->base) & ~val;
155 	writel(val, usbmisc->base);
156 	spin_unlock_irqrestore(&usbmisc->lock, flags);
157 
158 	return 0;
159 }
160 
161 static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
162 {
163 	void __iomem *reg = NULL;
164 	unsigned long flags;
165 	u32 val = 0;
166 
167 	if (data->index > 3)
168 		return -EINVAL;
169 
170 	/* Select a 24 MHz reference clock for the PHY  */
171 	reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
172 	val = readl(reg);
173 	val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
174 	val |= MX53_USB_PLL_DIV_24_MHZ;
175 	writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
176 
177 	if (data->disable_oc) {
178 		spin_lock_irqsave(&usbmisc->lock, flags);
179 		switch (data->index) {
180 		case 0:
181 			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
182 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
183 			break;
184 		case 1:
185 			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
186 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
187 			break;
188 		case 2:
189 			reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
190 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
191 			break;
192 		case 3:
193 			reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
194 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
195 			break;
196 		}
197 		if (reg && val)
198 			writel(val, reg);
199 		spin_unlock_irqrestore(&usbmisc->lock, flags);
200 	}
201 
202 	return 0;
203 }
204 
205 static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
206 {
207 	unsigned long flags;
208 	u32 reg;
209 
210 	if (data->index > 3)
211 		return -EINVAL;
212 
213 	if (data->disable_oc) {
214 		spin_lock_irqsave(&usbmisc->lock, flags);
215 		reg = readl(usbmisc->base + data->index * 4);
216 		writel(reg | MX6_BM_OVER_CUR_DIS,
217 			usbmisc->base + data->index * 4);
218 		spin_unlock_irqrestore(&usbmisc->lock, flags);
219 	}
220 
221 	return 0;
222 }
223 
224 static const struct usbmisc_ops imx25_usbmisc_ops = {
225 	.init = usbmisc_imx25_init,
226 	.post = usbmisc_imx25_post,
227 };
228 
229 static const struct usbmisc_ops imx27_usbmisc_ops = {
230 	.init = usbmisc_imx27_init,
231 };
232 
233 static const struct usbmisc_ops imx53_usbmisc_ops = {
234 	.init = usbmisc_imx53_init,
235 };
236 
237 static const struct usbmisc_ops imx6q_usbmisc_ops = {
238 	.init = usbmisc_imx6q_init,
239 };
240 
241 int imx_usbmisc_init(struct imx_usbmisc_data *data)
242 {
243 	if (!usbmisc)
244 		return -EPROBE_DEFER;
245 	if (!usbmisc->ops->init)
246 		return 0;
247 	return usbmisc->ops->init(data);
248 }
249 EXPORT_SYMBOL_GPL(imx_usbmisc_init);
250 
251 int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
252 {
253 	if (!usbmisc)
254 		return -EPROBE_DEFER;
255 	if (!usbmisc->ops->post)
256 		return 0;
257 	return usbmisc->ops->post(data);
258 }
259 EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
260 
261 static const struct of_device_id usbmisc_imx_dt_ids[] = {
262 	{
263 		.compatible = "fsl,imx25-usbmisc",
264 		.data = &imx25_usbmisc_ops,
265 	},
266 	{
267 		.compatible = "fsl,imx35-usbmisc",
268 		.data = &imx25_usbmisc_ops,
269 	},
270 	{
271 		.compatible = "fsl,imx27-usbmisc",
272 		.data = &imx27_usbmisc_ops,
273 	},
274 	{
275 		.compatible = "fsl,imx51-usbmisc",
276 		.data = &imx53_usbmisc_ops,
277 	},
278 	{
279 		.compatible = "fsl,imx53-usbmisc",
280 		.data = &imx53_usbmisc_ops,
281 	},
282 	{
283 		.compatible = "fsl,imx6q-usbmisc",
284 		.data = &imx6q_usbmisc_ops,
285 	},
286 	{ /* sentinel */ }
287 };
288 MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
289 
290 static int usbmisc_imx_probe(struct platform_device *pdev)
291 {
292 	struct resource	*res;
293 	struct imx_usbmisc *data;
294 	int ret;
295 	struct of_device_id *tmp_dev;
296 
297 	if (usbmisc)
298 		return -EBUSY;
299 
300 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
301 	if (!data)
302 		return -ENOMEM;
303 
304 	spin_lock_init(&data->lock);
305 
306 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
307 	data->base = devm_ioremap_resource(&pdev->dev, res);
308 	if (IS_ERR(data->base))
309 		return PTR_ERR(data->base);
310 
311 	data->clk = devm_clk_get(&pdev->dev, NULL);
312 	if (IS_ERR(data->clk)) {
313 		dev_err(&pdev->dev,
314 			"failed to get clock, err=%ld\n", PTR_ERR(data->clk));
315 		return PTR_ERR(data->clk);
316 	}
317 
318 	ret = clk_prepare_enable(data->clk);
319 	if (ret) {
320 		dev_err(&pdev->dev,
321 			"clk_prepare_enable failed, err=%d\n", ret);
322 		return ret;
323 	}
324 
325 	tmp_dev = (struct of_device_id *)
326 		of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
327 	data->ops = (const struct usbmisc_ops *)tmp_dev->data;
328 	usbmisc = data;
329 
330 	return 0;
331 }
332 
333 static int usbmisc_imx_remove(struct platform_device *pdev)
334 {
335 	clk_disable_unprepare(usbmisc->clk);
336 	usbmisc = NULL;
337 	return 0;
338 }
339 
340 static struct platform_driver usbmisc_imx_driver = {
341 	.probe = usbmisc_imx_probe,
342 	.remove = usbmisc_imx_remove,
343 	.driver = {
344 		.name = "usbmisc_imx",
345 		.owner = THIS_MODULE,
346 		.of_match_table = usbmisc_imx_dt_ids,
347 	 },
348 };
349 
350 module_platform_driver(usbmisc_imx_driver);
351 
352 MODULE_ALIAS("platform:usbmisc-imx");
353 MODULE_LICENSE("GPL v2");
354 MODULE_DESCRIPTION("driver for imx usb non-core registers");
355 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
356