dwc3-exynos.c revision d28a9689c93195d39f91f35a9519876688605b65
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/module.h> 22d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include <linux/clk.h> 23d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 24d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov#include "core.h" 25d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 26d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstruct dwc3_exynos { 27d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct platform_device *dwc3; 28d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct device *dev; 29d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 30d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct clk *clk; 31d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}; 32d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 33d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic int __devinit dwc3_exynos_probe(struct platform_device *pdev) 34d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{ 35d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos_data *pdata = pdev->dev.platform_data; 36d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct platform_device *dwc3; 37d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos *exynos; 38d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct clk *clk; 39d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 40d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov int devid; 41d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov int ret = -ENOMEM; 42d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 43d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos = kzalloc(sizeof(*exynos), GFP_KERNEL); 44d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!exynos) { 45d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "not enough memory\n"); 46d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err0; 47d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 48d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 49d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_set_drvdata(pdev, exynos); 50d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 51d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov devid = dwc3_get_device_id(); 52d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (devid < 0) 53d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err1; 54d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 55d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3 = platform_device_alloc("dwc3", devid); 56d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!dwc3) { 57d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); 58d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err2; 59d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 60d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 61d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk = clk_get(&pdev->dev, "usbdrd30"); 62d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (IS_ERR(clk)) { 63d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "couldn't get clock\n"); 64d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = -EINVAL; 65d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err3; 66d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 67d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 68d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask); 69d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 70d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3->dev.parent = &pdev->dev; 71d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3->dev.dma_mask = pdev->dev.dma_mask; 72d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3->dev.dma_parms = pdev->dev.dma_parms; 73d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->dwc3 = dwc3; 74d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->dev = &pdev->dev; 75d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov exynos->clk = clk; 76d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 77d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_enable(exynos->clk); 78d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 79d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov /* PHY initialization */ 80d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (!pdata) { 81d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_dbg(&pdev->dev, "missing platform data\n"); 82d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } else { 83d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (pdata->phy_init) 84d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov pdata->phy_init(pdev, pdata->phy_type); 85d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 86d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 87d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = platform_device_add_resources(dwc3, pdev->resource, 88d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov pdev->num_resources); 89d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (ret) { 90d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); 91d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err4; 92d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 93d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 94d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov ret = platform_device_add(dwc3); 95d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (ret) { 96d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dev_err(&pdev->dev, "failed to register dwc3 device\n"); 97d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov goto err4; 98d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov } 99d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 100d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return 0; 101d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 102d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr4: 103d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (pdata && pdata->phy_exit) 104d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov pdata->phy_exit(pdev, pdata->phy_type); 105d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 106d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_disable(clk); 107d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_put(clk); 108d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr3: 109d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_device_put(dwc3); 110d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr2: 111d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3_put_device_id(devid); 112d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr1: 113d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov kfree(exynos); 114d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomiroverr0: 115d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return ret; 116d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov} 117d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 118d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic int __devexit dwc3_exynos_remove(struct platform_device *pdev) 119d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov{ 120d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos *exynos = platform_get_drvdata(pdev); 121d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov struct dwc3_exynos_data *pdata = pdev->dev.platform_data; 122d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 123d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov platform_device_unregister(exynos->dwc3); 124d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 125d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov dwc3_put_device_id(exynos->dwc3->id); 126d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 127d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov if (pdata && pdata->phy_exit) 128d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov pdata->phy_exit(pdev, pdata->phy_type); 129d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 130d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_disable(exynos->clk); 131d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov clk_put(exynos->clk); 132d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 133d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov kfree(exynos); 134d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 135d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov return 0; 136d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov} 137d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 138d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovstatic struct platform_driver dwc3_exynos_driver = { 139d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .probe = dwc3_exynos_probe, 140d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .remove = __devexit_p(dwc3_exynos_remove), 141d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .driver = { 142d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov .name = "exynos-dwc3", 143d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov }, 144d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov}; 145d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 146d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirovmodule_platform_driver(dwc3_exynos_driver); 147d28a9689c93195d39f91f35a9519876688605b65Anton Tikhomirov 148d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_ALIAS("platform:exynos-dwc3"); 149d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); 150d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_LICENSE("GPL"); 151d28a9689c93195d39f91f35a9519876688605b65Anton TikhomirovMODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); 152