summaryrefslogtreecommitdiff
path: root/drivers/clk/qcom/lpasscc-sc7280.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-11-03 21:18:44 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-11-03 21:18:44 -0700
commit7ddb58cb0ecae8e8b6181d736a87667cc9ab8389 (patch)
tree8f0362989419ba74174bb46453225e2cc1e603e3 /drivers/clk/qcom/lpasscc-sc7280.c
parentce840177930f591a181f55515fc6ac9e1f56b84a (diff)
parente2ceaa867d266472b31f3e03ba16f3120aefc152 (diff)
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd: "The usual collection of clk driver updates and new driver additions. In terms of lines it's mainly Qualcomm and Mediatek code, supporting various SoCs and their multitude of clk controllers. New Drivers: - GCC and RPMcc support for Qualcomm QCM2290 SoCs - GCC support for Qualcomm MSM8994/MSM8992 SoCs - LPASSCC and CAMCC support for Qualcomm SC7280 SoCs - Support for Mediatek MT8195 SoCs - Initial clock driver for the Exynos850 SoC - Add i.MX8ULP clock driver and related bindings Updates: - Clock power management for new SAMA7G5 SoC - Updates to the master clock driver and sam9x60-pll to be able to use cpufreq-dt driver and avoid overclocking of CPU and MCK0 domains while changing the frequency via DVFS - Use ARRAY_SIZE in qcom clk drivers - Remove some impractical fallback parent names in qcom clk drivers - Make Mediatek clk drivers tristate - Refactoring of the CPU clock code and conversion of Samsung Exynos5433 CPU clock driver to the platform driver - A few conversions to devm_platform_ioremap_resource() - Updates of the Samsung Kconfig help text - Update video path realted clocks for Amlogic meson8 - Add SPI Multi I/O Bus and SDHI clocks and resets on Renesas RZ/G2L - Add SPI Multi I/O Bus (RPC) clocks on Renesas R-Car V3U - Add MediaLB clocks on Renesas R-Car H3, M3-W/W+, and M3-N - Remove unused helpers from i.MX specific clock header - Rework all i.MX clk based helpers to use clk_hw based ones - Rework i.MX gate/mux/divider wrappers - Rework imx_clk_hw_composite and imx_clk_hw_pll14xx wrappers - Update i.MX pllv4 and composite clocks to support i.MX8ULP - Disable i.MX7ULP composite clock during initialization - Add CLK_SET_RATE_NO_REPARENT flag to the i.MX7ULP composite - Disable the i.MX pfd when set pfdv2 clock rate - Add support for i.MX8ULP in pfdv2 - Add the pcc reset controller support on i.MX8ULP - Fix the build break when clk-imx8ulp is built as module - Move csi_sel mux to correct base register in i.MX6UL clock drivr - Fix csi clk gate register in i.MX6UL clock driver - Fix build bug making CLK_IMX8ULP select MXC_CLK - Add TPU (PWM), and Z (Cortex-A76) clocks on Renesas R-Car V3U - Add Ethernet clocks on Renesas RZ/G2L - Move Rockchip to use module_platform_probe - Enable usage of Coresight related clocks on Rockchip rk3399" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (170 commits) clk: use clk_core_get_rate_recalc() in clk_rate_get() clk: at91: sama7g5: set low limit for mck0 at 32KHz clk: at91: sama7g5: remove prescaler part of master clock clk: at91: clk-master: add notifier for divider clk: at91: clk-sam9x60-pll: add notifier for div part of PLL clk: at91: clk-master: fix prescaler logic clk: at91: clk-master: mask mckr against layout->mask clk: at91: clk-master: check if div or pres is zero clk: at91: sam9x60-pll: use DIV_ROUND_CLOSEST_ULL clk: at91: pmc: add sama7g5 to the list of available pmcs clk: at91: clk-master: improve readability by using local variables clk: at91: clk-master: add register definition for sama7g5's master clock clk: at91: sama7g5: add securam's peripheral clock clk: at91: pmc: execute suspend/resume only for backup mode clk: at91: re-factor clocks suspend/resume clk: ux500: Add driver for the reset portions of PRCC dt-bindings: clock: u8500: Rewrite in YAML and extend clk: composite: Use rate_ops.determine_rate when also a mux is available clk: samsung: describe drivers in Kconfig clk: samsung: exynos5433: update apollo and atlas clock probing ...
Diffstat (limited to 'drivers/clk/qcom/lpasscc-sc7280.c')
-rw-r--r--drivers/clk/qcom/lpasscc-sc7280.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/drivers/clk/qcom/lpasscc-sc7280.c b/drivers/clk/qcom/lpasscc-sc7280.c
new file mode 100644
index 000000000000..89f1ad6631da
--- /dev/null
+++ b/drivers/clk/qcom/lpasscc-sc7280.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lpass-sc7280.h>
+
+#include "clk-regmap.h"
+#include "clk-branch.h"
+#include "common.h"
+
+static struct clk_branch lpass_q6ss_ahbm_clk = {
+ .halt_reg = 0x1c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "lpass_q6ss_ahbm_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch lpass_q6ss_ahbs_clk = {
+ .halt_reg = 0x20,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x20,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "lpass_q6ss_ahbs_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch lpass_top_cc_lpi_q6_axim_hs_clk = {
+ .halt_reg = 0x0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "lpass_top_cc_lpi_q6_axim_hs_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch lpass_qdsp6ss_core_clk = {
+ .halt_reg = 0x20,
+ /* CLK_OFF would not toggle until LPASS is out of reset */
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x20,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "lpass_qdsp6ss_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch lpass_qdsp6ss_xo_clk = {
+ .halt_reg = 0x38,
+ /* CLK_OFF would not toggle until LPASS is out of reset */
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x38,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "lpass_qdsp6ss_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch lpass_qdsp6ss_sleep_clk = {
+ .halt_reg = 0x3c,
+ /* CLK_OFF would not toggle until LPASS is out of reset */
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x3c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "lpass_qdsp6ss_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct regmap_config lpass_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+};
+
+static struct clk_regmap *lpass_cc_sc7280_clocks[] = {
+ [LPASS_Q6SS_AHBM_CLK] = &lpass_q6ss_ahbm_clk.clkr,
+ [LPASS_Q6SS_AHBS_CLK] = &lpass_q6ss_ahbs_clk.clkr,
+};
+
+static const struct qcom_cc_desc lpass_cc_sc7280_desc = {
+ .config = &lpass_regmap_config,
+ .clks = lpass_cc_sc7280_clocks,
+ .num_clks = ARRAY_SIZE(lpass_cc_sc7280_clocks),
+};
+
+static struct clk_regmap *lpass_cc_top_sc7280_clocks[] = {
+ [LPASS_TOP_CC_LPI_Q6_AXIM_HS_CLK] =
+ &lpass_top_cc_lpi_q6_axim_hs_clk.clkr,
+};
+
+static const struct qcom_cc_desc lpass_cc_top_sc7280_desc = {
+ .config = &lpass_regmap_config,
+ .clks = lpass_cc_top_sc7280_clocks,
+ .num_clks = ARRAY_SIZE(lpass_cc_top_sc7280_clocks),
+};
+
+static struct clk_regmap *lpass_qdsp6ss_sc7280_clocks[] = {
+ [LPASS_QDSP6SS_XO_CLK] = &lpass_qdsp6ss_xo_clk.clkr,
+ [LPASS_QDSP6SS_SLEEP_CLK] = &lpass_qdsp6ss_sleep_clk.clkr,
+ [LPASS_QDSP6SS_CORE_CLK] = &lpass_qdsp6ss_core_clk.clkr,
+};
+
+static const struct qcom_cc_desc lpass_qdsp6ss_sc7280_desc = {
+ .config = &lpass_regmap_config,
+ .clks = lpass_qdsp6ss_sc7280_clocks,
+ .num_clks = ARRAY_SIZE(lpass_qdsp6ss_sc7280_clocks),
+};
+
+static int lpass_cc_sc7280_probe(struct platform_device *pdev)
+{
+ const struct qcom_cc_desc *desc;
+ int ret;
+
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_clk_create(&pdev->dev);
+ if (ret)
+ goto disable_pm_runtime;
+
+ ret = pm_clk_add(&pdev->dev, "iface");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to acquire iface clock\n");
+ goto destroy_pm_clk;
+ }
+
+ lpass_regmap_config.name = "qdsp6ss";
+ desc = &lpass_qdsp6ss_sc7280_desc;
+
+ ret = qcom_cc_probe_by_index(pdev, 0, desc);
+ if (ret)
+ goto destroy_pm_clk;
+
+ lpass_regmap_config.name = "top_cc";
+ desc = &lpass_cc_top_sc7280_desc;
+
+ ret = qcom_cc_probe_by_index(pdev, 1, desc);
+ if (ret)
+ goto destroy_pm_clk;
+
+ lpass_regmap_config.name = "cc";
+ desc = &lpass_cc_sc7280_desc;
+
+ ret = qcom_cc_probe_by_index(pdev, 2, desc);
+ if (ret)
+ goto destroy_pm_clk;
+
+ return 0;
+
+destroy_pm_clk:
+ pm_clk_destroy(&pdev->dev);
+
+disable_pm_runtime:
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static const struct of_device_id lpass_cc_sc7280_match_table[] = {
+ { .compatible = "qcom,sc7280-lpasscc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpass_cc_sc7280_match_table);
+
+static struct platform_driver lpass_cc_sc7280_driver = {
+ .probe = lpass_cc_sc7280_probe,
+ .driver = {
+ .name = "sc7280-lpasscc",
+ .of_match_table = lpass_cc_sc7280_match_table,
+ },
+};
+
+static int __init lpass_cc_sc7280_init(void)
+{
+ return platform_driver_register(&lpass_cc_sc7280_driver);
+}
+subsys_initcall(lpass_cc_sc7280_init);
+
+static void __exit lpass_cc_sc7280_exit(void)
+{
+ platform_driver_unregister(&lpass_cc_sc7280_driver);
+}
+module_exit(lpass_cc_sc7280_exit);
+
+MODULE_DESCRIPTION("QTI LPASS_CC SC7280 Driver");
+MODULE_LICENSE("GPL v2");