Date: | 2013-05-21 22:56:12 (10 years 4 months ago) |
---|---|
Author: | Apelete Seketeli |
Commit: | 03232dd185dd23d49a8e658a46172ea0c16d9808 |
Message: | usb: musb: add support for JZ4740 usb device controller Add support for Ingenic JZ4740 USB Device Controller through a specific musb glue layer. The platform data already available in tree for that USB Device Controller was previously used by an out-of-tree USB gadget driver which was not relying on the musb driver and was written by Ingenic and the Qi-Hardware community. JZ4740 UDC not being OTG compatible and missing some hardware registers, this musb glue layer is written from scratch to be used in gadget mode only and take silicon design specifics into account. Signed-off-by: Apelete Seketeli <apelete@seketeli.net> |
Files: |
arch/mips/include/asm/mach-jz4740/platform.h (1 diff) arch/mips/jz4740/board-qi_lb60.c (1 diff) arch/mips/jz4740/platform.c (2 diffs) drivers/usb/musb/Kconfig (2 diffs) drivers/usb/musb/Makefile (1 diff) drivers/usb/musb/jz4740.c (1 diff) drivers/usb/musb/musb_core.c (3 diffs) |
Change Details
arch/mips/include/asm/mach-jz4740/platform.h | ||
---|---|---|
21 | 21 | |
22 | 22 | extern struct platform_device jz4740_usb_ohci_device; |
23 | 23 | extern struct platform_device jz4740_udc_device; |
24 | extern struct platform_device jz4740_udc_xceiv_device; | |
24 | 25 | extern struct platform_device jz4740_mmc_device; |
25 | 26 | extern struct platform_device jz4740_rtc_device; |
26 | 27 | extern struct platform_device jz4740_i2c_device; |
arch/mips/jz4740/board-qi_lb60.c | ||
---|---|---|
454 | 454 | |
455 | 455 | static struct platform_device *jz_platform_devices[] __initdata = { |
456 | 456 | &jz4740_udc_device, |
457 | &jz4740_udc_xceiv_device, | |
457 | 458 | &jz4740_mmc_device, |
458 | 459 | &jz4740_nand_device, |
459 | 460 | &qi_lb60_keypad, |
arch/mips/jz4740/platform.c | ||
---|---|---|
21 | 21 | |
22 | 22 | #include <linux/dma-mapping.h> |
23 | 23 | |
24 | #include <linux/usb/musb.h> | |
25 | ||
24 | 26 | #include <asm/mach-jz4740/platform.h> |
25 | 27 | #include <asm/mach-jz4740/base.h> |
26 | 28 | #include <asm/mach-jz4740/irq.h> |
... | ... | |
56 | 58 | .resource = jz4740_usb_ohci_resources, |
57 | 59 | }; |
58 | 60 | |
59 | /* UDC (USB gadget controller) */ | |
60 | static struct resource jz4740_usb_gdt_resources[] = { | |
61 | { | |
62 | .start = JZ4740_UDC_BASE_ADDR, | |
63 | .end = JZ4740_UDC_BASE_ADDR + 0x1000 - 1, | |
64 | .flags = IORESOURCE_MEM, | |
61 | /* USB Device Controller */ | |
62 | struct platform_device jz4740_udc_xceiv_device = { | |
63 | .name = "usb_phy_gen_xceiv", | |
64 | .id = 0, | |
65 | }; | |
66 | ||
67 | static struct musb_hdrc_config jz4740_udc_config = { | |
68 | /* Silicon does not implement USB OTG. */ | |
69 | .multipoint = 0, | |
70 | /* Max EPs scanned, driver will decide which EP can be used. */ | |
71 | .num_eps = 4, | |
72 | /* RAMbits needed to configure EPs from table */ | |
73 | .ram_bits = 9, | |
74 | }; | |
75 | ||
76 | static struct musb_hdrc_platform_data jz4740_udc_platform_data = { | |
77 | .mode = MUSB_PERIPHERAL, | |
78 | .config = &jz4740_udc_config, | |
79 | }; | |
80 | ||
81 | static struct resource jz4740_udc_resources[] = { | |
82 | [0] = { | |
83 | .start = JZ4740_UDC_BASE_ADDR, | |
84 | .end = JZ4740_UDC_BASE_ADDR + 0x10000 - 1, | |
85 | .flags = IORESOURCE_MEM, | |
65 | 86 | }, |
66 | { | |
67 | .start = JZ4740_IRQ_UDC, | |
68 | .end = JZ4740_IRQ_UDC, | |
69 | .flags = IORESOURCE_IRQ, | |
87 | [1] = { | |
88 | .start = JZ4740_IRQ_UDC, | |
89 | .end = JZ4740_IRQ_UDC, | |
90 | .flags = IORESOURCE_IRQ, | |
91 | .name = "mc", | |
70 | 92 | }, |
71 | 93 | }; |
72 | 94 | |
73 | 95 | struct platform_device jz4740_udc_device = { |
74 | .name = "jz-udc", | |
75 | .id = -1, | |
76 | .dev = { | |
77 | .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, | |
96 | .name = "musb-jz4740", | |
97 | .id = -1, | |
98 | .dev = { | |
99 | .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, | |
78 | 100 | .coherent_dma_mask = DMA_BIT_MASK(32), |
101 | .platform_data = &jz4740_udc_platform_data, | |
79 | 102 | }, |
80 | .num_resources = ARRAY_SIZE(jz4740_usb_gdt_resources), | |
81 | .resource = jz4740_usb_gdt_resources, | |
103 | .num_resources = ARRAY_SIZE(jz4740_udc_resources), | |
104 | .resource = jz4740_udc_resources, | |
82 | 105 | }; |
83 | 106 | |
84 | 107 | /* MMC/SD controller */ |
drivers/usb/musb/Kconfig | ||
---|---|---|
92 | 92 | config USB_MUSB_UX500 |
93 | 93 | tristate "U8500 and U5500" |
94 | 94 | |
95 | config USB_MUSB_JZ4740 | |
96 | tristate "JZ4740" | |
97 | depends on MACH_JZ4740 | |
98 | depends on USB_MUSB_GADGET | |
99 | depends on USB_OTG_BLACKLIST_HUB | |
100 | ||
95 | 101 | endchoice |
96 | 102 | |
97 | 103 | config USB_MUSB_AM335X_CHILD |
... | ... | |
99 | 105 | |
100 | 106 | choice |
101 | 107 | prompt 'MUSB DMA mode' |
102 | default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM | |
108 | default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740 | |
103 | 109 | default USB_UX500_DMA if USB_MUSB_UX500 |
104 | 110 | default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN |
105 | 111 | default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI |
drivers/usb/musb/Makefile | ||
---|---|---|
19 | 19 | obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o |
20 | 20 | obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o |
21 | 21 | obj-$(CONFIG_USB_MUSB_UX500) += ux500.o |
22 | obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o | |
22 | 23 | |
23 | 24 | |
24 | 25 | obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o |
drivers/usb/musb/jz4740.c | ||
---|---|---|
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 int jz4740_musb_init(struct musb *musb) | |
89 | { | |
90 | musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); | |
91 | if (!musb->xceiv) { | |
92 | pr_err("HS UDC: no transceiver configured\n"); | |
93 | return -ENODEV; | |
94 | } | |
95 | ||
96 | /* Silicon does not implement ConfigData register. | |
97 | * Set dyn_fifo to avoid reading EP config from hardware. | |
98 | */ | |
99 | musb->dyn_fifo = true; | |
100 | ||
101 | musb->isr = jz4740_musb_interrupt; | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
106 | static int jz4740_musb_exit(struct musb *musb) | |
107 | { | |
108 | usb_put_phy(musb->xceiv); | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static const struct musb_platform_ops jz4740_musb_ops = { | |
114 | .init = jz4740_musb_init, | |
115 | .exit = jz4740_musb_exit, | |
116 | ||
117 | .set_vbus = jz4740_musb_set_vbus, | |
118 | }; | |
119 | ||
120 | static int jz4740_probe(struct platform_device *pdev) | |
121 | { | |
122 | struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; | |
123 | struct platform_device *musb; | |
124 | struct jz4740_glue *glue; | |
125 | struct clk *clk; | |
126 | ||
127 | int ret = -ENOMEM; | |
128 | ||
129 | if (!pdata) { | |
130 | dev_err(&pdev->dev, "failed to allocate platform data\n"); | |
131 | goto err0; | |
132 | } | |
133 | ||
134 | glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); | |
135 | if (!glue) { | |
136 | dev_err(&pdev->dev, "failed to allocate glue context\n"); | |
137 | goto err0; | |
138 | } | |
139 | ||
140 | musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); | |
141 | if (!musb) { | |
142 | dev_err(&pdev->dev, "failed to allocate musb device\n"); | |
143 | goto err1; | |
144 | } | |
145 | ||
146 | clk = devm_clk_get(&pdev->dev, "udc"); | |
147 | if (IS_ERR(clk)) { | |
148 | dev_err(&pdev->dev, "failed to get clock\n"); | |
149 | ret = PTR_ERR(clk); | |
150 | goto err2; | |
151 | } | |
152 | ||
153 | ret = clk_prepare_enable(clk); | |
154 | if (ret) { | |
155 | dev_err(&pdev->dev, "failed to enable clock\n"); | |
156 | goto err3; | |
157 | } | |
158 | ||
159 | musb->dev.parent = &pdev->dev; | |
160 | ||
161 | glue->dev = &pdev->dev; | |
162 | glue->musb = musb; | |
163 | glue->clk = clk; | |
164 | ||
165 | pdata->platform_ops = &jz4740_musb_ops; | |
166 | ||
167 | platform_set_drvdata(pdev, glue); | |
168 | ||
169 | ret = platform_device_add_resources(musb, pdev->resource, | |
170 | pdev->num_resources); | |
171 | if (ret) { | |
172 | dev_err(&pdev->dev, "failed to add resources\n"); | |
173 | goto err4; | |
174 | } | |
175 | ||
176 | ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); | |
177 | if (ret) { | |
178 | dev_err(&pdev->dev, "failed to add platform_data\n"); | |
179 | goto err4; | |
180 | } | |
181 | ||
182 | ret = platform_device_add(musb); | |
183 | if (ret) { | |
184 | dev_err(&pdev->dev, "failed to register musb device\n"); | |
185 | goto err4; | |
186 | } | |
187 | ||
188 | return 0; | |
189 | ||
190 | err4: | |
191 | clk_disable_unprepare(clk); | |
192 | ||
193 | err3: | |
194 | devm_clk_put(&pdev->dev, clk); | |
195 | ||
196 | err2: | |
197 | platform_device_put(musb); | |
198 | ||
199 | err1: | |
200 | devm_kfree(&pdev->dev, glue); | |
201 | ||
202 | err0: | |
203 | return ret; | |
204 | } | |
205 | ||
206 | static int jz4740_remove(struct platform_device *pdev) | |
207 | { | |
208 | struct jz4740_glue *glue = platform_get_drvdata(pdev); | |
209 | ||
210 | platform_device_unregister(glue->musb); | |
211 | clk_disable_unprepare(glue->clk); | |
212 | clk_put(glue->clk); | |
213 | devm_kfree(&pdev->dev, glue); | |
214 | ||
215 | return 0; | |
216 | } | |
217 | ||
218 | static struct platform_driver jz4740_driver = { | |
219 | .probe = jz4740_probe, | |
220 | .remove = jz4740_remove, | |
221 | .driver = { | |
222 | .name = "musb-jz4740", | |
223 | }, | |
224 | }; | |
225 | ||
226 | MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer"); | |
227 | MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>"); | |
228 | MODULE_LICENSE("GPL v2"); | |
229 | module_platform_driver(jz4740_driver); |
drivers/usb/musb/musb_core.c | ||
---|---|---|
1038 | 1038 | #elif defined(CONFIG_USB_MUSB_UX500) \ |
1039 | 1039 | || defined(CONFIG_USB_MUSB_UX500_MODULE) |
1040 | 1040 | static ushort fifo_mode = 5; |
1041 | #elif defined(CONFIG_USB_MUSB_JZ4740) \ | |
1042 | || defined(CONFIG_USB_MUSB_JZ4740_MODULE) | |
1043 | static ushort fifo_mode = 6; | |
1041 | 1044 | #else |
1042 | 1045 | static ushort fifo_mode = 2; |
1043 | 1046 | #endif |
... | ... | |
1151 | 1154 | { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, |
1152 | 1155 | }; |
1153 | 1156 | |
1157 | /* mode 6 - fits in 2KB */ | |
1158 | static struct musb_fifo_cfg mode_6_cfg[] = { | |
1159 | { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, | |
1160 | { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, | |
1161 | { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, | |
1162 | }; | |
1163 | ||
1154 | 1164 | /* |
1155 | 1165 | * configure a fifo; for non-shared endpoints, this may be called |
1156 | 1166 | * once for a tx fifo and once for an rx fifo. |
... | ... | |
1273 | 1283 | cfg = mode_5_cfg; |
1274 | 1284 | n = ARRAY_SIZE(mode_5_cfg); |
1275 | 1285 | break; |
1286 | case 6: | |
1287 | cfg = mode_6_cfg; | |
1288 | n = ARRAY_SIZE(mode_6_cfg); | |
1289 | break; | |
1276 | 1290 | } |
1277 | 1291 | |
1278 | 1292 | printk(KERN_DEBUG "%s: setup fifo_mode %d\n", |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
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