186 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2021, The Linux Foundation. All rights reserved.4 */5 6#include <linux/clk-provider.h>7#include <linux/platform_device.h>8#include <linux/pm_clock.h>9#include <linux/pm_runtime.h>10#include <linux/module.h>11#include <linux/of_address.h>12#include <linux/regmap.h>13 14#include <dt-bindings/clock/qcom,lpass-sc7280.h>15 16#include "clk-regmap.h"17#include "clk-branch.h"18#include "common.h"19 20static struct clk_branch lpass_top_cc_lpi_q6_axim_hs_clk = {21 .halt_reg = 0x0,22 .halt_check = BRANCH_HALT,23 .clkr = {24 .enable_reg = 0x0,25 .enable_mask = BIT(0),26 .hw.init = &(struct clk_init_data){27 .name = "lpass_top_cc_lpi_q6_axim_hs_clk",28 .ops = &clk_branch2_ops,29 },30 },31};32 33static struct clk_branch lpass_qdsp6ss_core_clk = {34 .halt_reg = 0x20,35 /* CLK_OFF would not toggle until LPASS is out of reset */36 .halt_check = BRANCH_HALT_SKIP,37 .clkr = {38 .enable_reg = 0x20,39 .enable_mask = BIT(0),40 .hw.init = &(struct clk_init_data){41 .name = "lpass_qdsp6ss_core_clk",42 .ops = &clk_branch2_ops,43 },44 },45};46 47static struct clk_branch lpass_qdsp6ss_xo_clk = {48 .halt_reg = 0x38,49 /* CLK_OFF would not toggle until LPASS is out of reset */50 .halt_check = BRANCH_HALT_SKIP,51 .clkr = {52 .enable_reg = 0x38,53 .enable_mask = BIT(0),54 .hw.init = &(struct clk_init_data){55 .name = "lpass_qdsp6ss_xo_clk",56 .ops = &clk_branch2_ops,57 },58 },59};60 61static struct clk_branch lpass_qdsp6ss_sleep_clk = {62 .halt_reg = 0x3c,63 /* CLK_OFF would not toggle until LPASS is out of reset */64 .halt_check = BRANCH_HALT_SKIP,65 .clkr = {66 .enable_reg = 0x3c,67 .enable_mask = BIT(0),68 .hw.init = &(struct clk_init_data){69 .name = "lpass_qdsp6ss_sleep_clk",70 .ops = &clk_branch2_ops,71 },72 },73};74 75static struct regmap_config lpass_regmap_config = {76 .reg_bits = 32,77 .reg_stride = 4,78 .val_bits = 32,79 .fast_io = true,80};81 82static struct clk_regmap *lpass_cc_top_sc7280_clocks[] = {83 [LPASS_TOP_CC_LPI_Q6_AXIM_HS_CLK] =84 &lpass_top_cc_lpi_q6_axim_hs_clk.clkr,85};86 87static const struct qcom_cc_desc lpass_cc_top_sc7280_desc = {88 .config = &lpass_regmap_config,89 .clks = lpass_cc_top_sc7280_clocks,90 .num_clks = ARRAY_SIZE(lpass_cc_top_sc7280_clocks),91};92 93static struct clk_regmap *lpass_qdsp6ss_sc7280_clocks[] = {94 [LPASS_QDSP6SS_XO_CLK] = &lpass_qdsp6ss_xo_clk.clkr,95 [LPASS_QDSP6SS_SLEEP_CLK] = &lpass_qdsp6ss_sleep_clk.clkr,96 [LPASS_QDSP6SS_CORE_CLK] = &lpass_qdsp6ss_core_clk.clkr,97};98 99static const struct qcom_cc_desc lpass_qdsp6ss_sc7280_desc = {100 .config = &lpass_regmap_config,101 .clks = lpass_qdsp6ss_sc7280_clocks,102 .num_clks = ARRAY_SIZE(lpass_qdsp6ss_sc7280_clocks),103};104 105static int lpass_cc_sc7280_probe(struct platform_device *pdev)106{107 const struct qcom_cc_desc *desc;108 int ret;109 110 ret = devm_pm_runtime_enable(&pdev->dev);111 if (ret)112 return ret;113 114 ret = pm_clk_create(&pdev->dev);115 if (ret)116 return ret;117 118 ret = pm_clk_add(&pdev->dev, "iface");119 if (ret < 0) {120 dev_err(&pdev->dev, "failed to acquire iface clock\n");121 goto err_destroy_pm_clk;122 }123 124 ret = pm_runtime_resume_and_get(&pdev->dev);125 if (ret)126 goto err_destroy_pm_clk;127 128 if (!of_property_read_bool(pdev->dev.of_node, "qcom,adsp-pil-mode")) {129 lpass_regmap_config.name = "qdsp6ss";130 lpass_regmap_config.max_register = 0x3f;131 desc = &lpass_qdsp6ss_sc7280_desc;132 133 ret = qcom_cc_probe_by_index(pdev, 0, desc);134 if (ret)135 goto err_put_rpm;136 }137 138 lpass_regmap_config.name = "top_cc";139 lpass_regmap_config.max_register = 0x4;140 desc = &lpass_cc_top_sc7280_desc;141 142 ret = qcom_cc_probe_by_index(pdev, 1, desc);143 if (ret)144 goto err_put_rpm;145 146 pm_runtime_put(&pdev->dev);147 148 return 0;149 150err_put_rpm:151 pm_runtime_put_sync(&pdev->dev);152err_destroy_pm_clk:153 pm_clk_destroy(&pdev->dev);154 155 return ret;156}157 158static const struct of_device_id lpass_cc_sc7280_match_table[] = {159 { .compatible = "qcom,sc7280-lpasscc" },160 { }161};162MODULE_DEVICE_TABLE(of, lpass_cc_sc7280_match_table);163 164static struct platform_driver lpass_cc_sc7280_driver = {165 .probe = lpass_cc_sc7280_probe,166 .driver = {167 .name = "sc7280-lpasscc",168 .of_match_table = lpass_cc_sc7280_match_table,169 },170};171 172static int __init lpass_cc_sc7280_init(void)173{174 return platform_driver_register(&lpass_cc_sc7280_driver);175}176subsys_initcall(lpass_cc_sc7280_init);177 178static void __exit lpass_cc_sc7280_exit(void)179{180 platform_driver_unregister(&lpass_cc_sc7280_driver);181}182module_exit(lpass_cc_sc7280_exit);183 184MODULE_DESCRIPTION("QTI LPASS_CC SC7280 Driver");185MODULE_LICENSE("GPL v2");186