1 // SPDX-License-Identifier: GPL-2.0+
3 * Ingenic JZ4740 "glue layer"
5 * Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net>
9 #include <linux/dma-mapping.h>
10 #include <linux/errno.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of_device.h>
14 #include <linux/platform_device.h>
15 #include <linux/usb/role.h>
16 #include <linux/usb/usb_phy_generic.h>
18 #include "musb_core.h"
21 struct platform_device
*pdev
;
24 struct usb_role_switch
*role_sw
;
27 static irqreturn_t
jz4740_musb_interrupt(int irq
, void *__hci
)
30 irqreturn_t retval
= IRQ_NONE
, retval_dma
= IRQ_NONE
;
31 struct musb
*musb
= __hci
;
33 if (IS_ENABLED(CONFIG_USB_INVENTRA_DMA
) && musb
->dma_controller
)
34 retval_dma
= dma_controller_irq(irq
, musb
->dma_controller
);
36 spin_lock_irqsave(&musb
->lock
, flags
);
38 musb
->int_usb
= musb_readb(musb
->mregs
, MUSB_INTRUSB
);
39 musb
->int_tx
= musb_readw(musb
->mregs
, MUSB_INTRTX
);
40 musb
->int_rx
= musb_readw(musb
->mregs
, MUSB_INTRRX
);
43 * The controller is gadget only, the state of the host mode IRQ bits is
44 * undefined. Mask them to make sure that the musb driver core will
47 musb
->int_usb
&= MUSB_INTR_SUSPEND
| MUSB_INTR_RESUME
|
48 MUSB_INTR_RESET
| MUSB_INTR_SOF
;
50 if (musb
->int_usb
|| musb
->int_tx
|| musb
->int_rx
)
51 retval
= musb_interrupt(musb
);
53 spin_unlock_irqrestore(&musb
->lock
, flags
);
55 if (retval
== IRQ_HANDLED
|| retval_dma
== IRQ_HANDLED
)
61 static struct musb_fifo_cfg jz4740_musb_fifo_cfg
[] = {
62 { .hw_ep_num
= 1, .style
= FIFO_TX
, .maxpacket
= 512, },
63 { .hw_ep_num
= 1, .style
= FIFO_RX
, .maxpacket
= 512, },
64 { .hw_ep_num
= 2, .style
= FIFO_TX
, .maxpacket
= 64, },
67 static const struct musb_hdrc_config jz4740_musb_config
= {
68 /* Silicon does not implement USB OTG. */
70 /* Max EPs scanned, driver will decide which EP can be used. */
72 /* RAMbits needed to configure EPs from table */
74 .fifo_cfg
= jz4740_musb_fifo_cfg
,
75 .fifo_cfg_size
= ARRAY_SIZE(jz4740_musb_fifo_cfg
),
78 static int jz4740_musb_role_switch_set(struct usb_role_switch
*sw
,
81 struct jz4740_glue
*glue
= usb_role_switch_get_drvdata(sw
);
82 struct usb_phy
*phy
= glue
->musb
->xceiv
;
86 atomic_notifier_call_chain(&phy
->notifier
, USB_EVENT_NONE
, phy
);
89 atomic_notifier_call_chain(&phy
->notifier
, USB_EVENT_VBUS
, phy
);
92 atomic_notifier_call_chain(&phy
->notifier
, USB_EVENT_ID
, phy
);
99 static int jz4740_musb_init(struct musb
*musb
)
101 struct device
*dev
= musb
->controller
->parent
;
102 struct jz4740_glue
*glue
= dev_get_drvdata(dev
);
103 struct usb_role_switch_desc role_sw_desc
= {
104 .set
= jz4740_musb_role_switch_set
,
106 .fwnode
= dev_fwnode(dev
),
113 musb
->xceiv
= devm_usb_get_phy_by_phandle(dev
, "phys", 0);
115 musb
->xceiv
= devm_usb_get_phy(dev
, USB_PHY_TYPE_USB2
);
116 if (IS_ERR(musb
->xceiv
)) {
117 err
= PTR_ERR(musb
->xceiv
);
118 if (err
!= -EPROBE_DEFER
)
119 dev_err(dev
, "No transceiver configured: %d", err
);
123 glue
->role_sw
= usb_role_switch_register(dev
, &role_sw_desc
);
124 if (IS_ERR(glue
->role_sw
)) {
125 dev_err(dev
, "Failed to register USB role switch");
126 return PTR_ERR(glue
->role_sw
);
130 * Silicon does not implement ConfigData register.
131 * Set dyn_fifo to avoid reading EP config from hardware.
133 musb
->dyn_fifo
= true;
135 musb
->isr
= jz4740_musb_interrupt
;
140 static int jz4740_musb_exit(struct musb
*musb
)
142 struct jz4740_glue
*glue
= dev_get_drvdata(musb
->controller
->parent
);
144 usb_role_switch_unregister(glue
->role_sw
);
149 static const struct musb_platform_ops jz4740_musb_ops
= {
150 .quirks
= MUSB_DMA_INVENTRA
| MUSB_INDEXED_EP
,
152 .init
= jz4740_musb_init
,
153 .exit
= jz4740_musb_exit
,
154 #ifdef CONFIG_USB_INVENTRA_DMA
155 .dma_init
= musbhs_dma_controller_create_noirq
,
156 .dma_exit
= musbhs_dma_controller_destroy
,
160 static const struct musb_hdrc_platform_data jz4740_musb_pdata
= {
161 .mode
= MUSB_PERIPHERAL
,
162 .config
= &jz4740_musb_config
,
163 .platform_ops
= &jz4740_musb_ops
,
166 static struct musb_fifo_cfg jz4770_musb_fifo_cfg
[] = {
167 { .hw_ep_num
= 1, .style
= FIFO_TX
, .maxpacket
= 512, },
168 { .hw_ep_num
= 1, .style
= FIFO_RX
, .maxpacket
= 512, },
169 { .hw_ep_num
= 2, .style
= FIFO_TX
, .maxpacket
= 512, },
170 { .hw_ep_num
= 2, .style
= FIFO_RX
, .maxpacket
= 512, },
171 { .hw_ep_num
= 3, .style
= FIFO_TX
, .maxpacket
= 512, },
172 { .hw_ep_num
= 3, .style
= FIFO_RX
, .maxpacket
= 512, },
173 { .hw_ep_num
= 4, .style
= FIFO_TX
, .maxpacket
= 512, },
174 { .hw_ep_num
= 4, .style
= FIFO_RX
, .maxpacket
= 512, },
175 { .hw_ep_num
= 5, .style
= FIFO_TX
, .maxpacket
= 512, },
176 { .hw_ep_num
= 5, .style
= FIFO_RX
, .maxpacket
= 512, },
179 static struct musb_hdrc_config jz4770_musb_config
= {
183 .fifo_cfg
= jz4770_musb_fifo_cfg
,
184 .fifo_cfg_size
= ARRAY_SIZE(jz4770_musb_fifo_cfg
),
187 static const struct musb_hdrc_platform_data jz4770_musb_pdata
= {
188 .mode
= MUSB_PERIPHERAL
, /* TODO: support OTG */
189 .config
= &jz4770_musb_config
,
190 .platform_ops
= &jz4740_musb_ops
,
193 static int jz4740_probe(struct platform_device
*pdev
)
195 struct device
*dev
= &pdev
->dev
;
196 const struct musb_hdrc_platform_data
*pdata
;
197 struct platform_device
*musb
;
198 struct jz4740_glue
*glue
;
202 glue
= devm_kzalloc(dev
, sizeof(*glue
), GFP_KERNEL
);
206 pdata
= of_device_get_match_data(dev
);
208 dev_err(dev
, "missing platform data");
212 musb
= platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO
);
214 dev_err(dev
, "failed to allocate musb device");
218 clk
= devm_clk_get(dev
, "udc");
220 dev_err(dev
, "failed to get clock");
222 goto err_platform_device_put
;
225 ret
= clk_prepare_enable(clk
);
227 dev_err(dev
, "failed to enable clock");
228 goto err_platform_device_put
;
231 musb
->dev
.parent
= dev
;
232 musb
->dev
.dma_mask
= &musb
->dev
.coherent_dma_mask
;
233 musb
->dev
.coherent_dma_mask
= DMA_BIT_MASK(32);
238 platform_set_drvdata(pdev
, glue
);
240 ret
= platform_device_add_resources(musb
, pdev
->resource
,
241 pdev
->num_resources
);
243 dev_err(dev
, "failed to add resources");
244 goto err_clk_disable
;
247 ret
= platform_device_add_data(musb
, pdata
, sizeof(*pdata
));
249 dev_err(dev
, "failed to add platform_data");
250 goto err_clk_disable
;
253 ret
= platform_device_add(musb
);
255 dev_err(dev
, "failed to register musb device");
256 goto err_clk_disable
;
262 clk_disable_unprepare(clk
);
263 err_platform_device_put
:
264 platform_device_put(musb
);
268 static int jz4740_remove(struct platform_device
*pdev
)
270 struct jz4740_glue
*glue
= platform_get_drvdata(pdev
);
272 platform_device_unregister(glue
->pdev
);
273 clk_disable_unprepare(glue
->clk
);
278 static const struct of_device_id jz4740_musb_of_match
[] = {
279 { .compatible
= "ingenic,jz4740-musb", .data
= &jz4740_musb_pdata
},
280 { .compatible
= "ingenic,jz4770-musb", .data
= &jz4770_musb_pdata
},
283 MODULE_DEVICE_TABLE(of
, jz4740_musb_of_match
);
285 static struct platform_driver jz4740_driver
= {
286 .probe
= jz4740_probe
,
287 .remove
= jz4740_remove
,
289 .name
= "musb-jz4740",
290 .of_match_table
= jz4740_musb_of_match
,
294 MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer");
295 MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>");
296 MODULE_LICENSE("GPL v2");
297 module_platform_driver(jz4740_driver
);