2 * snps_udc_plat.c - Synopsys UDC Platform Driver
4 * Copyright (C) 2016 Broadcom
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation version 2.
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/extcon.h>
17 #include <linux/of_address.h>
18 #include <linux/of_irq.h>
19 #include <linux/of_gpio.h>
20 #include <linux/platform_device.h>
21 #include <linux/phy/phy.h>
22 #include <linux/module.h>
23 #include <linux/dmapool.h>
24 #include <linux/interrupt.h>
25 #include <linux/moduleparam.h>
26 #include "amd5536udc.h"
29 #define UDC_MOD_DESCRIPTION "Synopsys UDC platform driver"
31 static void start_udc(struct udc
*udc
)
34 dev_info(udc
->dev
, "Connecting...\n");
35 udc_enable_dev_setup_interrupts(udc
);
41 static void stop_udc(struct udc
*udc
)
46 spin_lock(&udc
->lock
);
48 /* Flush the receieve fifo */
49 reg
= readl(&udc
->regs
->ctl
);
50 reg
|= AMD_BIT(UDC_DEVCTL_SRX_FLUSH
);
51 writel(reg
, &udc
->regs
->ctl
);
53 reg
= readl(&udc
->regs
->ctl
);
54 reg
&= ~(AMD_BIT(UDC_DEVCTL_SRX_FLUSH
));
55 writel(reg
, &udc
->regs
->ctl
);
56 dev_dbg(udc
->dev
, "ep rx queue flushed\n");
58 /* Mask interrupts. Required more so when the
59 * UDC is connected to a DRD phy.
61 udc_mask_unused_interrupts(udc
);
63 /* Disconnect gadget driver */
65 spin_unlock(&udc
->lock
);
66 udc
->driver
->disconnect(&udc
->gadget
);
67 spin_lock(&udc
->lock
);
70 for (tmp
= 0; tmp
< UDC_EP_NUM
; tmp
++)
71 empty_req_queue(&udc
->ep
[tmp
]);
75 spin_unlock(&udc
->lock
);
76 dev_info(udc
->dev
, "Device disconnected\n");
79 static void udc_drd_work(struct work_struct
*work
)
83 udc
= container_of(to_delayed_work(work
),
84 struct udc
, drd_work
);
87 dev_dbg(udc
->dev
, "idle -> device\n");
90 dev_dbg(udc
->dev
, "device -> idle\n");
95 static int usbd_connect_notify(struct notifier_block
*self
,
96 unsigned long event
, void *ptr
)
98 struct udc
*udc
= container_of(self
, struct udc
, nb
);
100 dev_dbg(udc
->dev
, "%s: event: %lu\n", __func__
, event
);
102 udc
->conn_type
= event
;
104 schedule_delayed_work(&udc
->drd_work
, 0);
109 static int udc_plat_probe(struct platform_device
*pdev
)
111 struct device
*dev
= &pdev
->dev
;
112 struct resource
*res
;
116 udc
= devm_kzalloc(dev
, sizeof(*udc
), GFP_KERNEL
);
120 spin_lock_init(&udc
->lock
);
123 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
124 udc
->virt_addr
= devm_ioremap_resource(dev
, res
);
125 if (IS_ERR(udc
->regs
))
126 return PTR_ERR(udc
->regs
);
128 /* udc csr registers base */
129 udc
->csr
= udc
->virt_addr
+ UDC_CSR_ADDR
;
131 /* dev registers base */
132 udc
->regs
= udc
->virt_addr
+ UDC_DEVCFG_ADDR
;
134 /* ep registers base */
135 udc
->ep_regs
= udc
->virt_addr
+ UDC_EPREGS_ADDR
;
138 udc
->rxfifo
= (u32 __iomem
*)(udc
->virt_addr
+ UDC_RXFIFO_ADDR
);
139 udc
->txfifo
= (u32 __iomem
*)(udc
->virt_addr
+ UDC_TXFIFO_ADDR
);
141 udc
->phys_addr
= (unsigned long)res
->start
;
143 udc
->irq
= irq_of_parse_and_map(dev
->of_node
, 0);
145 dev_err(dev
, "Can't parse and map interrupt\n");
149 udc
->udc_phy
= devm_of_phy_get_by_index(dev
, dev
->of_node
, 0);
150 if (IS_ERR(udc
->udc_phy
)) {
151 dev_err(dev
, "Failed to obtain phy from device tree\n");
152 return PTR_ERR(udc
->udc_phy
);
155 ret
= phy_init(udc
->udc_phy
);
157 dev_err(dev
, "UDC phy init failed");
161 ret
= phy_power_on(udc
->udc_phy
);
163 dev_err(dev
, "UDC phy power on failed");
164 phy_exit(udc
->udc_phy
);
168 /* Register for extcon if supported */
169 if (of_get_property(dev
->of_node
, "extcon", NULL
)) {
170 udc
->edev
= extcon_get_edev_by_phandle(dev
, 0);
171 if (IS_ERR(udc
->edev
)) {
172 if (PTR_ERR(udc
->edev
) == -EPROBE_DEFER
)
173 return -EPROBE_DEFER
;
174 dev_err(dev
, "Invalid or missing extcon\n");
175 ret
= PTR_ERR(udc
->edev
);
179 udc
->nb
.notifier_call
= usbd_connect_notify
;
180 ret
= extcon_register_notifier(udc
->edev
, EXTCON_USB
,
183 dev_err(dev
, "Can't register extcon device\n");
187 ret
= extcon_get_cable_state_(udc
->edev
, EXTCON_USB
);
189 dev_err(dev
, "Can't get cable state\n");
192 udc
->conn_type
= ret
;
194 INIT_DELAYED_WORK(&udc
->drd_work
, udc_drd_work
);
199 ret
= init_dma_pools(udc
);
204 ret
= devm_request_irq(dev
, udc
->irq
, udc_irq
, IRQF_SHARED
,
207 dev_err(dev
, "Request irq %d failed for UDC\n", udc
->irq
);
211 platform_set_drvdata(pdev
, udc
);
212 udc
->chiprev
= UDC_BCM_REV
;
214 if (udc_probe(udc
)) {
218 dev_info(dev
, "Synopsys UDC platform driver probe successful\n");
227 extcon_unregister_notifier(udc
->edev
, EXTCON_USB
, &udc
->nb
);
230 phy_power_off(udc
->udc_phy
);
231 phy_exit(udc
->udc_phy
);
236 static int udc_plat_remove(struct platform_device
*pdev
)
240 dev
= platform_get_drvdata(pdev
);
242 usb_del_gadget_udc(&dev
->gadget
);
243 /* gadget driver must not be registered */
244 if (WARN_ON(dev
->driver
))
247 /* dma pool cleanup */
252 platform_set_drvdata(pdev
, NULL
);
255 flush_workqueue(dev
->drd_wq
);
256 destroy_workqueue(dev
->drd_wq
);
259 phy_power_off(dev
->udc_phy
);
260 phy_exit(dev
->udc_phy
);
261 extcon_unregister_notifier(dev
->edev
, EXTCON_USB
, &dev
->nb
);
263 dev_info(&pdev
->dev
, "Synopsys UDC platform driver removed\n");
268 #ifdef CONFIG_PM_SLEEP
269 static int udc_plat_suspend(struct device
*dev
)
273 udc
= dev_get_drvdata(dev
);
276 if (extcon_get_cable_state_(udc
->edev
, EXTCON_USB
) > 0) {
277 dev_dbg(udc
->dev
, "device -> idle\n");
280 phy_power_off(udc
->udc_phy
);
281 phy_exit(udc
->udc_phy
);
286 static int udc_plat_resume(struct device
*dev
)
291 udc
= dev_get_drvdata(dev
);
293 ret
= phy_init(udc
->udc_phy
);
295 dev_err(udc
->dev
, "UDC phy init failure");
299 ret
= phy_power_on(udc
->udc_phy
);
301 dev_err(udc
->dev
, "UDC phy power on failure");
302 phy_exit(udc
->udc_phy
);
306 if (extcon_get_cable_state_(udc
->edev
, EXTCON_USB
) > 0) {
307 dev_dbg(udc
->dev
, "idle -> device\n");
313 static const struct dev_pm_ops udc_plat_pm_ops
= {
314 .suspend
= udc_plat_suspend
,
315 .resume
= udc_plat_resume
,
319 #if defined(CONFIG_OF)
320 static const struct of_device_id of_udc_match
[] = {
321 { .compatible
= "brcm,ns2-udc", },
322 { .compatible
= "brcm,cygnus-udc", },
323 { .compatible
= "brcm,iproc-udc", },
326 MODULE_DEVICE_TABLE(of
, of_udc_match
);
329 static struct platform_driver udc_plat_driver
= {
330 .probe
= udc_plat_probe
,
331 .remove
= udc_plat_remove
,
333 .name
= "snps-udc-plat",
334 .of_match_table
= of_match_ptr(of_udc_match
),
335 #ifdef CONFIG_PM_SLEEP
336 .pm
= &udc_plat_pm_ops
,
340 module_platform_driver(udc_plat_driver
);
342 MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION
);
343 MODULE_AUTHOR("Broadcom");
344 MODULE_LICENSE("GPL v2");