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