1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/platform_device.h> 8 #include <linux/module.h> 9 #include <linux/pm_clock.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/regmap.h> 12 13 #include <dt-bindings/clock/qcom,mss-sc7180.h> 14 15 #include "clk-regmap.h" 16 #include "clk-branch.h" 17 #include "common.h" 18 19 static struct clk_branch mss_axi_nav_clk = { 20 .halt_reg = 0x20bc, 21 .halt_check = BRANCH_HALT, 22 .clkr = { 23 .enable_reg = 0x20bc, 24 .enable_mask = BIT(0), 25 .hw.init = &(struct clk_init_data){ 26 .name = "mss_axi_nav_clk", 27 .parent_data = &(const struct clk_parent_data){ 28 .fw_name = "gcc_mss_nav_axi", 29 }, 30 .num_parents = 1, 31 .ops = &clk_branch2_ops, 32 }, 33 }, 34 }; 35 36 static struct clk_branch mss_axi_crypto_clk = { 37 .halt_reg = 0x20cc, 38 .halt_check = BRANCH_HALT, 39 .clkr = { 40 .enable_reg = 0x20cc, 41 .enable_mask = BIT(0), 42 .hw.init = &(struct clk_init_data){ 43 .name = "mss_axi_crypto_clk", 44 .parent_data = &(const struct clk_parent_data){ 45 .fw_name = "gcc_mss_mfab_axis", 46 }, 47 .num_parents = 1, 48 .ops = &clk_branch2_ops, 49 }, 50 }, 51 }; 52 53 static const struct regmap_config mss_regmap_config = { 54 .reg_bits = 32, 55 .reg_stride = 4, 56 .val_bits = 32, 57 .fast_io = true, 58 .max_register = 0x41aa0cc, 59 }; 60 61 static struct clk_regmap *mss_sc7180_clocks[] = { 62 [MSS_AXI_CRYPTO_CLK] = &mss_axi_crypto_clk.clkr, 63 [MSS_AXI_NAV_CLK] = &mss_axi_nav_clk.clkr, 64 }; 65 66 static const struct qcom_cc_desc mss_sc7180_desc = { 67 .config = &mss_regmap_config, 68 .clks = mss_sc7180_clocks, 69 .num_clks = ARRAY_SIZE(mss_sc7180_clocks), 70 }; 71 72 static int mss_sc7180_probe(struct platform_device *pdev) 73 { 74 int ret; 75 76 pm_runtime_enable(&pdev->dev); 77 ret = pm_clk_create(&pdev->dev); 78 if (ret) 79 goto disable_pm_runtime; 80 81 ret = pm_clk_add(&pdev->dev, "cfg_ahb"); 82 if (ret < 0) { 83 dev_err(&pdev->dev, "failed to acquire iface clock\n"); 84 goto destroy_pm_clk; 85 } 86 87 ret = qcom_cc_probe(pdev, &mss_sc7180_desc); 88 if (ret < 0) 89 goto destroy_pm_clk; 90 91 return 0; 92 93 destroy_pm_clk: 94 pm_clk_destroy(&pdev->dev); 95 96 disable_pm_runtime: 97 pm_runtime_disable(&pdev->dev); 98 99 return ret; 100 } 101 102 static int mss_sc7180_remove(struct platform_device *pdev) 103 { 104 pm_clk_destroy(&pdev->dev); 105 pm_runtime_disable(&pdev->dev); 106 107 return 0; 108 } 109 110 static const struct dev_pm_ops mss_sc7180_pm_ops = { 111 SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) 112 }; 113 114 static const struct of_device_id mss_sc7180_match_table[] = { 115 { .compatible = "qcom,sc7180-mss" }, 116 { } 117 }; 118 MODULE_DEVICE_TABLE(of, mss_sc7180_match_table); 119 120 static struct platform_driver mss_sc7180_driver = { 121 .probe = mss_sc7180_probe, 122 .remove = mss_sc7180_remove, 123 .driver = { 124 .name = "sc7180-mss", 125 .of_match_table = mss_sc7180_match_table, 126 .pm = &mss_sc7180_pm_ops, 127 }, 128 }; 129 130 static int __init mss_sc7180_init(void) 131 { 132 return platform_driver_register(&mss_sc7180_driver); 133 } 134 subsys_initcall(mss_sc7180_init); 135 136 static void __exit mss_sc7180_exit(void) 137 { 138 platform_driver_unregister(&mss_sc7180_driver); 139 } 140 module_exit(mss_sc7180_exit); 141 142 MODULE_DESCRIPTION("QTI MSS SC7180 Driver"); 143 MODULE_LICENSE("GPL v2"); 144