1 /*
2  * Copyright 2012 Freescale Semiconductor, Inc.
3  * Copyright (C) 2012 Marek Vasut <marex@denx.de>
4  * on behalf of DENX Software Engineering GmbH
5  *
6  * The code contained herein is licensed under the GNU General Public
7  * License. You may obtain a copy of the GNU General Public License
8  * Version 2 or later at the following locations:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13 
14 #include <linux/module.h>
15 #include <linux/of_platform.h>
16 #include <linux/of_gpio.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/usb/chipidea.h>
21 #include <linux/clk.h>
22 
23 #include "ci.h"
24 #include "ci_hdrc_imx.h"
25 
26 struct ci_hdrc_imx_platform_flag {
27 	unsigned int flags;
28 	bool runtime_pm;
29 };
30 
31 static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
32 	.flags = CI_HDRC_TURN_VBUS_EARLY_ON |
33 		CI_HDRC_DISABLE_STREAMING,
34 };
35 
36 static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
37 		CI_HDRC_DISABLE_STREAMING,
38 };
39 
40 static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
41 	.flags = CI_HDRC_IMX28_WRITE_FIX |
42 		CI_HDRC_TURN_VBUS_EARLY_ON |
43 		CI_HDRC_DISABLE_STREAMING,
44 };
45 
46 static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
47 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
48 		CI_HDRC_TURN_VBUS_EARLY_ON |
49 		CI_HDRC_DISABLE_STREAMING,
50 };
51 
52 static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
53 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
54 		CI_HDRC_TURN_VBUS_EARLY_ON |
55 		CI_HDRC_DISABLE_HOST_STREAMING,
56 };
57 
58 static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
59 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
60 		CI_HDRC_TURN_VBUS_EARLY_ON |
61 		CI_HDRC_DISABLE_HOST_STREAMING,
62 };
63 
64 static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
65 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
66 		CI_HDRC_TURN_VBUS_EARLY_ON,
67 };
68 
69 static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
70 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
71 };
72 
73 static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
74 	{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
75 	{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
76 	{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
77 	{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
78 	{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
79 	{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
80 	{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
81 	{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
82 	{ /* sentinel */ }
83 };
84 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
85 
86 struct ci_hdrc_imx_data {
87 	struct usb_phy *phy;
88 	struct platform_device *ci_pdev;
89 	struct clk *clk;
90 	struct imx_usbmisc_data *usbmisc_data;
91 	bool supports_runtime_pm;
92 	bool in_lpm;
93 	/* SoC before i.mx6 (except imx23/imx28) needs three clks */
94 	bool need_three_clks;
95 	struct clk *clk_ipg;
96 	struct clk *clk_ahb;
97 	struct clk *clk_per;
98 	/* --------------------------------- */
99 };
100 
101 /* Common functions shared by usbmisc drivers */
102 
103 static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
104 {
105 	struct platform_device *misc_pdev;
106 	struct device_node *np = dev->of_node;
107 	struct of_phandle_args args;
108 	struct imx_usbmisc_data *data;
109 	int ret;
110 
111 	/*
112 	 * In case the fsl,usbmisc property is not present this device doesn't
113 	 * need usbmisc. Return NULL (which is no error here)
114 	 */
115 	if (!of_get_property(np, "fsl,usbmisc", NULL))
116 		return NULL;
117 
118 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
119 	if (!data)
120 		return ERR_PTR(-ENOMEM);
121 
122 	ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
123 					0, &args);
124 	if (ret) {
125 		dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
126 			ret);
127 		return ERR_PTR(ret);
128 	}
129 
130 	data->index = args.args[0];
131 
132 	misc_pdev = of_find_device_by_node(args.np);
133 	of_node_put(args.np);
134 
135 	if (!misc_pdev || !platform_get_drvdata(misc_pdev))
136 		return ERR_PTR(-EPROBE_DEFER);
137 
138 	data->dev = &misc_pdev->dev;
139 
140 	if (of_find_property(np, "disable-over-current", NULL))
141 		data->disable_oc = 1;
142 
143 	if (of_find_property(np, "external-vbus-divider", NULL))
144 		data->evdo = 1;
145 
146 	return data;
147 }
148 
149 /* End of common functions shared by usbmisc drivers*/
150 static int imx_get_clks(struct device *dev)
151 {
152 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
153 	int ret = 0;
154 
155 	data->clk_ipg = devm_clk_get(dev, "ipg");
156 	if (IS_ERR(data->clk_ipg)) {
157 		/* If the platform only needs one clocks */
158 		data->clk = devm_clk_get(dev, NULL);
159 		if (IS_ERR(data->clk)) {
160 			ret = PTR_ERR(data->clk);
161 			dev_err(dev,
162 				"Failed to get clks, err=%ld,%ld\n",
163 				PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
164 			return ret;
165 		}
166 		return ret;
167 	}
168 
169 	data->clk_ahb = devm_clk_get(dev, "ahb");
170 	if (IS_ERR(data->clk_ahb)) {
171 		ret = PTR_ERR(data->clk_ahb);
172 		dev_err(dev,
173 			"Failed to get ahb clock, err=%d\n", ret);
174 		return ret;
175 	}
176 
177 	data->clk_per = devm_clk_get(dev, "per");
178 	if (IS_ERR(data->clk_per)) {
179 		ret = PTR_ERR(data->clk_per);
180 		dev_err(dev,
181 			"Failed to get per clock, err=%d\n", ret);
182 		return ret;
183 	}
184 
185 	data->need_three_clks = true;
186 	return ret;
187 }
188 
189 static int imx_prepare_enable_clks(struct device *dev)
190 {
191 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
192 	int ret = 0;
193 
194 	if (data->need_three_clks) {
195 		ret = clk_prepare_enable(data->clk_ipg);
196 		if (ret) {
197 			dev_err(dev,
198 				"Failed to prepare/enable ipg clk, err=%d\n",
199 				ret);
200 			return ret;
201 		}
202 
203 		ret = clk_prepare_enable(data->clk_ahb);
204 		if (ret) {
205 			dev_err(dev,
206 				"Failed to prepare/enable ahb clk, err=%d\n",
207 				ret);
208 			clk_disable_unprepare(data->clk_ipg);
209 			return ret;
210 		}
211 
212 		ret = clk_prepare_enable(data->clk_per);
213 		if (ret) {
214 			dev_err(dev,
215 				"Failed to prepare/enable per clk, err=%d\n",
216 				ret);
217 			clk_disable_unprepare(data->clk_ahb);
218 			clk_disable_unprepare(data->clk_ipg);
219 			return ret;
220 		}
221 	} else {
222 		ret = clk_prepare_enable(data->clk);
223 		if (ret) {
224 			dev_err(dev,
225 				"Failed to prepare/enable clk, err=%d\n",
226 				ret);
227 			return ret;
228 		}
229 	}
230 
231 	return ret;
232 }
233 
234 static void imx_disable_unprepare_clks(struct device *dev)
235 {
236 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
237 
238 	if (data->need_three_clks) {
239 		clk_disable_unprepare(data->clk_per);
240 		clk_disable_unprepare(data->clk_ahb);
241 		clk_disable_unprepare(data->clk_ipg);
242 	} else {
243 		clk_disable_unprepare(data->clk);
244 	}
245 }
246 
247 static int ci_hdrc_imx_probe(struct platform_device *pdev)
248 {
249 	struct ci_hdrc_imx_data *data;
250 	struct ci_hdrc_platform_data pdata = {
251 		.name		= dev_name(&pdev->dev),
252 		.capoffset	= DEF_CAPOFFSET,
253 	};
254 	int ret;
255 	const struct of_device_id *of_id;
256 	const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
257 
258 	of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
259 	if (!of_id)
260 		return -ENODEV;
261 
262 	imx_platform_flag = of_id->data;
263 
264 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
265 	if (!data)
266 		return -ENOMEM;
267 
268 	platform_set_drvdata(pdev, data);
269 	data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
270 	if (IS_ERR(data->usbmisc_data))
271 		return PTR_ERR(data->usbmisc_data);
272 
273 	ret = imx_get_clks(&pdev->dev);
274 	if (ret)
275 		return ret;
276 
277 	ret = imx_prepare_enable_clks(&pdev->dev);
278 	if (ret)
279 		return ret;
280 
281 	data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
282 	if (IS_ERR(data->phy)) {
283 		ret = PTR_ERR(data->phy);
284 		/* Return -EINVAL if no usbphy is available */
285 		if (ret == -ENODEV)
286 			ret = -EINVAL;
287 		goto err_clk;
288 	}
289 
290 	pdata.usb_phy = data->phy;
291 	pdata.flags |= imx_platform_flag->flags;
292 	if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
293 		data->supports_runtime_pm = true;
294 
295 	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
296 	if (ret)
297 		goto err_clk;
298 
299 	ret = imx_usbmisc_init(data->usbmisc_data);
300 	if (ret) {
301 		dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
302 		goto err_clk;
303 	}
304 
305 	data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
306 				pdev->resource, pdev->num_resources,
307 				&pdata);
308 	if (IS_ERR(data->ci_pdev)) {
309 		ret = PTR_ERR(data->ci_pdev);
310 		if (ret != -EPROBE_DEFER)
311 			dev_err(&pdev->dev,
312 				"ci_hdrc_add_device failed, err=%d\n", ret);
313 		goto err_clk;
314 	}
315 
316 	ret = imx_usbmisc_init_post(data->usbmisc_data);
317 	if (ret) {
318 		dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret);
319 		goto disable_device;
320 	}
321 
322 	if (data->supports_runtime_pm) {
323 		pm_runtime_set_active(&pdev->dev);
324 		pm_runtime_enable(&pdev->dev);
325 	}
326 
327 	device_set_wakeup_capable(&pdev->dev, true);
328 
329 	return 0;
330 
331 disable_device:
332 	ci_hdrc_remove_device(data->ci_pdev);
333 err_clk:
334 	imx_disable_unprepare_clks(&pdev->dev);
335 	return ret;
336 }
337 
338 static int ci_hdrc_imx_remove(struct platform_device *pdev)
339 {
340 	struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
341 
342 	if (data->supports_runtime_pm) {
343 		pm_runtime_get_sync(&pdev->dev);
344 		pm_runtime_disable(&pdev->dev);
345 		pm_runtime_put_noidle(&pdev->dev);
346 	}
347 	ci_hdrc_remove_device(data->ci_pdev);
348 	imx_disable_unprepare_clks(&pdev->dev);
349 
350 	return 0;
351 }
352 
353 static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
354 {
355 	ci_hdrc_imx_remove(pdev);
356 }
357 
358 #ifdef CONFIG_PM
359 static int imx_controller_suspend(struct device *dev)
360 {
361 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
362 
363 	dev_dbg(dev, "at %s\n", __func__);
364 
365 	imx_disable_unprepare_clks(dev);
366 	data->in_lpm = true;
367 
368 	return 0;
369 }
370 
371 static int imx_controller_resume(struct device *dev)
372 {
373 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
374 	int ret = 0;
375 
376 	dev_dbg(dev, "at %s\n", __func__);
377 
378 	if (!data->in_lpm) {
379 		WARN_ON(1);
380 		return 0;
381 	}
382 
383 	ret = imx_prepare_enable_clks(dev);
384 	if (ret)
385 		return ret;
386 
387 	data->in_lpm = false;
388 
389 	ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
390 	if (ret) {
391 		dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
392 		goto clk_disable;
393 	}
394 
395 	return 0;
396 
397 clk_disable:
398 	imx_disable_unprepare_clks(dev);
399 	return ret;
400 }
401 
402 #ifdef CONFIG_PM_SLEEP
403 static int ci_hdrc_imx_suspend(struct device *dev)
404 {
405 	int ret;
406 
407 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
408 
409 	if (data->in_lpm)
410 		/* The core's suspend doesn't run */
411 		return 0;
412 
413 	if (device_may_wakeup(dev)) {
414 		ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
415 		if (ret) {
416 			dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
417 					ret);
418 			return ret;
419 		}
420 	}
421 
422 	return imx_controller_suspend(dev);
423 }
424 
425 static int ci_hdrc_imx_resume(struct device *dev)
426 {
427 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
428 	int ret;
429 
430 	ret = imx_controller_resume(dev);
431 	if (!ret && data->supports_runtime_pm) {
432 		pm_runtime_disable(dev);
433 		pm_runtime_set_active(dev);
434 		pm_runtime_enable(dev);
435 	}
436 
437 	return ret;
438 }
439 #endif /* CONFIG_PM_SLEEP */
440 
441 static int ci_hdrc_imx_runtime_suspend(struct device *dev)
442 {
443 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
444 	int ret;
445 
446 	if (data->in_lpm) {
447 		WARN_ON(1);
448 		return 0;
449 	}
450 
451 	ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
452 	if (ret) {
453 		dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
454 		return ret;
455 	}
456 
457 	return imx_controller_suspend(dev);
458 }
459 
460 static int ci_hdrc_imx_runtime_resume(struct device *dev)
461 {
462 	return imx_controller_resume(dev);
463 }
464 
465 #endif /* CONFIG_PM */
466 
467 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
468 	SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
469 	SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
470 			ci_hdrc_imx_runtime_resume, NULL)
471 };
472 static struct platform_driver ci_hdrc_imx_driver = {
473 	.probe = ci_hdrc_imx_probe,
474 	.remove = ci_hdrc_imx_remove,
475 	.shutdown = ci_hdrc_imx_shutdown,
476 	.driver = {
477 		.name = "imx_usb",
478 		.of_match_table = ci_hdrc_imx_dt_ids,
479 		.pm = &ci_hdrc_imx_pm_ops,
480 	 },
481 };
482 
483 module_platform_driver(ci_hdrc_imx_driver);
484 
485 MODULE_ALIAS("platform:imx-usb");
486 MODULE_LICENSE("GPL v2");
487 MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
488 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
489 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
490