blob: 5e9053eb4298332a789b06c4ab58f81ffe165b72 [file] [log] [blame]
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +01001/*
2 * Copyright (C) 2010 ST-Ericsson AB
3 * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
4 *
5 * Based on omap2430.c
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/init.h>
25#include <linux/clk.h>
Kishon Vijay Abraham Ided017e2012-06-26 17:40:32 +053026#include <linux/err.h>
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010027#include <linux/io.h>
28#include <linux/platform_device.h>
29
30#include "musb_core.h"
31
32struct ux500_glue {
33 struct device *dev;
34 struct platform_device *musb;
35 struct clk *clk;
36};
37#define glue_to_musb(g) platform_get_drvdata(g->musb)
38
39static int ux500_musb_init(struct musb *musb)
40{
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +053041 musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
Kishon Vijay Abraham Ided017e2012-06-26 17:40:32 +053042 if (IS_ERR_OR_NULL(musb->xceiv)) {
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010043 pr_err("HS USB OTG: no transceiver configured\n");
44 return -ENODEV;
45 }
46
47 return 0;
48}
49
50static int ux500_musb_exit(struct musb *musb)
51{
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +053052 usb_put_phy(musb->xceiv);
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010053
54 return 0;
55}
56
57static const struct musb_platform_ops ux500_ops = {
58 .init = ux500_musb_init,
59 .exit = ux500_musb_exit,
60};
61
Felipe Balbie9e8c852012-01-26 12:40:23 +020062static int __devinit ux500_probe(struct platform_device *pdev)
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010063{
64 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
65 struct platform_device *musb;
66 struct ux500_glue *glue;
67 struct clk *clk;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010068 int ret = -ENOMEM;
69
70 glue = kzalloc(sizeof(*glue), GFP_KERNEL);
71 if (!glue) {
72 dev_err(&pdev->dev, "failed to allocate glue context\n");
73 goto err0;
74 }
75
Sebastian Andrzej Siewior2f771162012-10-31 16:12:43 +010076 musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010077 if (!musb) {
78 dev_err(&pdev->dev, "failed to allocate musb device\n");
Sebastian Andrzej Siewior2f771162012-10-31 16:12:43 +010079 goto err1;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010080 }
81
82 clk = clk_get(&pdev->dev, "usb");
83 if (IS_ERR(clk)) {
84 dev_err(&pdev->dev, "failed to get clock\n");
85 ret = PTR_ERR(clk);
B, Ravi65b3d522012-08-31 11:09:49 +000086 goto err3;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010087 }
88
89 ret = clk_enable(clk);
90 if (ret) {
91 dev_err(&pdev->dev, "failed to enable clock\n");
B, Ravi65b3d522012-08-31 11:09:49 +000092 goto err4;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010093 }
94
95 musb->dev.parent = &pdev->dev;
Mian Yousaf Kaukab87266062011-03-15 16:24:29 +010096 musb->dev.dma_mask = pdev->dev.dma_mask;
97 musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +010098
99 glue->dev = &pdev->dev;
100 glue->musb = musb;
101 glue->clk = clk;
102
103 pdata->platform_ops = &ux500_ops;
104
105 platform_set_drvdata(pdev, glue);
106
107 ret = platform_device_add_resources(musb, pdev->resource,
108 pdev->num_resources);
109 if (ret) {
110 dev_err(&pdev->dev, "failed to add resources\n");
B, Ravi65b3d522012-08-31 11:09:49 +0000111 goto err5;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100112 }
113
114 ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
115 if (ret) {
116 dev_err(&pdev->dev, "failed to add platform_data\n");
B, Ravi65b3d522012-08-31 11:09:49 +0000117 goto err5;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100118 }
119
120 ret = platform_device_add(musb);
121 if (ret) {
122 dev_err(&pdev->dev, "failed to register musb device\n");
B, Ravi65b3d522012-08-31 11:09:49 +0000123 goto err5;
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100124 }
125
126 return 0;
127
B, Ravi65b3d522012-08-31 11:09:49 +0000128err5:
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100129 clk_disable(clk);
130
B, Ravi65b3d522012-08-31 11:09:49 +0000131err4:
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100132 clk_put(clk);
133
B, Ravi65b3d522012-08-31 11:09:49 +0000134err3:
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100135 platform_device_put(musb);
136
137err1:
138 kfree(glue);
139
140err0:
141 return ret;
142}
143
Felipe Balbie9e8c852012-01-26 12:40:23 +0200144static int __devexit ux500_remove(struct platform_device *pdev)
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100145{
146 struct ux500_glue *glue = platform_get_drvdata(pdev);
147
Wei Yongjun4b0de6f2012-10-23 13:36:43 +0800148 platform_device_unregister(glue->musb);
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100149 clk_disable(glue->clk);
150 clk_put(glue->clk);
151 kfree(glue);
152
153 return 0;
154}
155
156#ifdef CONFIG_PM
157static int ux500_suspend(struct device *dev)
158{
159 struct ux500_glue *glue = dev_get_drvdata(dev);
160 struct musb *musb = glue_to_musb(glue);
161
Heikki Krogerusb96d3b02012-02-13 13:24:18 +0200162 usb_phy_set_suspend(musb->xceiv, 1);
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100163 clk_disable(glue->clk);
164
165 return 0;
166}
167
168static int ux500_resume(struct device *dev)
169{
170 struct ux500_glue *glue = dev_get_drvdata(dev);
171 struct musb *musb = glue_to_musb(glue);
172 int ret;
173
174 ret = clk_enable(glue->clk);
175 if (ret) {
176 dev_err(dev, "failed to enable clock\n");
177 return ret;
178 }
179
Heikki Krogerusb96d3b02012-02-13 13:24:18 +0200180 usb_phy_set_suspend(musb->xceiv, 0);
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100181
182 return 0;
183}
184
185static const struct dev_pm_ops ux500_pm_ops = {
186 .suspend = ux500_suspend,
187 .resume = ux500_resume,
188};
189
190#define DEV_PM_OPS (&ux500_pm_ops)
191#else
192#define DEV_PM_OPS NULL
193#endif
194
195static struct platform_driver ux500_driver = {
Felipe Balbie9e8c852012-01-26 12:40:23 +0200196 .probe = ux500_probe,
197 .remove = __devexit_p(ux500_remove),
Mian Yousaf Kaukab4bc36fd2010-12-09 13:05:01 +0100198 .driver = {
199 .name = "musb-ux500",
200 .pm = DEV_PM_OPS,
201 },
202};
203
204MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
205MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
206MODULE_LICENSE("GPL v2");
Srinivas Kandagatla0e7090a2012-10-10 19:37:21 +0100207module_platform_driver(ux500_driver);