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 22 static 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 32 static 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 70 static 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 86 static 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 100 static 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 212 exit_dma: 213 if (use_dma) 214 free_dma_pools(udc); 215 exit_extcon: 216 if (udc->edev) 217 extcon_unregister_notifier(udc->edev, EXTCON_USB, &udc->nb); 218 exit_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 226 static 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 252 static 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 269 static 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 } 296 static const struct dev_pm_ops udc_plat_pm_ops = { 297 .suspend = udc_plat_suspend, 298 .resume = udc_plat_resume, 299 }; 300 #endif 301 302 static 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 }; 308 MODULE_DEVICE_TABLE(of, of_udc_match); 309 310 static 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 }; 321 module_platform_driver(udc_plat_driver); 322 323 MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); 324 MODULE_AUTHOR("Broadcom"); 325 MODULE_LICENSE("GPL v2"); 326