dwc3-exynos.c revision b0e45ddb96d5a972a8b76354f036b90549ae85b3
1d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov/**
2d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
3d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov *
4d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov *		http://www.samsung.com
6d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov *
7d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
8d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov *
9d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * This program is free software; you can redistribute it and/or modify
10d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * it under the terms of the GNU General Public License as published by
11d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * the Free Software Foundation; either version 2 of the License, or
12d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * (at your option) any later version.
13d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov */
14d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
15d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/module.h>
16d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/kernel.h>
17d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/slab.h>
18d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/platform_device.h>
19d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/platform_data/dwc3-exynos.h>
20d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/dma-mapping.h>
21d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/clk.h>
22d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi#include <linux/usb/otg.h>
23d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi#include <linux/usb/nop-usb-xceiv.h>
24accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#include <linux/of.h>
25d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
26d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include "core.h"
27d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
28d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstruct dwc3_exynos {
29d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct platform_device	*dwc3;
30d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	struct platform_device	*usb2_phy;
31d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	struct platform_device	*usb3_phy;
32d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct device		*dev;
33d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
34d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct clk		*clk;
35d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov};
36d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
3741ac7b3ab7fe1d6175839947a877fdf95cbd2211Bill Pembertonstatic int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
38d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi{
39d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	struct nop_usb_xceiv_platform_data pdata;
40d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	struct platform_device	*pdev;
41d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	int			ret;
42d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
43d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	memset(&pdata, 0x00, sizeof(pdata));
44d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
45b0e45ddb96d5a972a8b76354f036b90549ae85b3Vivek Gautam	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
46d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (!pdev)
47d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		return -ENOMEM;
48d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
49d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	exynos->usb2_phy = pdev;
50d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	pdata.type = USB_PHY_TYPE_USB2;
51d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
52d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
53d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (ret)
54d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		goto err1;
55d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
56b0e45ddb96d5a972a8b76354f036b90549ae85b3Vivek Gautam	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
57d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (!pdev) {
58d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		ret = -ENOMEM;
59d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		goto err1;
60d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	}
61d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
62d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	exynos->usb3_phy = pdev;
63d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	pdata.type = USB_PHY_TYPE_USB3;
64d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
65d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata));
66d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (ret)
67d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		goto err2;
68d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
69d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	ret = platform_device_add(exynos->usb2_phy);
70d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (ret)
71d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		goto err2;
72d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
73d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	ret = platform_device_add(exynos->usb3_phy);
74d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (ret)
75d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		goto err3;
76d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
77d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	return 0;
78d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
79d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbierr3:
80d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_del(exynos->usb2_phy);
81d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
82d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbierr2:
83d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_put(exynos->usb3_phy);
84d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
85d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbierr1:
86d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_put(exynos->usb2_phy);
87d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
88d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	return ret;
89d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi}
90d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
91accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautamstatic u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
92accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam
9341ac7b3ab7fe1d6175839947a877fdf95cbd2211Bill Pembertonstatic int dwc3_exynos_probe(struct platform_device *pdev)
94d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{
95d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct platform_device	*dwc3;
96d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct dwc3_exynos	*exynos;
97d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct clk		*clk;
9820b97dc18323938a92319abf031936b7d2686eafJingoo Han	struct device		*dev = &pdev->dev;
99d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
100d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	int			ret = -ENOMEM;
101d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
10220b97dc18323938a92319abf031936b7d2686eafJingoo Han	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
103d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (!exynos) {
10420b97dc18323938a92319abf031936b7d2686eafJingoo Han		dev_err(dev, "not enough memory\n");
10520b97dc18323938a92319abf031936b7d2686eafJingoo Han		return -ENOMEM;
106d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
107d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
108accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	/*
109accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 * Right now device-tree probed devices don't get dma_mask set.
110accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 * Since shared usb code relies on it, set it here for now.
111accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 * Once we move to full device tree support this will vanish off.
112accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 */
113accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	if (!pdev->dev.dma_mask)
114accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam		pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
115accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam
116d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	platform_set_drvdata(pdev, exynos);
117d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
118d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	ret = dwc3_exynos_register_phys(exynos);
119d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (ret) {
12020b97dc18323938a92319abf031936b7d2686eafJingoo Han		dev_err(dev, "couldn't register PHYs\n");
12120b97dc18323938a92319abf031936b7d2686eafJingoo Han		return ret;
122d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	}
123d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
124124dafde8f8174caf5cef1c3eaba001657d66f4fSebastian Andrzej Siewior	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
125d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (!dwc3) {
12620b97dc18323938a92319abf031936b7d2686eafJingoo Han		dev_err(dev, "couldn't allocate dwc3 device\n");
12720b97dc18323938a92319abf031936b7d2686eafJingoo Han		return -ENOMEM;
128d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
129d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
13020b97dc18323938a92319abf031936b7d2686eafJingoo Han	clk = devm_clk_get(dev, "usbdrd30");
131d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (IS_ERR(clk)) {
13220b97dc18323938a92319abf031936b7d2686eafJingoo Han		dev_err(dev, "couldn't get clock\n");
133d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		ret = -EINVAL;
13420b97dc18323938a92319abf031936b7d2686eafJingoo Han		goto err1;
135d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
136d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
13720b97dc18323938a92319abf031936b7d2686eafJingoo Han	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
138d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
13920b97dc18323938a92319abf031936b7d2686eafJingoo Han	dwc3->dev.parent = dev;
14020b97dc18323938a92319abf031936b7d2686eafJingoo Han	dwc3->dev.dma_mask = dev->dma_mask;
14120b97dc18323938a92319abf031936b7d2686eafJingoo Han	dwc3->dev.dma_parms = dev->dma_parms;
142d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	exynos->dwc3	= dwc3;
14320b97dc18323938a92319abf031936b7d2686eafJingoo Han	exynos->dev	= dev;
144d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	exynos->clk	= clk;
145d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
146d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_enable(exynos->clk);
147d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
148d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	ret = platform_device_add_resources(dwc3, pdev->resource,
149d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov			pdev->num_resources);
150d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (ret) {
15120b97dc18323938a92319abf031936b7d2686eafJingoo Han		dev_err(dev, "couldn't add resources to dwc3 device\n");
15220b97dc18323938a92319abf031936b7d2686eafJingoo Han		goto err2;
153d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
154d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
155d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	ret = platform_device_add(dwc3);
156d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (ret) {
15720b97dc18323938a92319abf031936b7d2686eafJingoo Han		dev_err(dev, "failed to register dwc3 device\n");
15820b97dc18323938a92319abf031936b7d2686eafJingoo Han		goto err2;
159d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
160d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
161d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	return 0;
162d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
16320b97dc18323938a92319abf031936b7d2686eafJingoo Hanerr2:
164d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_disable(clk);
165d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr1:
16620b97dc18323938a92319abf031936b7d2686eafJingoo Han	platform_device_put(dwc3);
16720b97dc18323938a92319abf031936b7d2686eafJingoo Han
168d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	return ret;
169d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}
170d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
171fb4e98ab63433c4d3a1588ea91c73f1cd7ebaa00Bill Pembertonstatic int dwc3_exynos_remove(struct platform_device *pdev)
172d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{
173d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct dwc3_exynos	*exynos = platform_get_drvdata(pdev);
174d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
175d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	platform_device_unregister(exynos->dwc3);
176d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_unregister(exynos->usb2_phy);
177d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_unregister(exynos->usb3_phy);
178d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
179d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_disable(exynos->clk);
180d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
181d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	return 0;
182d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}
183d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
184accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#ifdef CONFIG_OF
185accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautamstatic const struct of_device_id exynos_dwc3_match[] = {
186fe29db8fb22f5aa67af4bf30b85a0451c989a88bVivek Gautam	{ .compatible = "samsung,exynos5250-dwusb3" },
187accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	{},
188accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam};
189accefdd4b234f029a530928ee930b9dcac88fe84Vivek GautamMODULE_DEVICE_TABLE(of, exynos_dwc3_match);
190accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#endif
191accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam
192d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic struct platform_driver dwc3_exynos_driver = {
193d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	.probe		= dwc3_exynos_probe,
1947690417db5085f0de03aa70b8ca01b0118e8a1b4Bill Pemberton	.remove		= dwc3_exynos_remove,
195d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	.driver		= {
196d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		.name	= "exynos-dwc3",
197accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam		.of_match_table = of_match_ptr(exynos_dwc3_match),
198d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	},
199d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov};
200d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
201d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovmodule_platform_driver(dwc3_exynos_driver);
202d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
203d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_ALIAS("platform:exynos-dwc3");
204d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
205d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_LICENSE("GPL");
206d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
207