18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell Technology Group Ltd. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Antoine Tenart <antoine.tenart@free-electrons.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 138c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/usb/chipidea.h> 168c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 178c2ecf20Sopenharmony_ci#include <linux/usb/ulpi.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "ci.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct ci_hdrc_usb2_priv { 228c2ecf20Sopenharmony_ci struct platform_device *ci_pdev; 238c2ecf20Sopenharmony_ci struct clk *clk; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const struct ci_hdrc_platform_data ci_default_pdata = { 278c2ecf20Sopenharmony_ci .capoffset = DEF_CAPOFFSET, 288c2ecf20Sopenharmony_ci .flags = CI_HDRC_DISABLE_STREAMING, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const struct ci_hdrc_platform_data ci_zynq_pdata = { 328c2ecf20Sopenharmony_ci .capoffset = DEF_CAPOFFSET, 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const struct ci_hdrc_platform_data ci_zevio_pdata = { 368c2ecf20Sopenharmony_ci .capoffset = DEF_CAPOFFSET, 378c2ecf20Sopenharmony_ci .flags = CI_HDRC_REGS_SHARED | CI_HDRC_FORCE_FULLSPEED, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic const struct of_device_id ci_hdrc_usb2_of_match[] = { 418c2ecf20Sopenharmony_ci { .compatible = "chipidea,usb2" }, 428c2ecf20Sopenharmony_ci { .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata }, 438c2ecf20Sopenharmony_ci { .compatible = "lsi,zevio-usb", .data = &ci_zevio_pdata }, 448c2ecf20Sopenharmony_ci { } 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int ci_hdrc_usb2_probe(struct platform_device *pdev) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 518c2ecf20Sopenharmony_ci struct ci_hdrc_usb2_priv *priv; 528c2ecf20Sopenharmony_ci struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev); 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci const struct of_device_id *match; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (!ci_pdata) { 578c2ecf20Sopenharmony_ci ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL); 588c2ecf20Sopenharmony_ci if (!ci_pdata) 598c2ecf20Sopenharmony_ci return -ENOMEM; 608c2ecf20Sopenharmony_ci *ci_pdata = ci_default_pdata; /* struct copy */ 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci match = of_match_device(ci_hdrc_usb2_of_match, &pdev->dev); 648c2ecf20Sopenharmony_ci if (match && match->data) { 658c2ecf20Sopenharmony_ci /* struct copy */ 668c2ecf20Sopenharmony_ci *ci_pdata = *(struct ci_hdrc_platform_data *)match->data; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 708c2ecf20Sopenharmony_ci if (!priv) 718c2ecf20Sopenharmony_ci return -ENOMEM; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci priv->clk = devm_clk_get_optional(dev, NULL); 748c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) 758c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 788c2ecf20Sopenharmony_ci if (ret) { 798c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable the clock: %d\n", ret); 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ci_pdata->name = dev_name(dev); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci priv->ci_pdev = ci_hdrc_add_device(dev, pdev->resource, 868c2ecf20Sopenharmony_ci pdev->num_resources, ci_pdata); 878c2ecf20Sopenharmony_ci if (IS_ERR(priv->ci_pdev)) { 888c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->ci_pdev); 898c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 908c2ecf20Sopenharmony_ci dev_err(dev, 918c2ecf20Sopenharmony_ci "failed to register ci_hdrc platform device: %d\n", 928c2ecf20Sopenharmony_ci ret); 938c2ecf20Sopenharmony_ci goto clk_err; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci pm_runtime_no_callbacks(dev); 998c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciclk_err: 1048c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 1058c2ecf20Sopenharmony_ci return ret; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int ci_hdrc_usb2_remove(struct platform_device *pdev) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct ci_hdrc_usb2_priv *priv = platform_get_drvdata(pdev); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 1138c2ecf20Sopenharmony_ci ci_hdrc_remove_device(priv->ci_pdev); 1148c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct platform_driver ci_hdrc_usb2_driver = { 1208c2ecf20Sopenharmony_ci .probe = ci_hdrc_usb2_probe, 1218c2ecf20Sopenharmony_ci .remove = ci_hdrc_usb2_remove, 1228c2ecf20Sopenharmony_ci .driver = { 1238c2ecf20Sopenharmony_ci .name = "chipidea-usb2", 1248c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ci_hdrc_usb2_of_match), 1258c2ecf20Sopenharmony_ci }, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_cimodule_platform_driver(ci_hdrc_usb2_driver); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ChipIdea HDRC USB2 binding for ci13xxx"); 1308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); 1318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 132