Date:2013-05-21 22:56:12 (1 year 5 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
2121
2222extern struct platform_device jz4740_usb_ohci_device;
2323extern struct platform_device jz4740_udc_device;
24extern struct platform_device jz4740_udc_xceiv_device;
2425extern struct platform_device jz4740_mmc_device;
2526extern struct platform_device jz4740_rtc_device;
2627extern struct platform_device jz4740_i2c_device;
arch/mips/jz4740/board-qi_lb60.c
454454
455455static struct platform_device *jz_platform_devices[] __initdata = {
456456    &jz4740_udc_device,
457    &jz4740_udc_xceiv_device,
457458    &jz4740_mmc_device,
458459    &jz4740_nand_device,
459460    &qi_lb60_keypad,
arch/mips/jz4740/platform.c
2121
2222#include <linux/dma-mapping.h>
2323
24#include <linux/usb/musb.h>
25
2426#include <asm/mach-jz4740/platform.h>
2527#include <asm/mach-jz4740/base.h>
2628#include <asm/mach-jz4740/irq.h>
...... 
5658    .resource = jz4740_usb_ohci_resources,
5759};
5860
59/* UDC (USB gadget controller) */
60static 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 */
62struct platform_device jz4740_udc_xceiv_device = {
63    .name = "usb_phy_gen_xceiv",
64    .id = 0,
65};
66
67static 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
76static struct musb_hdrc_platform_data jz4740_udc_platform_data = {
77    .mode = MUSB_PERIPHERAL,
78    .config = &jz4740_udc_config,
79};
80
81static 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,
6586    },
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",
7092    },
7193};
7294
7395struct 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,
78100        .coherent_dma_mask = DMA_BIT_MASK(32),
101        .platform_data = &jz4740_udc_platform_data,
79102    },
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,
82105};
83106
84107/* MMC/SD controller */
drivers/usb/musb/Kconfig
9292config USB_MUSB_UX500
9393    tristate "U8500 and U5500"
9494
95config 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
95101endchoice
96102
97103config USB_MUSB_AM335X_CHILD
...... 
99105
100106choice
101107    prompt 'MUSB DMA mode'
102    default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
108    default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740
103109    default USB_UX500_DMA if USB_MUSB_UX500
104110    default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
105111    default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
drivers/usb/musb/Makefile
1919obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
2020obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
2121obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
22obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o
2223
2324
2425obj-$(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
25struct jz4740_glue {
26    struct device *dev;
27    struct platform_device *musb;
28    struct clk *clk;
29};
30
31static 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
68static 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
88static 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
106static int jz4740_musb_exit(struct musb *musb)
107{
108    usb_put_phy(musb->xceiv);
109
110    return 0;
111}
112
113static 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
120static 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
190err4:
191    clk_disable_unprepare(clk);
192
193err3:
194    devm_clk_put(&pdev->dev, clk);
195
196err2:
197    platform_device_put(musb);
198
199err1:
200    devm_kfree(&pdev->dev, glue);
201
202err0:
203    return ret;
204}
205
206static 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
218static struct platform_driver jz4740_driver = {
219    .probe = jz4740_probe,
220    .remove = jz4740_remove,
221    .driver = {
222        .name = "musb-jz4740",
223    },
224};
225
226MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer");
227MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>");
228MODULE_LICENSE("GPL v2");
229module_platform_driver(jz4740_driver);
drivers/usb/musb/musb_core.c
10381038#elif defined(CONFIG_USB_MUSB_UX500) \
10391039    || defined(CONFIG_USB_MUSB_UX500_MODULE)
10401040static ushort fifo_mode = 5;
1041#elif defined(CONFIG_USB_MUSB_JZ4740) \
1042    || defined(CONFIG_USB_MUSB_JZ4740_MODULE)
1043static ushort fifo_mode = 6;
10411044#else
10421045static ushort fifo_mode = 2;
10431046#endif
...... 
11511154{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
11521155};
11531156
1157/* mode 6 - fits in 2KB */
1158static 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
11541164/*
11551165 * configure a fifo; for non-shared endpoints, this may be called
11561166 * once for a tx fifo and once for an rx fifo.
...... 
12731283        cfg = mode_5_cfg;
12741284        n = ARRAY_SIZE(mode_5_cfg);
12751285        break;
1286    case 6:
1287        cfg = mode_6_cfg;
1288        n = ARRAY_SIZE(mode_6_cfg);
1289        break;
12761290    }
12771291
12781292    printk(KERN_DEBUG "%s: setup fifo_mode %d\n",

Archive Download the corresponding diff file



interactive