aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/fsl_tegra_udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/fsl_tegra_udc.c')
-rw-r--r--drivers/usb/gadget/fsl_tegra_udc.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c
new file mode 100644
index 00000000000..b254258726f
--- /dev/null
+++ b/drivers/usb/gadget/fsl_tegra_udc.c
@@ -0,0 +1,155 @@
1/*
2 * Description:
3 * Helper functions to support the tegra USB controller
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10#include <linux/fsl_devices.h>
11#include <linux/platform_device.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <mach/usb_phy.h>
15
16static struct tegra_usb_phy *phy;
17static struct clk *udc_clk;
18static struct clk *emc_clk;
19static struct clk *sclk_clk;
20static void *udc_base;
21
22int fsl_udc_clk_init(struct platform_device *pdev)
23{
24 struct resource *res;
25 int err;
26 int instance;
27 struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
28
29
30 udc_clk = clk_get(&pdev->dev, NULL);
31 if (IS_ERR(udc_clk)) {
32 dev_err(&pdev->dev, "Can't get udc clock\n");
33 return PTR_ERR(udc_clk);
34 }
35
36 clk_enable(udc_clk);
37
38 sclk_clk = clk_get(&pdev->dev, "sclk");
39 if (IS_ERR(sclk_clk)) {
40 dev_err(&pdev->dev, "Can't get sclk clock\n");
41 err = PTR_ERR(sclk_clk);
42 goto err_sclk;
43 }
44
45 clk_set_rate(sclk_clk, 80000000);
46 clk_enable(sclk_clk);
47
48 emc_clk = clk_get(&pdev->dev, "emc");
49 if (IS_ERR(emc_clk)) {
50 dev_err(&pdev->dev, "Can't get emc clock\n");
51 err = PTR_ERR(emc_clk);
52 goto err_emc;
53 }
54
55 clk_enable(emc_clk);
56#ifdef CONFIG_ARCH_TEGRA_2x_SOC
57 /* Set DDR busy hints to 150MHz. For Tegra 2x SOC, DDR rate is half of EMC rate */
58 clk_set_rate(emc_clk, 300000000);
59#else
60 /* Set DDR busy hints to 100MHz. For Tegra 3x SOC DDR rate equals to EMC rate */
61 clk_set_rate(emc_clk, 100000000);
62#endif
63
64 /* we have to remap the registers ourselves as fsl_udc does not
65 * export them for us.
66 */
67 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68 if (!res) {
69 err = -ENXIO;
70 goto err0;
71 }
72 udc_base = ioremap(res->start, resource_size(res));
73 if (!udc_base) {
74 err = -ENOMEM;
75 goto err0;
76 }
77
78 instance = pdev->id;
79 if (instance == -1)
80 instance = 0;
81
82 phy = tegra_usb_phy_open(instance, udc_base, pdata->phy_config,
83 TEGRA_USB_PHY_MODE_DEVICE, pdata->usb_phy_type);
84 if (IS_ERR(phy)) {
85 dev_err(&pdev->dev, "Can't open phy\n");
86 err = PTR_ERR(phy);
87 goto err1;
88 }
89 tegra_usb_phy_power_on(phy, true);
90
91 return 0;
92err1:
93 iounmap(udc_base);
94err0:
95 clk_disable(emc_clk);
96 clk_put(emc_clk);
97err_emc:
98 clk_disable(sclk_clk);
99 clk_put(sclk_clk);
100err_sclk:
101 clk_disable(udc_clk);
102 clk_put(udc_clk);
103 return err;
104}
105
106void fsl_udc_clk_finalize(struct platform_device *pdev)
107{
108}
109
110void fsl_udc_clk_release(void)
111{
112 tegra_usb_phy_close(phy);
113
114 iounmap(udc_base);
115
116 clk_disable(udc_clk);
117 clk_put(udc_clk);
118
119 clk_disable(sclk_clk);
120 clk_put(sclk_clk);
121
122 clk_disable(emc_clk);
123 clk_put(emc_clk);
124}
125
126void fsl_udc_clk_suspend(bool is_dpd)
127{
128 tegra_usb_phy_power_off(phy, is_dpd);
129 clk_disable(udc_clk);
130 clk_disable(sclk_clk);
131 clk_disable(emc_clk);
132}
133
134void fsl_udc_clk_resume(bool is_dpd)
135{
136 clk_enable(emc_clk);
137 clk_enable(sclk_clk);
138 clk_enable(udc_clk);
139 tegra_usb_phy_power_on(phy, is_dpd);
140}
141
142void fsl_udc_clk_enable(void)
143{
144 clk_enable(udc_clk);
145}
146
147void fsl_udc_clk_disable(void)
148{
149 clk_disable(udc_clk);
150}
151
152bool fsl_udc_charger_detect(void)
153{
154 return tegra_usb_phy_charger_detect(phy);
155}