1 /** 2 * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer 3 * 4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com 6 * 7 * Author: Anton Tikhomirov <av.tikhomirov@samsung.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 */ 14 15 #include <linux/module.h> 16 #include <linux/kernel.h> 17 #include <linux/slab.h> 18 #include <linux/platform_device.h> 19 #include <linux/platform_data/dwc3-exynos.h> 20 #include <linux/dma-mapping.h> 21 #include <linux/clk.h> 22 #include <linux/usb/otg.h> 23 #include <linux/usb/nop-usb-xceiv.h> 24 #include <linux/of.h> 25 26 #include "core.h" 27 28 struct dwc3_exynos { 29 struct platform_device *dwc3; 30 struct platform_device *usb2_phy; 31 struct platform_device *usb3_phy; 32 struct device *dev; 33 34 struct clk *clk; 35 }; 36 37 static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) 38 { 39 struct nop_usb_xceiv_platform_data pdata; 40 struct platform_device *pdev; 41 int ret; 42 43 memset(&pdata, 0x00, sizeof(pdata)); 44 45 pdev = platform_device_alloc("nop_usb_xceiv", 0); 46 if (!pdev) 47 return -ENOMEM; 48 49 exynos->usb2_phy = pdev; 50 pdata.type = USB_PHY_TYPE_USB2; 51 52 ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata)); 53 if (ret) 54 goto err1; 55 56 pdev = platform_device_alloc("nop_usb_xceiv", 1); 57 if (!pdev) { 58 ret = -ENOMEM; 59 goto err1; 60 } 61 62 exynos->usb3_phy = pdev; 63 pdata.type = USB_PHY_TYPE_USB3; 64 65 ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata)); 66 if (ret) 67 goto err2; 68 69 ret = platform_device_add(exynos->usb2_phy); 70 if (ret) 71 goto err2; 72 73 ret = platform_device_add(exynos->usb3_phy); 74 if (ret) 75 goto err3; 76 77 return 0; 78 79 err3: 80 platform_device_del(exynos->usb2_phy); 81 82 err2: 83 platform_device_put(exynos->usb3_phy); 84 85 err1: 86 platform_device_put(exynos->usb2_phy); 87 88 return ret; 89 } 90 91 static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32); 92 93 static int dwc3_exynos_probe(struct platform_device *pdev) 94 { 95 struct platform_device *dwc3; 96 struct dwc3_exynos *exynos; 97 struct clk *clk; 98 99 int ret = -ENOMEM; 100 101 exynos = kzalloc(sizeof(*exynos), GFP_KERNEL); 102 if (!exynos) { 103 dev_err(&pdev->dev, "not enough memory\n"); 104 goto err0; 105 } 106 107 /* 108 * Right now device-tree probed devices don't get dma_mask set. 109 * Since shared usb code relies on it, set it here for now. 110 * Once we move to full device tree support this will vanish off. 111 */ 112 if (!pdev->dev.dma_mask) 113 pdev->dev.dma_mask = &dwc3_exynos_dma_mask; 114 115 platform_set_drvdata(pdev, exynos); 116 117 ret = dwc3_exynos_register_phys(exynos); 118 if (ret) { 119 dev_err(&pdev->dev, "couldn't register PHYs\n"); 120 goto err1; 121 } 122 123 dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 124 if (!dwc3) { 125 dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); 126 goto err1; 127 } 128 129 clk = clk_get(&pdev->dev, "usbdrd30"); 130 if (IS_ERR(clk)) { 131 dev_err(&pdev->dev, "couldn't get clock\n"); 132 ret = -EINVAL; 133 goto err3; 134 } 135 136 dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask); 137 138 dwc3->dev.parent = &pdev->dev; 139 dwc3->dev.dma_mask = pdev->dev.dma_mask; 140 dwc3->dev.dma_parms = pdev->dev.dma_parms; 141 exynos->dwc3 = dwc3; 142 exynos->dev = &pdev->dev; 143 exynos->clk = clk; 144 145 clk_enable(exynos->clk); 146 147 ret = platform_device_add_resources(dwc3, pdev->resource, 148 pdev->num_resources); 149 if (ret) { 150 dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); 151 goto err4; 152 } 153 154 ret = platform_device_add(dwc3); 155 if (ret) { 156 dev_err(&pdev->dev, "failed to register dwc3 device\n"); 157 goto err4; 158 } 159 160 return 0; 161 162 err4: 163 clk_disable(clk); 164 clk_put(clk); 165 err3: 166 platform_device_put(dwc3); 167 err1: 168 kfree(exynos); 169 err0: 170 return ret; 171 } 172 173 static int dwc3_exynos_remove(struct platform_device *pdev) 174 { 175 struct dwc3_exynos *exynos = platform_get_drvdata(pdev); 176 177 platform_device_unregister(exynos->dwc3); 178 platform_device_unregister(exynos->usb2_phy); 179 platform_device_unregister(exynos->usb3_phy); 180 181 clk_disable(exynos->clk); 182 clk_put(exynos->clk); 183 184 kfree(exynos); 185 186 return 0; 187 } 188 189 #ifdef CONFIG_OF 190 static const struct of_device_id exynos_dwc3_match[] = { 191 { .compatible = "samsung,exynos-dwc3" }, 192 {}, 193 }; 194 MODULE_DEVICE_TABLE(of, exynos_dwc3_match); 195 #endif 196 197 static struct platform_driver dwc3_exynos_driver = { 198 .probe = dwc3_exynos_probe, 199 .remove = dwc3_exynos_remove, 200 .driver = { 201 .name = "exynos-dwc3", 202 .of_match_table = of_match_ptr(exynos_dwc3_match), 203 }, 204 }; 205 206 module_platform_driver(dwc3_exynos_driver); 207 208 MODULE_ALIAS("platform:exynos-dwc3"); 209 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); 210 MODULE_LICENSE("GPL"); 211 MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); 212