1// SPDX-License-Identifier: GPL-2.0 2/* 3 * snps_udc_plat.c - Synopsys UDC Platform Driver 4 * 5 * Copyright (C) 2016 Broadcom 6 */ 7 8#include <linux/extcon.h> 9#include <linux/of_address.h> 10#include <linux/of_irq.h> 11#include <linux/platform_device.h> 12#include <linux/phy/phy.h> 13#include <linux/module.h> 14#include <linux/dmapool.h> 15#include <linux/interrupt.h> 16#include <linux/moduleparam.h> 17#include "amd5536udc.h" 18 19/* description */ 20#define UDC_MOD_DESCRIPTION "Synopsys UDC platform driver" 21 22static void start_udc(struct udc *udc) 23{ 24 if (udc->driver) { 25 dev_info(udc->dev, "Connecting...\n"); 26 udc_enable_dev_setup_interrupts(udc); 27 udc_basic_init(udc); 28 udc->connected = 1; 29 } 30} 31 32static void stop_udc(struct udc *udc) 33{ 34 int tmp; 35 u32 reg; 36 37 spin_lock(&udc->lock); 38 39 /* Flush the receieve fifo */ 40 reg = readl(&udc->regs->ctl); 41 reg |= AMD_BIT(UDC_DEVCTL_SRX_FLUSH); 42 writel(reg, &udc->regs->ctl); 43 44 reg = readl(&udc->regs->ctl); 45 reg &= ~(AMD_BIT(UDC_DEVCTL_SRX_FLUSH)); 46 writel(reg, &udc->regs->ctl); 47 dev_dbg(udc->dev, "ep rx queue flushed\n"); 48 49 /* Mask interrupts. Required more so when the 50 * UDC is connected to a DRD phy. 51 */ 52 udc_mask_unused_interrupts(udc); 53 54 /* Disconnect gadget driver */ 55 if (udc->driver) { 56 spin_unlock(&udc->lock); 57 udc->driver->disconnect(&udc->gadget); 58 spin_lock(&udc->lock); 59 60 /* empty queues */ 61 for (tmp = 0; tmp < UDC_EP_NUM; tmp++) 62 empty_req_queue(&udc->ep[tmp]); 63 } 64 udc->connected = 0; 65 66 spin_unlock(&udc->lock); 67 dev_info(udc->dev, "Device disconnected\n"); 68} 69 70static void udc_drd_work(struct work_struct *work) 71{ 72 struct udc *udc; 73 74 udc = container_of(to_delayed_work(work), 75 struct udc, drd_work); 76 77 if (udc->conn_type) { 78 dev_dbg(udc->dev, "idle -> device\n"); 79 start_udc(udc); 80 } else { 81 dev_dbg(udc->dev, "device -> idle\n"); 82 stop_udc(udc); 83 } 84} 85 86static int usbd_connect_notify(struct notifier_block *self, 87 unsigned long event, void *ptr) 88{ 89 struct udc *udc = container_of(self, struct udc, nb); 90 91 dev_dbg(udc->dev, "%s: event: %lu\n", __func__, event); 92 93 udc->conn_type = event; 94 95 schedule_delayed_work(&udc->drd_work, 0); 96 97 return NOTIFY_OK; 98} 99 100static int udc_plat_probe(struct platform_device *pdev) 101{ 102 struct device *dev = &pdev->dev; 103 struct resource *res; 104 struct udc *udc; 105 int ret; 106 107 udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL); 108 if (!udc) 109 return -ENOMEM; 110 111 spin_lock_init(&udc->lock); 112 udc->dev = dev; 113 114 udc->virt_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 115 if (IS_ERR(udc->virt_addr)) 116 return PTR_ERR(udc->virt_addr); 117 118 /* udc csr registers base */ 119 udc->csr = udc->virt_addr + UDC_CSR_ADDR; 120 121 /* dev registers base */ 122 udc->regs = udc->virt_addr + UDC_DEVCFG_ADDR; 123 124 /* ep registers base */ 125 udc->ep_regs = udc->virt_addr + UDC_EPREGS_ADDR; 126 127 /* fifo's base */ 128 udc->rxfifo = (u32 __iomem *)(udc->virt_addr + UDC_RXFIFO_ADDR); 129 udc->txfifo = (u32 __iomem *)(udc->virt_addr + UDC_TXFIFO_ADDR); 130 131 udc->phys_addr = (unsigned long)res->start; 132 133 udc->irq = irq_of_parse_and_map(dev->of_node, 0); 134 if (udc->irq <= 0) { 135 dev_err(dev, "Can't parse and map interrupt\n"); 136 return -EINVAL; 137 } 138 139 udc->udc_phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); 140 if (IS_ERR(udc->udc_phy)) { 141 dev_err(dev, "Failed to obtain phy from device tree\n"); 142 return PTR_ERR(udc->udc_phy); 143 } 144 145 ret = phy_init(udc->udc_phy); 146 if (ret) { 147 dev_err(dev, "UDC phy init failed"); 148 return ret; 149 } 150 151 ret = phy_power_on(udc->udc_phy); 152 if (ret) { 153 dev_err(dev, "UDC phy power on failed"); 154 phy_exit(udc->udc_phy); 155 return ret; 156 } 157 158 /* Register for extcon if supported */ 159 if (of_property_present(dev->of_node, "extcon")) { 160 udc->edev = extcon_get_edev_by_phandle(dev, 0); 161 if (IS_ERR(udc->edev)) { 162 if (PTR_ERR(udc->edev) == -EPROBE_DEFER) 163 return -EPROBE_DEFER; 164 dev_err(dev, "Invalid or missing extcon\n"); 165 ret = PTR_ERR(udc->edev); 166 goto exit_phy; 167 } 168 169 udc->nb.notifier_call = usbd_connect_notify; 170 ret = extcon_register_notifier(udc->edev, EXTCON_USB, 171 &udc->nb); 172 if (ret < 0) { 173 dev_err(dev, "Can't register extcon device\n"); 174 goto exit_phy; 175 } 176 177 ret = extcon_get_state(udc->edev, EXTCON_USB); 178 if (ret < 0) { 179 dev_err(dev, "Can't get cable state\n"); 180 goto exit_extcon; 181 } else if (ret) { 182 udc->conn_type = ret; 183 } 184 INIT_DELAYED_WORK(&udc->drd_work, udc_drd_work); 185 } 186 187 /* init dma pools */ 188 if (use_dma) { 189 ret = init_dma_pools(udc); 190 if (ret != 0) 191 goto exit_extcon; 192 } 193 194 ret = devm_request_irq(dev, udc->irq, udc_irq, IRQF_SHARED, 195 "snps-udc", udc); 196 if (ret < 0) { 197 dev_err(dev, "Request irq %d failed for UDC\n", udc->irq); 198 goto exit_dma; 199 } 200 201 platform_set_drvdata(pdev, udc); 202 udc->chiprev = UDC_BCM_REV; 203 204 if (udc_probe(udc)) { 205 ret = -ENODEV; 206 goto exit_dma; 207 } 208 dev_info(dev, "Synopsys UDC platform driver probe successful\n"); 209 210 return 0; 211 212exit_dma: 213 if (use_dma) 214 free_dma_pools(udc); 215exit_extcon: 216 if (udc->edev) 217 extcon_unregister_notifier(udc->edev, EXTCON_USB, &udc->nb); 218exit_phy: 219 if (udc->udc_phy) { 220 phy_power_off(udc->udc_phy); 221 phy_exit(udc->udc_phy); 222 } 223 return ret; 224} 225 226static void udc_plat_remove(struct platform_device *pdev) 227{ 228 struct udc *dev; 229 230 dev = platform_get_drvdata(pdev); 231 232 usb_del_gadget_udc(&dev->gadget); 233 /* gadget driver must not be registered */ 234 if (WARN_ON(dev->driver)) 235 return; 236 237 /* dma pool cleanup */ 238 free_dma_pools(dev); 239 240 udc_remove(dev); 241 242 platform_set_drvdata(pdev, NULL); 243 244 phy_power_off(dev->udc_phy); 245 phy_exit(dev->udc_phy); 246 extcon_unregister_notifier(dev->edev, EXTCON_USB, &dev->nb); 247 248 dev_info(&pdev->dev, "Synopsys UDC platform driver removed\n"); 249} 250 251#ifdef CONFIG_PM_SLEEP 252static int udc_plat_suspend(struct device *dev) 253{ 254 struct udc *udc; 255 256 udc = dev_get_drvdata(dev); 257 stop_udc(udc); 258 259 if (extcon_get_state(udc->edev, EXTCON_USB) > 0) { 260 dev_dbg(udc->dev, "device -> idle\n"); 261 stop_udc(udc); 262 } 263 phy_power_off(udc->udc_phy); 264 phy_exit(udc->udc_phy); 265 266 return 0; 267} 268 269static int udc_plat_resume(struct device *dev) 270{ 271 struct udc *udc; 272 int ret; 273 274 udc = dev_get_drvdata(dev); 275 276 ret = phy_init(udc->udc_phy); 277 if (ret) { 278 dev_err(udc->dev, "UDC phy init failure"); 279 return ret; 280 } 281 282 ret = phy_power_on(udc->udc_phy); 283 if (ret) { 284 dev_err(udc->dev, "UDC phy power on failure"); 285 phy_exit(udc->udc_phy); 286 return ret; 287 } 288 289 if (extcon_get_state(udc->edev, EXTCON_USB) > 0) { 290 dev_dbg(udc->dev, "idle -> device\n"); 291 start_udc(udc); 292 } 293 294 return 0; 295} 296static const struct dev_pm_ops udc_plat_pm_ops = { 297 .suspend = udc_plat_suspend, 298 .resume = udc_plat_resume, 299}; 300#endif 301 302static const struct of_device_id of_udc_match[] = { 303 { .compatible = "brcm,ns2-udc", }, 304 { .compatible = "brcm,cygnus-udc", }, 305 { .compatible = "brcm,iproc-udc", }, 306 { } 307}; 308MODULE_DEVICE_TABLE(of, of_udc_match); 309 310static struct platform_driver udc_plat_driver = { 311 .probe = udc_plat_probe, 312 .remove_new = udc_plat_remove, 313 .driver = { 314 .name = "snps-udc-plat", 315 .of_match_table = of_udc_match, 316#ifdef CONFIG_PM_SLEEP 317 .pm = &udc_plat_pm_ops, 318#endif 319 }, 320}; 321module_platform_driver(udc_plat_driver); 322 323MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); 324MODULE_AUTHOR("Broadcom"); 325MODULE_LICENSE("GPL v2"); 326