dwc3-exynos.c revision b0e45ddb96d5a972a8b76354f036b90549ae85b3
1d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov/** 2d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer 3d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * 4d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * Copyright (c) 2012 Samsung Electronics Co., Ltd. 5d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * http://www.samsung.com 6d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * 7d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * Author: Anton Tikhomirov <av.tikhomirov@samsung.com> 8d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * 9d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * This program is free software; you can redistribute it and/or modify 10d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * it under the terms of the GNU General Public License as published by 11d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * the Free Software Foundation; either version 2 of the License, or 12d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov * (at your option) any later version. 13d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov */ 14d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 15d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/module.h> 16d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/kernel.h> 17d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/slab.h> 18d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/platform_device.h> 19d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/platform_data/dwc3-exynos.h> 20d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/dma-mapping.h> 21d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/clk.h> 22d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi#include <linux/usb/otg.h> 23d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi#include <linux/usb/nop-usb-xceiv.h> 24accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#include <linux/of.h> 25d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 26d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include "core.h" 27d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 28d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstruct dwc3_exynos { 29d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct platform_device *dwc3; 30d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi struct platform_device *usb2_phy; 31d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi struct platform_device *usb3_phy; 32d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct device *dev; 33d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 34d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct clk *clk; 35d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}; 36d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 3741ac7b3ab7fe1d6175839947a877fdf95cbd2211Bill Pembertonstatic int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) 38d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi{ 39d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi struct nop_usb_xceiv_platform_data pdata; 40d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi struct platform_device *pdev; 41d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi int ret; 42d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 43d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi memset(&pdata, 0x00, sizeof(pdata)); 44d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 45b0e45ddb96d5a972a8b76354f036b90549ae85b3Vivek Gautam pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); 46d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (!pdev) 47d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi return -ENOMEM; 48d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 49d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi exynos->usb2_phy = pdev; 50d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi pdata.type = USB_PHY_TYPE_USB2; 51d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 52d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata)); 53d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (ret) 54d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi goto err1; 55d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 56b0e45ddb96d5a972a8b76354f036b90549ae85b3Vivek Gautam pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); 57d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (!pdev) { 58d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = -ENOMEM; 59d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi goto err1; 60d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi } 61d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 62d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi exynos->usb3_phy = pdev; 63d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi pdata.type = USB_PHY_TYPE_USB3; 64d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 65d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata)); 66d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (ret) 67d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi goto err2; 68d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 69d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = platform_device_add(exynos->usb2_phy); 70d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (ret) 71d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi goto err2; 72d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 73d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = platform_device_add(exynos->usb3_phy); 74d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (ret) 75d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi goto err3; 76d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 77d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi return 0; 78d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 79d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbierr3: 80d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_del(exynos->usb2_phy); 81d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 82d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbierr2: 83d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_put(exynos->usb3_phy); 84d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 85d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbierr1: 86d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_put(exynos->usb2_phy); 87d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 88d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi return ret; 89d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi} 90d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 91accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautamstatic u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32); 92accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam 9341ac7b3ab7fe1d6175839947a877fdf95cbd2211Bill Pembertonstatic int dwc3_exynos_probe(struct platform_device *pdev) 94d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{ 95d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct platform_device *dwc3; 96d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos *exynos; 97d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct clk *clk; 9820b97dc18323938a92319abf031936b7d2686eafJingoo Han struct device *dev = &pdev->dev; 99d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 100d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov int ret = -ENOMEM; 101d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 10220b97dc18323938a92319abf031936b7d2686eafJingoo Han exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); 103d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!exynos) { 10420b97dc18323938a92319abf031936b7d2686eafJingoo Han dev_err(dev, "not enough memory\n"); 10520b97dc18323938a92319abf031936b7d2686eafJingoo Han return -ENOMEM; 106d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 107d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 108accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam /* 109accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam * Right now device-tree probed devices don't get dma_mask set. 110accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam * Since shared usb code relies on it, set it here for now. 111accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam * Once we move to full device tree support this will vanish off. 112accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam */ 113accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam if (!pdev->dev.dma_mask) 114accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam pdev->dev.dma_mask = &dwc3_exynos_dma_mask; 115accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam 116d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_set_drvdata(pdev, exynos); 117d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 118d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = dwc3_exynos_register_phys(exynos); 119d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (ret) { 12020b97dc18323938a92319abf031936b7d2686eafJingoo Han dev_err(dev, "couldn't register PHYs\n"); 12120b97dc18323938a92319abf031936b7d2686eafJingoo Han return ret; 122d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi } 123d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 124124dafde8f8174caf5cef1c3eaba001657d66f4fSebastian Andrzej Siewior dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 125d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!dwc3) { 12620b97dc18323938a92319abf031936b7d2686eafJingoo Han dev_err(dev, "couldn't allocate dwc3 device\n"); 12720b97dc18323938a92319abf031936b7d2686eafJingoo Han return -ENOMEM; 128d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 129d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 13020b97dc18323938a92319abf031936b7d2686eafJingoo Han clk = devm_clk_get(dev, "usbdrd30"); 131d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (IS_ERR(clk)) { 13220b97dc18323938a92319abf031936b7d2686eafJingoo Han dev_err(dev, "couldn't get clock\n"); 133d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = -EINVAL; 13420b97dc18323938a92319abf031936b7d2686eafJingoo Han goto err1; 135d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 136d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 13720b97dc18323938a92319abf031936b7d2686eafJingoo Han dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); 138d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 13920b97dc18323938a92319abf031936b7d2686eafJingoo Han dwc3->dev.parent = dev; 14020b97dc18323938a92319abf031936b7d2686eafJingoo Han dwc3->dev.dma_mask = dev->dma_mask; 14120b97dc18323938a92319abf031936b7d2686eafJingoo Han dwc3->dev.dma_parms = dev->dma_parms; 142d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->dwc3 = dwc3; 14320b97dc18323938a92319abf031936b7d2686eafJingoo Han exynos->dev = dev; 144d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->clk = clk; 145d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 146d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_enable(exynos->clk); 147d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 148d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = platform_device_add_resources(dwc3, pdev->resource, 149d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov pdev->num_resources); 150d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (ret) { 15120b97dc18323938a92319abf031936b7d2686eafJingoo Han dev_err(dev, "couldn't add resources to dwc3 device\n"); 15220b97dc18323938a92319abf031936b7d2686eafJingoo Han goto err2; 153d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 154d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 155d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = platform_device_add(dwc3); 156d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (ret) { 15720b97dc18323938a92319abf031936b7d2686eafJingoo Han dev_err(dev, "failed to register dwc3 device\n"); 15820b97dc18323938a92319abf031936b7d2686eafJingoo Han goto err2; 159d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 160d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 161d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return 0; 162d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 16320b97dc18323938a92319abf031936b7d2686eafJingoo Hanerr2: 164d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_disable(clk); 165d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr1: 16620b97dc18323938a92319abf031936b7d2686eafJingoo Han platform_device_put(dwc3); 16720b97dc18323938a92319abf031936b7d2686eafJingoo Han 168d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return ret; 169d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov} 170d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 171fb4e98ab63433c4d3a1588ea91c73f1cd7ebaa00Bill Pembertonstatic int dwc3_exynos_remove(struct platform_device *pdev) 172d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{ 173d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos *exynos = platform_get_drvdata(pdev); 174d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 175d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_device_unregister(exynos->dwc3); 176d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_unregister(exynos->usb2_phy); 177d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_unregister(exynos->usb3_phy); 178d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 179d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_disable(exynos->clk); 180d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 181d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return 0; 182d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov} 183d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 184accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#ifdef CONFIG_OF 185accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautamstatic const struct of_device_id exynos_dwc3_match[] = { 186fe29db8fb22f5aa67af4bf30b85a0451c989a88bVivek Gautam { .compatible = "samsung,exynos5250-dwusb3" }, 187accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam {}, 188accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam}; 189accefdd4b234f029a530928ee930b9dcac88fe84Vivek GautamMODULE_DEVICE_TABLE(of, exynos_dwc3_match); 190accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#endif 191accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam 192d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic struct platform_driver dwc3_exynos_driver = { 193d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .probe = dwc3_exynos_probe, 1947690417db5085f0de03aa70b8ca01b0118e8a1b4Bill Pemberton .remove = dwc3_exynos_remove, 195d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .driver = { 196d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .name = "exynos-dwc3", 197accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam .of_match_table = of_match_ptr(exynos_dwc3_match), 198d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov }, 199d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}; 200d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 201d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovmodule_platform_driver(dwc3_exynos_driver); 202d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 203d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_ALIAS("platform:exynos-dwc3"); 204d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); 205d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_LICENSE("GPL"); 206d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); 207