18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016, NVIDIA Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/of_device.h> 98c2ecf20Sopenharmony_ci#include <linux/reset.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/usb/chipidea.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "ci.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct tegra_udc { 168c2ecf20Sopenharmony_ci struct ci_hdrc_platform_data data; 178c2ecf20Sopenharmony_ci struct platform_device *dev; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci struct usb_phy *phy; 208c2ecf20Sopenharmony_ci struct clk *clk; 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct tegra_udc_soc_info { 248c2ecf20Sopenharmony_ci unsigned long flags; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const struct tegra_udc_soc_info tegra_udc_soc_info = { 288c2ecf20Sopenharmony_ci .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_udc_of_match[] = { 328c2ecf20Sopenharmony_ci { 338c2ecf20Sopenharmony_ci .compatible = "nvidia,tegra20-udc", 348c2ecf20Sopenharmony_ci .data = &tegra_udc_soc_info, 358c2ecf20Sopenharmony_ci }, { 368c2ecf20Sopenharmony_ci .compatible = "nvidia,tegra30-udc", 378c2ecf20Sopenharmony_ci .data = &tegra_udc_soc_info, 388c2ecf20Sopenharmony_ci }, { 398c2ecf20Sopenharmony_ci .compatible = "nvidia,tegra114-udc", 408c2ecf20Sopenharmony_ci .data = &tegra_udc_soc_info, 418c2ecf20Sopenharmony_ci }, { 428c2ecf20Sopenharmony_ci .compatible = "nvidia,tegra124-udc", 438c2ecf20Sopenharmony_ci .data = &tegra_udc_soc_info, 448c2ecf20Sopenharmony_ci }, { 458c2ecf20Sopenharmony_ci /* sentinel */ 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_udc_of_match); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int tegra_udc_probe(struct platform_device *pdev) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci const struct tegra_udc_soc_info *soc; 538c2ecf20Sopenharmony_ci struct tegra_udc *udc; 548c2ecf20Sopenharmony_ci int err; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); 578c2ecf20Sopenharmony_ci if (!udc) 588c2ecf20Sopenharmony_ci return -ENOMEM; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci soc = of_device_get_match_data(&pdev->dev); 618c2ecf20Sopenharmony_ci if (!soc) { 628c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to match OF data\n"); 638c2ecf20Sopenharmony_ci return -EINVAL; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci udc->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); 678c2ecf20Sopenharmony_ci if (IS_ERR(udc->phy)) { 688c2ecf20Sopenharmony_ci err = PTR_ERR(udc->phy); 698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get PHY: %d\n", err); 708c2ecf20Sopenharmony_ci return err; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci udc->clk = devm_clk_get(&pdev->dev, NULL); 748c2ecf20Sopenharmony_ci if (IS_ERR(udc->clk)) { 758c2ecf20Sopenharmony_ci err = PTR_ERR(udc->clk); 768c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get clock: %d\n", err); 778c2ecf20Sopenharmony_ci return err; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci err = clk_prepare_enable(udc->clk); 818c2ecf20Sopenharmony_ci if (err < 0) { 828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable clock: %d\n", err); 838c2ecf20Sopenharmony_ci return err; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* setup and register ChipIdea HDRC device */ 878c2ecf20Sopenharmony_ci udc->data.name = "tegra-udc"; 888c2ecf20Sopenharmony_ci udc->data.flags = soc->flags; 898c2ecf20Sopenharmony_ci udc->data.usb_phy = udc->phy; 908c2ecf20Sopenharmony_ci udc->data.capoffset = DEF_CAPOFFSET; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci udc->dev = ci_hdrc_add_device(&pdev->dev, pdev->resource, 938c2ecf20Sopenharmony_ci pdev->num_resources, &udc->data); 948c2ecf20Sopenharmony_ci if (IS_ERR(udc->dev)) { 958c2ecf20Sopenharmony_ci err = PTR_ERR(udc->dev); 968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to add HDRC device: %d\n", err); 978c2ecf20Sopenharmony_ci goto fail_power_off; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, udc); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cifail_power_off: 1058c2ecf20Sopenharmony_ci clk_disable_unprepare(udc->clk); 1068c2ecf20Sopenharmony_ci return err; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int tegra_udc_remove(struct platform_device *pdev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct tegra_udc *udc = platform_get_drvdata(pdev); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ci_hdrc_remove_device(udc->dev); 1148c2ecf20Sopenharmony_ci clk_disable_unprepare(udc->clk); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct platform_driver tegra_udc_driver = { 1208c2ecf20Sopenharmony_ci .driver = { 1218c2ecf20Sopenharmony_ci .name = "tegra-udc", 1228c2ecf20Sopenharmony_ci .of_match_table = tegra_udc_of_match, 1238c2ecf20Sopenharmony_ci }, 1248c2ecf20Sopenharmony_ci .probe = tegra_udc_probe, 1258c2ecf20Sopenharmony_ci .remove = tegra_udc_remove, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_cimodule_platform_driver(tegra_udc_driver); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra USB device mode driver"); 1308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 1318c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:tegra-udc"); 1328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 133