169 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2019, Linaro Ltd.4 */5 6#include <linux/bitops.h>7#include <linux/clk-provider.h>8#include <linux/err.h>9#include <linux/platform_device.h>10#include <linux/module.h>11#include <linux/of_address.h>12#include <linux/pm_clock.h>13#include <linux/pm_runtime.h>14#include <linux/regmap.h>15 16#include <dt-bindings/clock/qcom,turingcc-qcs404.h>17 18#include "clk-regmap.h"19#include "clk-branch.h"20#include "common.h"21#include "reset.h"22 23static struct clk_branch turing_wrapper_aon_cbcr = {24 .halt_reg = 0x5098,25 .halt_check = BRANCH_HALT,26 .clkr = {27 .enable_reg = 0x5098,28 .enable_mask = BIT(0),29 .hw.init = &(struct clk_init_data) {30 .name = "turing_wrapper_aon_clk",31 .ops = &clk_branch2_aon_ops,32 },33 },34};35 36static struct clk_branch turing_q6ss_ahbm_aon_cbcr = {37 .halt_reg = 0x9000,38 .halt_check = BRANCH_HALT,39 .clkr = {40 .enable_reg = 0x9000,41 .enable_mask = BIT(0),42 .hw.init = &(struct clk_init_data) {43 .name = "turing_q6ss_ahbm_aon_cbcr",44 .ops = &clk_branch2_ops,45 },46 },47};48 49static struct clk_branch turing_q6ss_q6_axim_clk = {50 .halt_reg = 0xb000,51 .halt_check = BRANCH_HALT,52 .clkr = {53 .enable_reg = 0xb000,54 .enable_mask = BIT(0),55 .hw.init = &(struct clk_init_data) {56 .name = "turing_q6ss_q6_axim_clk",57 .ops = &clk_branch2_aon_ops,58 },59 },60};61 62static struct clk_branch turing_q6ss_ahbs_aon_cbcr = {63 .halt_reg = 0x10000,64 .halt_check = BRANCH_HALT,65 .clkr = {66 .enable_reg = 0x10000,67 .enable_mask = BIT(0),68 .hw.init = &(struct clk_init_data) {69 .name = "turing_q6ss_ahbs_aon_clk",70 .ops = &clk_branch2_aon_ops,71 },72 },73};74 75static struct clk_branch turing_wrapper_qos_ahbs_aon_cbcr = {76 .halt_reg = 0x11014,77 .halt_check = BRANCH_HALT,78 .clkr = {79 .enable_reg = 0x11014,80 .enable_mask = BIT(0),81 .hw.init = &(struct clk_init_data) {82 .name = "turing_wrapper_qos_ahbs_aon_clk",83 .ops = &clk_branch2_aon_ops,84 },85 },86};87 88static struct clk_regmap *turingcc_clocks[] = {89 [TURING_WRAPPER_AON_CLK] = &turing_wrapper_aon_cbcr.clkr,90 [TURING_Q6SS_AHBM_AON_CLK] = &turing_q6ss_ahbm_aon_cbcr.clkr,91 [TURING_Q6SS_Q6_AXIM_CLK] = &turing_q6ss_q6_axim_clk.clkr,92 [TURING_Q6SS_AHBS_AON_CLK] = &turing_q6ss_ahbs_aon_cbcr.clkr,93 [TURING_WRAPPER_QOS_AHBS_AON_CLK] = &turing_wrapper_qos_ahbs_aon_cbcr.clkr,94};95 96static const struct regmap_config turingcc_regmap_config = {97 .reg_bits = 32,98 .reg_stride = 4,99 .val_bits = 32,100 .max_register = 0x23004,101 .fast_io = true,102};103 104static const struct qcom_cc_desc turingcc_desc = {105 .config = &turingcc_regmap_config,106 .clks = turingcc_clocks,107 .num_clks = ARRAY_SIZE(turingcc_clocks),108};109 110static int turingcc_probe(struct platform_device *pdev)111{112 int ret;113 114 ret = devm_pm_runtime_enable(&pdev->dev);115 if (ret)116 return ret;117 118 ret = devm_pm_clk_create(&pdev->dev);119 if (ret)120 return ret;121 122 ret = pm_clk_add(&pdev->dev, NULL);123 if (ret < 0) {124 dev_err(&pdev->dev, "failed to acquire iface clock\n");125 return ret;126 }127 128 ret = pm_runtime_resume_and_get(&pdev->dev);129 if (ret)130 return ret;131 132 ret = qcom_cc_probe(pdev, &turingcc_desc);133 if (ret < 0)134 goto err_put_rpm;135 136 pm_runtime_put(&pdev->dev);137 138 return 0;139 140err_put_rpm:141 pm_runtime_put_sync(&pdev->dev);142 143 return ret;144}145 146static const struct dev_pm_ops turingcc_pm_ops = {147 SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)148};149 150static const struct of_device_id turingcc_match_table[] = {151 { .compatible = "qcom,qcs404-turingcc" },152 { }153};154MODULE_DEVICE_TABLE(of, turingcc_match_table);155 156static struct platform_driver turingcc_driver = {157 .probe = turingcc_probe,158 .driver = {159 .name = "qcs404-turingcc",160 .of_match_table = turingcc_match_table,161 .pm = &turingcc_pm_ops,162 },163};164 165module_platform_driver(turingcc_driver);166 167MODULE_DESCRIPTION("Qualcomm QCS404 Turing Clock Controller");168MODULE_LICENSE("GPL v2");169