dwc3-exynos.c revision fb4e98ab63433c4d3a1588ea91c73f1cd7ebaa00
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
45d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	pdev = platform_device_alloc("nop_usb_xceiv", 0);
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
56d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	pdev = platform_device_alloc("nop_usb_xceiv", 1);
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;
98d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
99d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	int			ret = -ENOMEM;
100d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
101d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
102d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (!exynos) {
103d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		dev_err(&pdev->dev, "not enough memory\n");
104d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		goto err0;
105d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
106d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
107accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	/*
108accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 * Right now device-tree probed devices don't get dma_mask set.
109accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 * Since shared usb code relies on it, set it here for now.
110accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 * Once we move to full device tree support this will vanish off.
111accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	 */
112accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	if (!pdev->dev.dma_mask)
113accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam		pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
114accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam
115d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	platform_set_drvdata(pdev, exynos);
116d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
117d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	ret = dwc3_exynos_register_phys(exynos);
118d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	if (ret) {
119d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		dev_err(&pdev->dev, "couldn't register PHYs\n");
120d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi		goto err1;
121d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	}
122d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi
123124dafde8f8174caf5cef1c3eaba001657d66f4fSebastian Andrzej Siewior	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
124d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (!dwc3) {
125d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
126124dafde8f8174caf5cef1c3eaba001657d66f4fSebastian Andrzej Siewior		goto err1;
127d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
128d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
129d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk = clk_get(&pdev->dev, "usbdrd30");
130d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (IS_ERR(clk)) {
131d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		dev_err(&pdev->dev, "couldn't get clock\n");
132d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		ret = -EINVAL;
133d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		goto err3;
134d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
135d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
136d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
137d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
138d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	dwc3->dev.parent = &pdev->dev;
139d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	dwc3->dev.dma_mask = pdev->dev.dma_mask;
140d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	dwc3->dev.dma_parms = pdev->dev.dma_parms;
141d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	exynos->dwc3	= dwc3;
142d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	exynos->dev	= &pdev->dev;
143d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	exynos->clk	= clk;
144d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
145d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_enable(exynos->clk);
146d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
147d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	ret = platform_device_add_resources(dwc3, pdev->resource,
148d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov			pdev->num_resources);
149d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (ret) {
150d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
151d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		goto err4;
152d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
153d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
154d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	ret = platform_device_add(dwc3);
155d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	if (ret) {
156d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		dev_err(&pdev->dev, "failed to register dwc3 device\n");
157d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		goto err4;
158d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	}
159d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
160d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	return 0;
161d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
162d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr4:
163d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_disable(clk);
164d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_put(clk);
165d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr3:
166d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	platform_device_put(dwc3);
167d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr1:
168d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	kfree(exynos);
169d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr0:
170d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	return ret;
171d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}
172d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
173fb4e98ab63433c4d3a1588ea91c73f1cd7ebaa00Bill Pembertonstatic int dwc3_exynos_remove(struct platform_device *pdev)
174d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{
175d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	struct dwc3_exynos	*exynos = platform_get_drvdata(pdev);
176d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
177d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	platform_device_unregister(exynos->dwc3);
178d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_unregister(exynos->usb2_phy);
179d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi	platform_device_unregister(exynos->usb3_phy);
180d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
181d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_disable(exynos->clk);
182d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	clk_put(exynos->clk);
183d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
184d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	kfree(exynos);
185d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
186d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	return 0;
187d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}
188d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
189accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#ifdef CONFIG_OF
190accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautamstatic const struct of_device_id exynos_dwc3_match[] = {
191accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	{ .compatible = "samsung,exynos-dwc3" },
192accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam	{},
193accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam};
194accefdd4b234f029a530928ee930b9dcac88fe84Vivek GautamMODULE_DEVICE_TABLE(of, exynos_dwc3_match);
195accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#endif
196accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam
197d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic struct platform_driver dwc3_exynos_driver = {
198d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	.probe		= dwc3_exynos_probe,
1997690417db5085f0de03aa70b8ca01b0118e8a1b4Bill Pemberton	.remove		= dwc3_exynos_remove,
200d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	.driver		= {
201d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov		.name	= "exynos-dwc3",
202accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam		.of_match_table = of_match_ptr(exynos_dwc3_match),
203d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov	},
204d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov};
205d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
206d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovmodule_platform_driver(dwc3_exynos_driver);
207d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov
208d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_ALIAS("platform:exynos-dwc3");
209d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
210d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_LICENSE("GPL");
211d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
212