18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Platform UFS Host driver for Cadence controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Cadence Design Systems, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Jan Kotas <jank@cadence.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/time.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "ufshcd-pltfrm.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define CDNS_UFS_REG_HCLKDIV 0xFC 218c2ecf20Sopenharmony_ci#define CDNS_UFS_REG_PHY_XCFGD1 0x113C 228c2ecf20Sopenharmony_ci#define CDNS_UFS_MAX_L4_ATTRS 12 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct cdns_ufs_host { 258c2ecf20Sopenharmony_ci /** 268c2ecf20Sopenharmony_ci * cdns_ufs_dme_attr_val - for storing L4 attributes 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci u32 cdns_ufs_dme_attr_val[CDNS_UFS_MAX_L4_ATTRS]; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * cdns_ufs_get_l4_attr - get L4 attributes on local side 338c2ecf20Sopenharmony_ci * @hba: per adapter instance 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistatic void cdns_ufs_get_l4_attr(struct ufs_hba *hba) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct cdns_ufs_host *host = ufshcd_get_variant(hba); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_PEERDEVICEID), 418c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[0]); 428c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_PEERCPORTID), 438c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[1]); 448c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_TRAFFICCLASS), 458c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[2]); 468c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_PROTOCOLID), 478c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[3]); 488c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_CPORTFLAGS), 498c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[4]); 508c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_TXTOKENVALUE), 518c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[5]); 528c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_RXTOKENVALUE), 538c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[6]); 548c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_LOCALBUFFERSPACE), 558c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[7]); 568c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_PEERBUFFERSPACE), 578c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[8]); 588c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_CREDITSTOSEND), 598c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[9]); 608c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_CPORTMODE), 618c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[10]); 628c2ecf20Sopenharmony_ci ufshcd_dme_get(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 638c2ecf20Sopenharmony_ci &host->cdns_ufs_dme_attr_val[11]); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * cdns_ufs_set_l4_attr - set L4 attributes on local side 688c2ecf20Sopenharmony_ci * @hba: per adapter instance 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistatic void cdns_ufs_set_l4_attr(struct ufs_hba *hba) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct cdns_ufs_host *host = ufshcd_get_variant(hba); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 0); 768c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERDEVICEID), 778c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[0]); 788c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERCPORTID), 798c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[1]); 808c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_TRAFFICCLASS), 818c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[2]); 828c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_PROTOCOLID), 838c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[3]); 848c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTFLAGS), 858c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[4]); 868c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_TXTOKENVALUE), 878c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[5]); 888c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_RXTOKENVALUE), 898c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[6]); 908c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_LOCALBUFFERSPACE), 918c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[7]); 928c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERBUFFERSPACE), 938c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[8]); 948c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_CREDITSTOSEND), 958c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[9]); 968c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTMODE), 978c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[10]); 988c2ecf20Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 998c2ecf20Sopenharmony_ci host->cdns_ufs_dme_attr_val[11]); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/** 1038c2ecf20Sopenharmony_ci * Sets HCLKDIV register value based on the core_clk 1048c2ecf20Sopenharmony_ci * @hba: host controller instance 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * Return zero for success and non-zero for failure 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistatic int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct ufs_clk_info *clki; 1118c2ecf20Sopenharmony_ci struct list_head *head = &hba->clk_list_head; 1128c2ecf20Sopenharmony_ci unsigned long core_clk_rate = 0; 1138c2ecf20Sopenharmony_ci u32 core_clk_div = 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (list_empty(head)) 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci list_for_each_entry(clki, head, list) { 1198c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clki->clk)) 1208c2ecf20Sopenharmony_ci continue; 1218c2ecf20Sopenharmony_ci if (!strcmp(clki->name, "core_clk")) 1228c2ecf20Sopenharmony_ci core_clk_rate = clk_get_rate(clki->clk); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (!core_clk_rate) { 1268c2ecf20Sopenharmony_ci dev_err(hba->dev, "%s: unable to find core_clk rate\n", 1278c2ecf20Sopenharmony_ci __func__); 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci core_clk_div = core_clk_rate / USEC_PER_SEC; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ufshcd_writel(hba, core_clk_div, CDNS_UFS_REG_HCLKDIV); 1348c2ecf20Sopenharmony_ci /** 1358c2ecf20Sopenharmony_ci * Make sure the register was updated, 1368c2ecf20Sopenharmony_ci * UniPro layer will not work with an incorrect value. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci mb(); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * Called before and after HCE enable bit is set. 1458c2ecf20Sopenharmony_ci * @hba: host controller instance 1468c2ecf20Sopenharmony_ci * @status: notify stage (pre, post change) 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Return zero for success and non-zero for failure 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic int cdns_ufs_hce_enable_notify(struct ufs_hba *hba, 1518c2ecf20Sopenharmony_ci enum ufs_notify_change_status status) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci if (status != PRE_CHANGE) 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return cdns_ufs_set_hclkdiv(hba); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * Called around hibern8 enter/exit. 1618c2ecf20Sopenharmony_ci * @hba: host controller instance 1628c2ecf20Sopenharmony_ci * @cmd: UIC Command 1638c2ecf20Sopenharmony_ci * @status: notify stage (pre, post change) 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd, 1678c2ecf20Sopenharmony_ci enum ufs_notify_change_status status) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci if (status == PRE_CHANGE && cmd == UIC_CMD_DME_HIBER_ENTER) 1708c2ecf20Sopenharmony_ci cdns_ufs_get_l4_attr(hba); 1718c2ecf20Sopenharmony_ci if (status == POST_CHANGE && cmd == UIC_CMD_DME_HIBER_EXIT) 1728c2ecf20Sopenharmony_ci cdns_ufs_set_l4_attr(hba); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * Called before and after Link startup is carried out. 1778c2ecf20Sopenharmony_ci * @hba: host controller instance 1788c2ecf20Sopenharmony_ci * @status: notify stage (pre, post change) 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * Return zero for success and non-zero for failure 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_cistatic int cdns_ufs_link_startup_notify(struct ufs_hba *hba, 1838c2ecf20Sopenharmony_ci enum ufs_notify_change_status status) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci if (status != PRE_CHANGE) 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * Some UFS devices have issues if LCC is enabled. 1908c2ecf20Sopenharmony_ci * So we are setting PA_Local_TX_LCC_Enable to 0 1918c2ecf20Sopenharmony_ci * before link startup which will make sure that both host 1928c2ecf20Sopenharmony_ci * and device TX LCC are disabled once link startup is 1938c2ecf20Sopenharmony_ci * completed. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci ufshcd_disable_host_tx_lcc(hba); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Disabling Autohibern8 feature in cadence UFS 1998c2ecf20Sopenharmony_ci * to mask unexpected interrupt trigger. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci hba->ahit = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/** 2078c2ecf20Sopenharmony_ci * cdns_ufs_init - performs additional ufs initialization 2088c2ecf20Sopenharmony_ci * @hba: host controller instance 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Returns status of initialization 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cistatic int cdns_ufs_init(struct ufs_hba *hba) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int status = 0; 2158c2ecf20Sopenharmony_ci struct cdns_ufs_host *host; 2168c2ecf20Sopenharmony_ci struct device *dev = hba->dev; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!host) 2218c2ecf20Sopenharmony_ci return -ENOMEM; 2228c2ecf20Sopenharmony_ci ufshcd_set_variant(hba, host); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (hba->vops && hba->vops->phy_initialization) 2258c2ecf20Sopenharmony_ci status = hba->vops->phy_initialization(hba); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return status; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * cdns_ufs_m31_16nm_phy_initialization - performs m31 phy initialization 2328c2ecf20Sopenharmony_ci * @hba: host controller instance 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * Always returns 0 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_cistatic int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci u32 data; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Increase RX_Advanced_Min_ActivateTime_Capability */ 2418c2ecf20Sopenharmony_ci data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1); 2428c2ecf20Sopenharmony_ci data |= BIT(24); 2438c2ecf20Sopenharmony_ci ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic const struct ufs_hba_variant_ops cdns_ufs_pltfm_hba_vops = { 2498c2ecf20Sopenharmony_ci .name = "cdns-ufs-pltfm", 2508c2ecf20Sopenharmony_ci .init = cdns_ufs_init, 2518c2ecf20Sopenharmony_ci .hce_enable_notify = cdns_ufs_hce_enable_notify, 2528c2ecf20Sopenharmony_ci .link_startup_notify = cdns_ufs_link_startup_notify, 2538c2ecf20Sopenharmony_ci .hibern8_notify = cdns_ufs_hibern8_notify, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { 2578c2ecf20Sopenharmony_ci .name = "cdns-ufs-pltfm", 2588c2ecf20Sopenharmony_ci .init = cdns_ufs_init, 2598c2ecf20Sopenharmony_ci .hce_enable_notify = cdns_ufs_hce_enable_notify, 2608c2ecf20Sopenharmony_ci .link_startup_notify = cdns_ufs_link_startup_notify, 2618c2ecf20Sopenharmony_ci .phy_initialization = cdns_ufs_m31_16nm_phy_initialization, 2628c2ecf20Sopenharmony_ci .hibern8_notify = cdns_ufs_hibern8_notify, 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic const struct of_device_id cdns_ufs_of_match[] = { 2668c2ecf20Sopenharmony_ci { 2678c2ecf20Sopenharmony_ci .compatible = "cdns,ufshc", 2688c2ecf20Sopenharmony_ci .data = &cdns_ufs_pltfm_hba_vops, 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci { 2718c2ecf20Sopenharmony_ci .compatible = "cdns,ufshc-m31-16nm", 2728c2ecf20Sopenharmony_ci .data = &cdns_ufs_m31_16nm_pltfm_hba_vops, 2738c2ecf20Sopenharmony_ci }, 2748c2ecf20Sopenharmony_ci { }, 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cdns_ufs_of_match); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/** 2808c2ecf20Sopenharmony_ci * cdns_ufs_pltfrm_probe - probe routine of the driver 2818c2ecf20Sopenharmony_ci * @pdev: pointer to platform device handle 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Return zero for success and non-zero for failure 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic int cdns_ufs_pltfrm_probe(struct platform_device *pdev) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int err; 2888c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 2898c2ecf20Sopenharmony_ci struct ufs_hba_variant_ops *vops; 2908c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci of_id = of_match_node(cdns_ufs_of_match, dev->of_node); 2938c2ecf20Sopenharmony_ci vops = (struct ufs_hba_variant_ops *)of_id->data; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Perform generic probe */ 2968c2ecf20Sopenharmony_ci err = ufshcd_pltfrm_init(pdev, vops); 2978c2ecf20Sopenharmony_ci if (err) 2988c2ecf20Sopenharmony_ci dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return err; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/** 3048c2ecf20Sopenharmony_ci * cdns_ufs_pltfrm_remove - removes the ufs driver 3058c2ecf20Sopenharmony_ci * @pdev: pointer to platform device handle 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Always returns 0 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic int cdns_ufs_pltfrm_remove(struct platform_device *pdev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct ufs_hba *hba = platform_get_drvdata(pdev); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci ufshcd_remove(hba); 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cdns_ufs_dev_pm_ops = { 3188c2ecf20Sopenharmony_ci .suspend = ufshcd_pltfrm_suspend, 3198c2ecf20Sopenharmony_ci .resume = ufshcd_pltfrm_resume, 3208c2ecf20Sopenharmony_ci .runtime_suspend = ufshcd_pltfrm_runtime_suspend, 3218c2ecf20Sopenharmony_ci .runtime_resume = ufshcd_pltfrm_runtime_resume, 3228c2ecf20Sopenharmony_ci .runtime_idle = ufshcd_pltfrm_runtime_idle, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic struct platform_driver cdns_ufs_pltfrm_driver = { 3268c2ecf20Sopenharmony_ci .probe = cdns_ufs_pltfrm_probe, 3278c2ecf20Sopenharmony_ci .remove = cdns_ufs_pltfrm_remove, 3288c2ecf20Sopenharmony_ci .shutdown = ufshcd_pltfrm_shutdown, 3298c2ecf20Sopenharmony_ci .driver = { 3308c2ecf20Sopenharmony_ci .name = "cdns-ufshcd", 3318c2ecf20Sopenharmony_ci .pm = &cdns_ufs_dev_pm_ops, 3328c2ecf20Sopenharmony_ci .of_match_table = cdns_ufs_of_match, 3338c2ecf20Sopenharmony_ci }, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cimodule_platform_driver(cdns_ufs_pltfrm_driver); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jan Kotas <jank@cadence.com>"); 3398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence UFS host controller platform driver"); 3408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3418c2ecf20Sopenharmony_ciMODULE_VERSION(UFSHCD_DRIVER_VERSION); 342