2 * Copyright (C) 2010 Google, Inc.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <linux/usb.h>
20 #include <linux/usb/otg.h>
21 #include <linux/usb/gadget.h>
22 #include <linux/usb/hcd.h>
23 #include <linux/platform_device.h>
24 #include <linux/clk.h>
26 #include <linux/delay.h>
27 #include <linux/err.h>
29 #define TEGRA_USB_PHY_WAKEUP_REG_OFFSET 0x408
30 #define TEGRA_VBUS_WAKEUP_SW_VALUE (1 << 12)
31 #define TEGRA_VBUS_WAKEUP_SW_ENABLE (1 << 11)
32 #define TEGRA_ID_SW_VALUE (1 << 4)
33 #define TEGRA_ID_SW_ENABLE (1 << 3)
35 struct cpcap_otg_data {
36 struct otg_transceiver otg;
37 struct notifier_block nb;
40 struct platform_device *host;
41 struct platform_device *pdev;
44 static const char *cpcap_state_name(enum usb_otg_state state)
46 if (state == OTG_STATE_A_HOST)
48 if (state == OTG_STATE_B_PERIPHERAL)
50 if (state == OTG_STATE_A_SUSPEND)
55 void cpcap_start_host(struct cpcap_otg_data *cpcap)
59 cpcap->pdev = platform_device_alloc(cpcap->host->name, cpcap->host->id);
63 if (cpcap->host->resource) {
64 retval = platform_device_add_resources(cpcap->pdev,
65 cpcap->host->resource,
66 cpcap->host->num_resources);
71 cpcap->pdev->dev.dma_mask = cpcap->host->dev.dma_mask;
72 cpcap->pdev->dev.coherent_dma_mask = cpcap->host->dev.coherent_dma_mask;
74 retval = platform_device_add(cpcap->pdev);
80 pr_err("%s: failed to add the host contoller device\n", __func__);
81 platform_device_put(cpcap->pdev);
84 void cpcap_stop_host(struct cpcap_otg_data *cpcap)
87 platform_device_unregister(cpcap->pdev);
92 static int cpcap_otg_notify(struct notifier_block *nb, unsigned long event,
95 struct cpcap_otg_data *cpcap;
96 struct otg_transceiver *otg;
97 enum usb_otg_state from;
98 enum usb_otg_state to;
102 cpcap = container_of(nb, struct cpcap_otg_data, nb);
106 if (event == USB_EVENT_VBUS)
107 to = OTG_STATE_B_PERIPHERAL;
108 else if (event == USB_EVENT_ID)
109 to = OTG_STATE_A_HOST;
111 to = OTG_STATE_A_SUSPEND;
117 dev_info(cpcap->otg.dev, "%s --> %s", cpcap_state_name(from),
118 cpcap_state_name(to));
120 clk_enable(cpcap->clk);
122 if ((to == OTG_STATE_A_HOST) && (from == OTG_STATE_A_SUSPEND)
124 hcd = (struct usb_hcd *)otg->host;
126 val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
127 val &= ~TEGRA_ID_SW_VALUE;
128 writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
130 cpcap_start_host(cpcap);
132 } else if ((to == OTG_STATE_A_SUSPEND) && (from == OTG_STATE_A_HOST)
134 val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
135 val |= TEGRA_ID_SW_VALUE;
136 writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
138 cpcap_stop_host(cpcap);
140 } else if ((to == OTG_STATE_B_PERIPHERAL)
141 && (from == OTG_STATE_A_SUSPEND)
143 val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
144 val |= TEGRA_VBUS_WAKEUP_SW_VALUE;
145 writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
147 usb_gadget_vbus_connect(otg->gadget);
149 } else if ((to == OTG_STATE_A_SUSPEND)
150 && (from == OTG_STATE_B_PERIPHERAL)
152 val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
153 val &= ~TEGRA_VBUS_WAKEUP_SW_VALUE;
154 writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
156 usb_gadget_vbus_disconnect(otg->gadget);
159 clk_disable(cpcap->clk);
164 static int cpcap_otg_set_peripheral(struct otg_transceiver *otg,
165 struct usb_gadget *gadget)
167 otg->gadget = gadget;
171 static int cpcap_otg_set_host(struct otg_transceiver *otg,
172 struct usb_bus *host)
178 static int cpcap_otg_set_power(struct otg_transceiver *otg, unsigned mA)
183 static int cpcap_otg_set_suspend(struct otg_transceiver *otg, int suspend)
188 static int cpcap_otg_probe(struct platform_device *pdev)
190 struct cpcap_otg_data *cpcap;
191 struct resource *res;
195 cpcap = kzalloc(sizeof(struct cpcap_otg_data), GFP_KERNEL);
199 cpcap->otg.dev = &pdev->dev;
200 cpcap->otg.label = "cpcap-otg";
201 cpcap->otg.state = OTG_STATE_UNDEFINED;
202 cpcap->otg.set_host = cpcap_otg_set_host;
203 cpcap->otg.set_peripheral = cpcap_otg_set_peripheral;
204 cpcap->otg.set_suspend = cpcap_otg_set_suspend;
205 cpcap->otg.set_power = cpcap_otg_set_power;
206 cpcap->host = pdev->dev.platform_data;
208 platform_set_drvdata(pdev, cpcap);
210 cpcap->clk = clk_get(&pdev->dev, NULL);
211 if (IS_ERR(cpcap->clk)) {
212 dev_err(&pdev->dev, "Can't get otg clock\n");
213 err = PTR_ERR(cpcap->clk);
217 err = clk_enable(cpcap->clk);
221 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
223 dev_err(&pdev->dev, "Failed to get I/O memory\n");
227 cpcap->regs = ioremap(res->start, resource_size(res));
233 val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
234 val |= TEGRA_VBUS_WAKEUP_SW_ENABLE | TEGRA_ID_SW_ENABLE;
235 val |= TEGRA_ID_SW_VALUE;
236 val &= ~(TEGRA_VBUS_WAKEUP_SW_VALUE);
237 writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
239 clk_disable(cpcap->clk);
240 cpcap->otg.state = OTG_STATE_A_SUSPEND;
242 BLOCKING_INIT_NOTIFIER_HEAD(&cpcap->otg.notifier);
243 cpcap->nb.notifier_call = cpcap_otg_notify;
244 otg_register_notifier(&cpcap->otg, &cpcap->nb);
246 err = otg_set_transceiver(&cpcap->otg);
248 dev_err(&pdev->dev, "can't register transceiver (%d)\n", err);
255 iounmap(cpcap->regs);
257 clk_disable(cpcap->clk);
261 platform_set_drvdata(pdev, NULL);
266 static int __exit cpcap_otg_remove(struct platform_device *pdev)
268 struct cpcap_otg_data *cpcap = platform_get_drvdata(pdev);
270 otg_set_transceiver(NULL);
271 iounmap(cpcap->regs);
272 clk_disable(cpcap->clk);
274 platform_set_drvdata(pdev, NULL);
280 static struct platform_driver cpcap_otg_driver = {
284 .remove = __exit_p(cpcap_otg_remove),
285 .probe = cpcap_otg_probe,
288 static int __init cpcap_otg_init(void)
290 return platform_driver_register(&cpcap_otg_driver);
292 module_init(cpcap_otg_init);
294 static void __exit cpcap_otg_exit(void)
296 platform_driver_unregister(&cpcap_otg_driver);
298 module_exit(cpcap_otg_exit);