usb: phy: nop: Handle RESET for the PHY
[profile/ivi/kernel-x86-ivi.git] / drivers / usb / otg / nop-usb-xceiv.c
1 /*
2  * drivers/usb/otg/nop-usb-xceiv.c
3  *
4  * NOP USB transceiver for all USB transceiver which are either built-in
5  * into USB IP or which are mostly autonomous.
6  *
7  * Copyright (C) 2009 Texas Instruments Inc
8  * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * Current status:
25  *      This provides a "nop" transceiver for PHYs which are
26  *      autonomous such as isp1504, isp1707, etc.
27  */
28
29 #include <linux/module.h>
30 #include <linux/platform_device.h>
31 #include <linux/dma-mapping.h>
32 #include <linux/usb/otg.h>
33 #include <linux/usb/nop-usb-xceiv.h>
34 #include <linux/slab.h>
35 #include <linux/clk.h>
36 #include <linux/regulator/consumer.h>
37
38 struct nop_usb_xceiv {
39         struct usb_phy          phy;
40         struct device           *dev;
41         struct clk              *clk;
42         struct regulator        *vcc;
43         struct regulator        *reset;
44 };
45
46 static struct platform_device *pd;
47
48 void usb_nop_xceiv_register(void)
49 {
50         if (pd)
51                 return;
52         pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
53         if (!pd) {
54                 printk(KERN_ERR "Unable to register usb nop transceiver\n");
55                 return;
56         }
57 }
58 EXPORT_SYMBOL(usb_nop_xceiv_register);
59
60 void usb_nop_xceiv_unregister(void)
61 {
62         platform_device_unregister(pd);
63         pd = NULL;
64 }
65 EXPORT_SYMBOL(usb_nop_xceiv_unregister);
66
67 static int nop_set_suspend(struct usb_phy *x, int suspend)
68 {
69         return 0;
70 }
71
72 static int nop_init(struct usb_phy *phy)
73 {
74         struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
75
76         if (!IS_ERR(nop->vcc)) {
77                 if (regulator_enable(nop->vcc))
78                         dev_err(phy->dev, "Failed to enable power\n");
79         }
80
81         if (!IS_ERR(nop->clk))
82                 clk_enable(nop->clk);
83
84         if (!IS_ERR(nop->reset)) {
85                 /* De-assert RESET */
86                 if (regulator_enable(nop->reset))
87                         dev_err(phy->dev, "Failed to de-assert reset\n");
88         }
89
90         return 0;
91 }
92
93 static void nop_shutdown(struct usb_phy *phy)
94 {
95         struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
96
97         if (!IS_ERR(nop->reset)) {
98                 /* Assert RESET */
99                 if (regulator_disable(nop->reset))
100                         dev_err(phy->dev, "Failed to assert reset\n");
101         }
102
103         if (!IS_ERR(nop->clk))
104                 clk_disable(nop->clk);
105
106         if (!IS_ERR(nop->vcc)) {
107                 if (regulator_disable(nop->vcc))
108                         dev_err(phy->dev, "Failed to disable power\n");
109         }
110 }
111
112 static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
113 {
114         if (!otg)
115                 return -ENODEV;
116
117         if (!gadget) {
118                 otg->gadget = NULL;
119                 return -ENODEV;
120         }
121
122         otg->gadget = gadget;
123         otg->phy->state = OTG_STATE_B_IDLE;
124         return 0;
125 }
126
127 static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
128 {
129         if (!otg)
130                 return -ENODEV;
131
132         if (!host) {
133                 otg->host = NULL;
134                 return -ENODEV;
135         }
136
137         otg->host = host;
138         return 0;
139 }
140
141 static int nop_usb_xceiv_probe(struct platform_device *pdev)
142 {
143         struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
144         struct nop_usb_xceiv    *nop;
145         enum usb_phy_type       type = USB_PHY_TYPE_USB2;
146         int err;
147
148         nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
149         if (!nop)
150                 return -ENOMEM;
151
152         nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
153                                                         GFP_KERNEL);
154         if (!nop->phy.otg)
155                 return -ENOMEM;
156
157         if (pdata)
158                 type = pdata->type;
159
160         nop->clk = devm_clk_get(&pdev->dev, "main_clk");
161         if (IS_ERR(nop->clk)) {
162                 dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
163                                         PTR_ERR(nop->clk));
164         }
165
166         if (!IS_ERR(nop->clk) && pdata && pdata->clk_rate) {
167                 err = clk_set_rate(nop->clk, pdata->clk_rate);
168                 if (err) {
169                         dev_err(&pdev->dev, "Error setting clock rate\n");
170                         return err;
171                 }
172         }
173
174         if (!IS_ERR(nop->clk)) {
175                 err = clk_prepare(nop->clk);
176                 if (err) {
177                         dev_err(&pdev->dev, "Error preparing clock\n");
178                         return err;
179                 }
180         }
181
182         nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
183         if (IS_ERR(nop->vcc)) {
184                 dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
185                                         PTR_ERR(nop->vcc));
186         }
187
188         nop->reset = devm_regulator_get(&pdev->dev, "reset");
189         if (IS_ERR(nop->reset)) {
190                 dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
191                                         PTR_ERR(nop->reset));
192         }
193
194         nop->dev                = &pdev->dev;
195         nop->phy.dev            = nop->dev;
196         nop->phy.label          = "nop-xceiv";
197         nop->phy.set_suspend    = nop_set_suspend;
198         nop->phy.init           = nop_init;
199         nop->phy.shutdown       = nop_shutdown;
200         nop->phy.state          = OTG_STATE_UNDEFINED;
201
202         nop->phy.otg->phy               = &nop->phy;
203         nop->phy.otg->set_host          = nop_set_host;
204         nop->phy.otg->set_peripheral    = nop_set_peripheral;
205
206         err = usb_add_phy(&nop->phy, type);
207         if (err) {
208                 dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
209                         err);
210                 goto err_add;
211         }
212
213         platform_set_drvdata(pdev, nop);
214
215         ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
216
217         return 0;
218
219 err_add:
220         if (!IS_ERR(nop->clk))
221                 clk_unprepare(nop->clk);
222         return err;
223 }
224
225 static int nop_usb_xceiv_remove(struct platform_device *pdev)
226 {
227         struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
228
229         if (!IS_ERR(nop->clk))
230                 clk_unprepare(nop->clk);
231
232         usb_remove_phy(&nop->phy);
233
234         platform_set_drvdata(pdev, NULL);
235
236         return 0;
237 }
238
239 static struct platform_driver nop_usb_xceiv_driver = {
240         .probe          = nop_usb_xceiv_probe,
241         .remove         = nop_usb_xceiv_remove,
242         .driver         = {
243                 .name   = "nop_usb_xceiv",
244                 .owner  = THIS_MODULE,
245         },
246 };
247
248 static int __init nop_usb_xceiv_init(void)
249 {
250         return platform_driver_register(&nop_usb_xceiv_driver);
251 }
252 subsys_initcall(nop_usb_xceiv_init);
253
254 static void __exit nop_usb_xceiv_exit(void)
255 {
256         platform_driver_unregister(&nop_usb_xceiv_driver);
257 }
258 module_exit(nop_usb_xceiv_exit);
259
260 MODULE_ALIAS("platform:nop_usb_xceiv");
261 MODULE_AUTHOR("Texas Instruments Inc");
262 MODULE_DESCRIPTION("NOP USB Transceiver driver");
263 MODULE_LICENSE("GPL");