Root/
Source at commit 65b33a24c1039156c0f4c0f0dbe043a41ce5a177 created 9 years 11 months ago. By Lars-Peter Clausen, usb: musb-jz4740: Move musb_hdrc_config to the glue driver | |
---|---|
1 | /* |
2 | * Ingenic JZ4740 "glue layer" |
3 | * |
4 | * Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net> |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * You should have received a copy of the GNU General Public License along |
12 | * with this program; if not, write to the Free Software Foundation, Inc., |
13 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
14 | */ |
15 | |
16 | #include <linux/clk.h> |
17 | #include <linux/dma-mapping.h> |
18 | #include <linux/errno.h> |
19 | #include <linux/kernel.h> |
20 | #include <linux/module.h> |
21 | #include <linux/platform_device.h> |
22 | |
23 | #include "musb_core.h" |
24 | |
25 | struct jz4740_glue { |
26 | struct device *dev; |
27 | struct platform_device *musb; |
28 | struct clk *clk; |
29 | }; |
30 | |
31 | static void jz4740_musb_set_vbus(struct musb *musb, int is_on) |
32 | { |
33 | u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); |
34 | |
35 | /* HDRC controls CPEN, but beware current surges during device |
36 | * connect. They can trigger transient overcurrent conditions |
37 | * that must be ignored. |
38 | */ |
39 | |
40 | if (is_on) { |
41 | musb->is_active = 1; |
42 | musb->xceiv->otg->default_a = 1; |
43 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; |
44 | devctl |= MUSB_DEVCTL_SESSION; |
45 | |
46 | MUSB_HST_MODE(musb); |
47 | } else { |
48 | musb->is_active = 0; |
49 | |
50 | /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and |
51 | * jumping right to B_IDLE... |
52 | */ |
53 | |
54 | musb->xceiv->otg->default_a = 0; |
55 | musb->xceiv->state = OTG_STATE_B_IDLE; |
56 | devctl &= ~MUSB_DEVCTL_SESSION; |
57 | |
58 | MUSB_DEV_MODE(musb); |
59 | } |
60 | musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); |
61 | |
62 | dev_dbg(musb->xceiv->dev, "VBUS %s, devctl %02x " |
63 | /* otg %3x conf %08x prcm %08x */ "\n", |
64 | usb_otg_state_string(musb->xceiv->state), |
65 | musb_readb(musb->mregs, MUSB_DEVCTL)); |
66 | } |
67 | |
68 | static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) |
69 | { |
70 | unsigned long flags; |
71 | irqreturn_t retval = IRQ_NONE; |
72 | struct musb *musb = __hci; |
73 | |
74 | spin_lock_irqsave(&musb->lock, flags); |
75 | |
76 | musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); |
77 | musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); |
78 | musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); |
79 | |
80 | if (musb->int_usb || musb->int_tx || musb->int_rx) |
81 | retval = musb_interrupt(musb); |
82 | |
83 | spin_unlock_irqrestore(&musb->lock, flags); |
84 | |
85 | return retval; |
86 | } |
87 | |
88 | static struct musb_hdrc_config jz4740_musb_config = { |
89 | /* Silicon does not implement USB OTG. */ |
90 | .multipoint = 0, |
91 | /* Max EPs scanned, driver will decide which EP can be used. */ |
92 | .num_eps = 4, |
93 | /* RAMbits needed to configure EPs from table */ |
94 | .ram_bits = 9, |
95 | }; |
96 | |
97 | static struct musb_hdrc_platform_data jz4740_musb_platform_data = { |
98 | .mode = MUSB_PERIPHERAL, |
99 | .config = &jz4740_musb_config, |
100 | }; |
101 | |
102 | static int jz4740_musb_init(struct musb *musb) |
103 | { |
104 | musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); |
105 | if (!musb->xceiv) { |
106 | pr_err("HS UDC: no transceiver configured\n"); |
107 | return -ENODEV; |
108 | } |
109 | |
110 | /* Silicon does not implement ConfigData register. |
111 | * Set dyn_fifo to avoid reading EP config from hardware. |
112 | */ |
113 | musb->dyn_fifo = true; |
114 | |
115 | musb->isr = jz4740_musb_interrupt; |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | static int jz4740_musb_exit(struct musb *musb) |
121 | { |
122 | usb_put_phy(musb->xceiv); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | static const struct musb_platform_ops jz4740_musb_ops = { |
128 | .init = jz4740_musb_init, |
129 | .exit = jz4740_musb_exit, |
130 | |
131 | .set_vbus = jz4740_musb_set_vbus, |
132 | }; |
133 | |
134 | static int jz4740_probe(struct platform_device *pdev) |
135 | { |
136 | struct musb_hdrc_platform_data *pdata = &jz4740_musb_platform_data; |
137 | struct platform_device *musb; |
138 | struct jz4740_glue *glue; |
139 | struct clk *clk; |
140 | int ret; |
141 | |
142 | glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); |
143 | if (!glue) |
144 | return -ENOMEM; |
145 | |
146 | musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); |
147 | if (!musb) { |
148 | dev_err(&pdev->dev, "failed to allocate musb device\n"); |
149 | return -ENOMEM; |
150 | } |
151 | |
152 | clk = devm_clk_get(&pdev->dev, "udc"); |
153 | if (IS_ERR(clk)) { |
154 | dev_err(&pdev->dev, "failed to get clock\n"); |
155 | ret = PTR_ERR(clk); |
156 | goto err_platform_device_put; |
157 | } |
158 | |
159 | ret = clk_prepare_enable(clk); |
160 | if (ret) { |
161 | dev_err(&pdev->dev, "failed to enable clock\n"); |
162 | goto err_platform_device_put; |
163 | } |
164 | |
165 | musb->dev.parent = &pdev->dev; |
166 | |
167 | glue->dev = &pdev->dev; |
168 | glue->musb = musb; |
169 | glue->clk = clk; |
170 | |
171 | pdata->platform_ops = &jz4740_musb_ops; |
172 | |
173 | platform_set_drvdata(pdev, glue); |
174 | |
175 | ret = platform_device_add_resources(musb, pdev->resource, |
176 | pdev->num_resources); |
177 | if (ret) { |
178 | dev_err(&pdev->dev, "failed to add resources\n"); |
179 | goto err_clk_disable; |
180 | } |
181 | |
182 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); |
183 | if (ret) { |
184 | dev_err(&pdev->dev, "failed to add platform_data\n"); |
185 | goto err_clk_disable; |
186 | } |
187 | |
188 | ret = platform_device_add(musb); |
189 | if (ret) { |
190 | dev_err(&pdev->dev, "failed to register musb device\n"); |
191 | goto err_clk_disable; |
192 | } |
193 | |
194 | return 0; |
195 | |
196 | err_clk_disable: |
197 | clk_disable_unprepare(clk); |
198 | err_platform_device_put: |
199 | platform_device_put(musb); |
200 | return ret; |
201 | } |
202 | |
203 | static int jz4740_remove(struct platform_device *pdev) |
204 | { |
205 | struct jz4740_glue *glue = platform_get_drvdata(pdev); |
206 | |
207 | platform_device_unregister(glue->musb); |
208 | clk_disable_unprepare(glue->clk); |
209 | |
210 | return 0; |
211 | } |
212 | |
213 | static struct platform_driver jz4740_driver = { |
214 | .probe = jz4740_probe, |
215 | .remove = jz4740_remove, |
216 | .driver = { |
217 | .name = "musb-jz4740", |
218 | }, |
219 | }; |
220 | |
221 | MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer"); |
222 | MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>"); |
223 | MODULE_LICENSE("GPL v2"); |
224 | module_platform_driver(jz4740_driver); |
225 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9