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 = imx_usbmisc_init(data->usbmisc_data);
296 	if (ret) {
297 		dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
298 		goto err_clk;
299 	}
300 
301 	data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
302 				pdev->resource, pdev->num_resources,
303 				&pdata);
304 	if (IS_ERR(data->ci_pdev)) {
305 		ret = PTR_ERR(data->ci_pdev);
306 		if (ret != -EPROBE_DEFER)
307 			dev_err(&pdev->dev,
308 				"ci_hdrc_add_device failed, err=%d\n", ret);
309 		goto err_clk;
310 	}
311 
312 	ret = imx_usbmisc_init_post(data->usbmisc_data);
313 	if (ret) {
314 		dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret);
315 		goto disable_device;
316 	}
317 
318 	if (data->supports_runtime_pm) {
319 		pm_runtime_set_active(&pdev->dev);
320 		pm_runtime_enable(&pdev->dev);
321 	}
322 
323 	device_set_wakeup_capable(&pdev->dev, true);
324 
325 	return 0;
326 
327 disable_device:
328 	ci_hdrc_remove_device(data->ci_pdev);
329 err_clk:
330 	imx_disable_unprepare_clks(&pdev->dev);
331 	return ret;
332 }
333 
334 static int ci_hdrc_imx_remove(struct platform_device *pdev)
335 {
336 	struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
337 
338 	if (data->supports_runtime_pm) {
339 		pm_runtime_get_sync(&pdev->dev);
340 		pm_runtime_disable(&pdev->dev);
341 		pm_runtime_put_noidle(&pdev->dev);
342 	}
343 	ci_hdrc_remove_device(data->ci_pdev);
344 	imx_disable_unprepare_clks(&pdev->dev);
345 
346 	return 0;
347 }
348 
349 static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
350 {
351 	ci_hdrc_imx_remove(pdev);
352 }
353 
354 #ifdef CONFIG_PM
355 static int imx_controller_suspend(struct device *dev)
356 {
357 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
358 
359 	dev_dbg(dev, "at %s\n", __func__);
360 
361 	imx_disable_unprepare_clks(dev);
362 	data->in_lpm = true;
363 
364 	return 0;
365 }
366 
367 static int imx_controller_resume(struct device *dev)
368 {
369 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
370 	int ret = 0;
371 
372 	dev_dbg(dev, "at %s\n", __func__);
373 
374 	if (!data->in_lpm) {
375 		WARN_ON(1);
376 		return 0;
377 	}
378 
379 	ret = imx_prepare_enable_clks(dev);
380 	if (ret)
381 		return ret;
382 
383 	data->in_lpm = false;
384 
385 	ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
386 	if (ret) {
387 		dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
388 		goto clk_disable;
389 	}
390 
391 	return 0;
392 
393 clk_disable:
394 	imx_disable_unprepare_clks(dev);
395 	return ret;
396 }
397 
398 #ifdef CONFIG_PM_SLEEP
399 static int ci_hdrc_imx_suspend(struct device *dev)
400 {
401 	int ret;
402 
403 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
404 
405 	if (data->in_lpm)
406 		/* The core's suspend doesn't run */
407 		return 0;
408 
409 	if (device_may_wakeup(dev)) {
410 		ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
411 		if (ret) {
412 			dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
413 					ret);
414 			return ret;
415 		}
416 	}
417 
418 	return imx_controller_suspend(dev);
419 }
420 
421 static int ci_hdrc_imx_resume(struct device *dev)
422 {
423 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
424 	int ret;
425 
426 	ret = imx_controller_resume(dev);
427 	if (!ret && data->supports_runtime_pm) {
428 		pm_runtime_disable(dev);
429 		pm_runtime_set_active(dev);
430 		pm_runtime_enable(dev);
431 	}
432 
433 	return ret;
434 }
435 #endif /* CONFIG_PM_SLEEP */
436 
437 static int ci_hdrc_imx_runtime_suspend(struct device *dev)
438 {
439 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
440 	int ret;
441 
442 	if (data->in_lpm) {
443 		WARN_ON(1);
444 		return 0;
445 	}
446 
447 	ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
448 	if (ret) {
449 		dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
450 		return ret;
451 	}
452 
453 	return imx_controller_suspend(dev);
454 }
455 
456 static int ci_hdrc_imx_runtime_resume(struct device *dev)
457 {
458 	return imx_controller_resume(dev);
459 }
460 
461 #endif /* CONFIG_PM */
462 
463 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
464 	SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
465 	SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
466 			ci_hdrc_imx_runtime_resume, NULL)
467 };
468 static struct platform_driver ci_hdrc_imx_driver = {
469 	.probe = ci_hdrc_imx_probe,
470 	.remove = ci_hdrc_imx_remove,
471 	.shutdown = ci_hdrc_imx_shutdown,
472 	.driver = {
473 		.name = "imx_usb",
474 		.of_match_table = ci_hdrc_imx_dt_ids,
475 		.pm = &ci_hdrc_imx_pm_ops,
476 	 },
477 };
478 
479 module_platform_driver(ci_hdrc_imx_driver);
480 
481 MODULE_ALIAS("platform:imx-usb");
482 MODULE_LICENSE("GPL v2");
483 MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
484 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
485 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
486