dwc3-exynos.c revision fb4e98ab63433c4d3a1588ea91c73f1cd7ebaa00
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 45d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi pdev = platform_device_alloc("nop_usb_xceiv", 0); 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 56d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi pdev = platform_device_alloc("nop_usb_xceiv", 1); 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; 98d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 99d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov int ret = -ENOMEM; 100d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 101d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos = kzalloc(sizeof(*exynos), GFP_KERNEL); 102d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!exynos) { 103d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "not enough memory\n"); 104d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err0; 105d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 106d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 107accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam /* 108accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam * Right now device-tree probed devices don't get dma_mask set. 109accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam * Since shared usb code relies on it, set it here for now. 110accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam * Once we move to full device tree support this will vanish off. 111accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam */ 112accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam if (!pdev->dev.dma_mask) 113accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam pdev->dev.dma_mask = &dwc3_exynos_dma_mask; 114accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam 115d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_set_drvdata(pdev, exynos); 116d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 117d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi ret = dwc3_exynos_register_phys(exynos); 118d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi if (ret) { 119d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi dev_err(&pdev->dev, "couldn't register PHYs\n"); 120d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi goto err1; 121d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi } 122d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi 123124dafde8f8174caf5cef1c3eaba001657d66f4fSebastian Andrzej Siewior dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 124d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!dwc3) { 125d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); 126124dafde8f8174caf5cef1c3eaba001657d66f4fSebastian Andrzej Siewior goto err1; 127d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 128d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 129d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk = clk_get(&pdev->dev, "usbdrd30"); 130d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (IS_ERR(clk)) { 131d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "couldn't get clock\n"); 132d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = -EINVAL; 133d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err3; 134d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 135d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 136d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask); 137d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 138d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3->dev.parent = &pdev->dev; 139d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3->dev.dma_mask = pdev->dev.dma_mask; 140d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3->dev.dma_parms = pdev->dev.dma_parms; 141d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->dwc3 = dwc3; 142d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->dev = &pdev->dev; 143d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->clk = clk; 144d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 145d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_enable(exynos->clk); 146d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 147d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = platform_device_add_resources(dwc3, pdev->resource, 148d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov pdev->num_resources); 149d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (ret) { 150d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); 151d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err4; 152d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 153d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 154d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = platform_device_add(dwc3); 155d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (ret) { 156d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "failed to register dwc3 device\n"); 157d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err4; 158d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 159d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 160d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return 0; 161d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 162d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr4: 163d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_disable(clk); 164d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_put(clk); 165d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr3: 166d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_device_put(dwc3); 167d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr1: 168d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov kfree(exynos); 169d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr0: 170d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return ret; 171d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov} 172d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 173fb4e98ab63433c4d3a1588ea91c73f1cd7ebaa00Bill Pembertonstatic int dwc3_exynos_remove(struct platform_device *pdev) 174d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{ 175d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos *exynos = platform_get_drvdata(pdev); 176d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 177d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_device_unregister(exynos->dwc3); 178d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_unregister(exynos->usb2_phy); 179d720f057fda4bae91a5108a11587374b9e396c6aFelipe Balbi platform_device_unregister(exynos->usb3_phy); 180d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 181d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_disable(exynos->clk); 182d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_put(exynos->clk); 183d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 184d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov kfree(exynos); 185d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 186d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return 0; 187d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov} 188d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 189accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#ifdef CONFIG_OF 190accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautamstatic const struct of_device_id exynos_dwc3_match[] = { 191accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam { .compatible = "samsung,exynos-dwc3" }, 192accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam {}, 193accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam}; 194accefdd4b234f029a530928ee930b9dcac88fe84Vivek GautamMODULE_DEVICE_TABLE(of, exynos_dwc3_match); 195accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam#endif 196accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam 197d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic struct platform_driver dwc3_exynos_driver = { 198d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .probe = dwc3_exynos_probe, 1997690417db5085f0de03aa70b8ca01b0118e8a1b4Bill Pemberton .remove = dwc3_exynos_remove, 200d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .driver = { 201d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .name = "exynos-dwc3", 202accefdd4b234f029a530928ee930b9dcac88fe84Vivek Gautam .of_match_table = of_match_ptr(exynos_dwc3_match), 203d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov }, 204d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}; 205d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 206d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovmodule_platform_driver(dwc3_exynos_driver); 207d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 208d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_ALIAS("platform:exynos-dwc3"); 209d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); 210d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_LICENSE("GPL"); 211d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); 212