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