* Re: [PATCH v2 8/8] arm64: dts: qcom: eliza: Add support for MM clock controllers
From: Bryan O'Donoghue @ 2026-04-09 18:40 UTC (permalink / raw)
To: Taniya Das, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Maxime Coquelin, Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-8-bc0c6dd77bc5@oss.qualcomm.com>
On 09/04/2026 19:10, Taniya Das wrote:
> + videocc: clock-controller@aaf0000 {
> + compatible = "qcom,eliza-videocc";
> + reg = <0x0 0xaaf0000 0x0 0x10000>;
> +
> + clocks = <&bi_tcxo_div2>,
> + <&sleep_clk>,
> + <&gcc GCC_VIDEO_AHB_CLK>;
> +
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + #power-domain-cells = <1>;
> + };
> +
> + camcc: clock-controller@ade0000 {
> + compatible = "qcom,eliza-camcc";
> + reg = <0x0 0x0ade0000 0x0 0x20000>;
> +
> + clocks = <&gcc GCC_CAMERA_AHB_CLK>,
> + <&bi_tcxo_div2>,
> + <&sleep_clk>;
> +
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + };
This looks odd.
Why do these two controllers have no power-domains ?
---
bod
^ permalink raw reply
* [PATCH] arm64: dts: qcom: Drop unused remoteproc_adsp_glink label
From: Mukesh Ojha @ 2026-04-09 18:13 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, devicetree, linux-kernel, Mukesh Ojha
The remoteproc_adsp_glink label on the ADSP glink-edge node has no
users in the upstream tree across all affected SoCs. The only user
of this label is qcs6490-audioreach.dtsi which references the label
defined in its own SoC dtsi and is left untouched.
Remove the label from kaanapali, kodiak, lemans, monaco,
sar2130p, sc8180x, sc8280xp, sm8450, sm8550, sm8650 and sm8750.
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
Not sure, if these should be individual patches..
arch/arm64/boot/dts/qcom/kaanapali.dtsi | 2 +-
arch/arm64/boot/dts/qcom/lemans.dtsi | 2 +-
arch/arm64/boot/dts/qcom/monaco.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sar2130p.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sc8180x.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sm8750.dtsi | 2 +-
10 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/kaanapali.dtsi b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
index 7cc326aa1a1a..39aad33f42c5 100644
--- a/arch/arm64/boot/dts/qcom/kaanapali.dtsi
+++ b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
@@ -2634,7 +2634,7 @@ remoteproc_adsp: remoteproc@6800000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_MPROC_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index fe6e76351823..c5976e19fc4a 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -7483,7 +7483,7 @@ remoteproc_adsp: remoteproc@30000000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 7b1d57460f1e..e44a42173d2d 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -2795,7 +2795,7 @@ remoteproc_adsp: remoteproc@3000000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/sar2130p.dtsi b/arch/arm64/boot/dts/qcom/sar2130p.dtsi
index d65ad0df6865..3c9529bb2f76 100644
--- a/arch/arm64/boot/dts/qcom/sar2130p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sar2130p.dtsi
@@ -1612,7 +1612,7 @@ remoteproc_adsp: remoteproc@3000000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi
index f45deb188c6c..6d36d377e05e 100644
--- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi
@@ -3755,7 +3755,7 @@ remoteproc_adsp: remoteproc@17300000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
label = "lpass";
qcom,remote-pid = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
index 761f229e8f47..416991bf9cba 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
@@ -2956,7 +2956,7 @@ remoteproc_adsp: remoteproc@3000000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 03bf30b53f28..ffc4ab021ad7 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -2798,7 +2798,7 @@ remoteproc_adsp: remoteproc@3000000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi
index 912525e9bca6..e5dc3dc19f04 100644
--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi
@@ -2797,7 +2797,7 @@ remoteproc_adsp: remoteproc@6800000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi
index 1604bc8cff37..a4b71fd3ca14 100644
--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi
@@ -4486,7 +4486,7 @@ remoteproc_adsp: remoteproc@6800000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi
index 18fb52c14acd..63fcc6c749a5 100644
--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi
@@ -2217,7 +2217,7 @@ remoteproc_adsp: remoteproc@6800000 {
status = "disabled";
- remoteproc_adsp_glink: glink-edge {
+ glink-edge {
interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
IPCC_MPROC_SIGNAL_GLINK_QMP
IRQ_TYPE_EDGE_RISING>;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 8/8] arm64: dts: qcom: eliza: Add support for MM clock controllers
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Add the device nodes for the multimedia clock controllers (cambistmclkcc,
camcc, videocc, gpucc) for Qualcomm Eliza SoC.
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/eliza.dtsi | 54 +++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/eliza.dtsi b/arch/arm64/boot/dts/qcom/eliza.dtsi
index 4a7a0ac40ce6252a138bed06c7c190ada3ea61a3..7a2a3dba86b9395743781cdf724e81733140ecd0 100644
--- a/arch/arm64/boot/dts/qcom/eliza.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza.dtsi
@@ -709,6 +709,18 @@ aggre2_noc: interconnect@1700000 {
#interconnect-cells = <2>;
};
+ cambistmclkcc: clock-controller@1760000 {
+ compatible = "qcom,eliza-cambistmclkcc";
+ reg = <0x0 0x01760000 0x0 0x6000>;
+
+ clocks = <&gcc GCC_CAM_BIST_MCLK_AHB_CLK>,
+ <&bi_tcxo_div2>,
+ <&sleep_clk>;
+
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
mmss_noc: interconnect@1780000 {
compatible = "qcom,eliza-mmss-noc";
reg = <0x0 0x01780000 0x0 0x7d800>;
@@ -862,6 +874,23 @@ tcsr: clock-controller@1fbf000 {
#reset-cells = <1>;
};
+ gpucc: clock-controller@3d90000 {
+ compatible = "qcom,eliza-gpucc";
+ reg = <0x0 0x03d90000 0x0 0xa000>;
+
+ clocks = <&bi_tcxo_div2>,
+ <&gcc GCC_GPU_GPLL0_CPH_CLK_SRC>,
+ <&gcc GCC_GPU_GPLL0_DIV_CPH_CLK_SRC>;
+
+ power-domains = <&rpmhpd RPMHPD_MX>,
+ <&rpmhpd RPMHPD_CX>;
+ required-opps = <&rpmhpd_opp_low_svs>,
+ <&rpmhpd_opp_low_svs>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
lpass_ag_noc: interconnect@7e40000 {
compatible = "qcom,eliza-lpass-ag-noc";
reg = <0x0 0x07e40000 0x0 0xe080>;
@@ -883,6 +912,31 @@ lpass_lpicx_noc: interconnect@7420000 {
#interconnect-cells = <2>;
};
+ videocc: clock-controller@aaf0000 {
+ compatible = "qcom,eliza-videocc";
+ reg = <0x0 0xaaf0000 0x0 0x10000>;
+
+ clocks = <&bi_tcxo_div2>,
+ <&sleep_clk>,
+ <&gcc GCC_VIDEO_AHB_CLK>;
+
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+ camcc: clock-controller@ade0000 {
+ compatible = "qcom,eliza-camcc";
+ reg = <0x0 0x0ade0000 0x0 0x20000>;
+
+ clocks = <&gcc GCC_CAMERA_AHB_CLK>,
+ <&bi_tcxo_div2>,
+ <&sleep_clk>;
+
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
pdc: interrupt-controller@b220000 {
compatible = "qcom,eliza-pdc", "qcom,pdc";
reg = <0x0 0x0b220000 0x0 0x40000>,
--
2.34.1
^ permalink raw reply related
* [PATCH v2 7/8] arm64: defconfig: Enable clock controllers on Qualcomm Eliza SoC
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Enable the video, camera and gpu clock controllers for their respective
functionalities on the Qualcomm Eliza MTP board.
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
arch/arm64/configs/defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index dd1ac01ee29bf631d517c38486f6896ffd82dcc9..130e8716e67d69c54cde3f66db09b352f736feaf 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1475,9 +1475,12 @@ CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y
CONFIG_COMMON_CLK_MT8192_VDECSYS=y
CONFIG_COMMON_CLK_MT8192_VENCSYS=y
CONFIG_COMMON_CLK_QCOM=y
+CONFIG_CLK_ELIZA_CAMCC=m
CONFIG_CLK_ELIZA_DISPCC=m
CONFIG_CLK_ELIZA_GCC=y
+CONFIG_CLK_ELIZA_GPUCC=m
CONFIG_CLK_ELIZA_TCSRCC=m
+CONFIG_CLK_ELIZA_VIDEOCC=m
CONFIG_CLK_GLYMUR_DISPCC=m
CONFIG_CLK_GLYMUR_GCC=y
CONFIG_CLK_GLYMUR_TCSRCC=m
--
2.34.1
^ permalink raw reply related
* [PATCH v2 6/8] clk: qcom: camcc: Add support for camera clock controller for Eliza
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das, Konrad Dybcio
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Add support for the Camera Clock Controller (CAMCC) on the Eliza
platform.
The CAMCC block on Eliza includes both the primary camera clock
controller and the Camera BIST clock controller, which provides the
functional MCLK required for camera operations.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
drivers/clk/qcom/Kconfig | 10 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/cambistmclkcc-eliza.c | 465 ++++++
drivers/clk/qcom/camcc-eliza.c | 2803 ++++++++++++++++++++++++++++++++
4 files changed, 3279 insertions(+)
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 7626dfa536ece08e88ad198d8fa60972f06f14d5..3a8b4922ee3745f172922faa3e0316972ec7052f 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -19,6 +19,16 @@ menuconfig COMMON_CLK_QCOM
if COMMON_CLK_QCOM
+config CLK_ELIZA_CAMCC
+ tristate "Eliza Camera Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select CLK_ELIZA_GCC
+ help
+ Support for the camera clock controller on Qualcomm Technologies, Inc
+ Eliza devices.
+ Say Y if you want to support camera devices and functionality such as
+ capturing pictures.
+
config CLK_ELIZA_DISPCC
tristate "Eliza Display Clock Controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 1c34797eb385963110614ba43eb9bbc9653699fb..12574157b7c8a82c890996502f79da03f25cfaa2 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -20,6 +20,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
# Keep alphabetically sorted by config
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
+obj-$(CONFIG_CLK_ELIZA_CAMCC) += cambistmclkcc-eliza.o camcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_DISPCC) += dispcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_GCC) += gcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_GPUCC) += gpucc-eliza.o
diff --git a/drivers/clk/qcom/cambistmclkcc-eliza.c b/drivers/clk/qcom/cambistmclkcc-eliza.c
new file mode 100644
index 0000000000000000000000000000000000000000..3fda22ad13c91aeff68947d4f68154c263a8e321
--- /dev/null
+++ b/drivers/clk/qcom/cambistmclkcc-eliza.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,eliza-cambistmclkcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+ DT_AHB_CLK,
+ DT_BI_TCXO,
+ DT_SLEEP_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN,
+ P_CAM_BIST_MCLK_CC_PLL0_OUT_MAIN,
+ P_SLEEP_CLK,
+};
+
+static const struct pll_vco rivian_ole_vco[] = {
+ { 777000000, 1285000000, 0 },
+};
+
+/* 960.0 MHz Configuration */
+static const struct alpha_pll_config cam_bist_mclk_cc_pll0_config = {
+ .l = 0x32,
+ .cal_l = 0x32,
+ .alpha = 0x0,
+ .config_ctl_val = 0x10000030,
+ .config_ctl_hi_val = 0x80890263,
+ .config_ctl_hi1_val = 0x00000217,
+ .user_ctl_val = 0x00000001,
+ .user_ctl_hi_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_bist_mclk_cc_pll0 = {
+ .offset = 0x0,
+ .config = &cam_bist_mclk_cc_pll0_config,
+ .vco_table = rivian_ole_vco,
+ .num_vco = ARRAY_SIZE(rivian_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_RIVIAN_EVO],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_rivian_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map cam_bist_mclk_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN, 3 },
+ { P_CAM_BIST_MCLK_CC_PLL0_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data cam_bist_mclk_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_bist_mclk_cc_pll0.clkr.hw },
+ { .hw = &cam_bist_mclk_cc_pll0.clkr.hw },
+};
+
+static const struct parent_map cam_bist_mclk_cc_parent_map_1[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data cam_bist_mclk_cc_parent_data_1[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct freq_tbl ftbl_cam_bist_mclk_cc_mclk0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(24000000, P_CAM_BIST_MCLK_CC_PLL0_OUT_EVEN, 10, 1, 4),
+ F(68571429, P_CAM_BIST_MCLK_CC_PLL0_OUT_MAIN, 14, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk0_clk_src = {
+ .cmd_rcgr = 0x4000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk0_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk1_clk_src = {
+ .cmd_rcgr = 0x401c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk1_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk2_clk_src = {
+ .cmd_rcgr = 0x4038,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk2_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk3_clk_src = {
+ .cmd_rcgr = 0x4054,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk3_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk4_clk_src = {
+ .cmd_rcgr = 0x4070,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk4_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk5_clk_src = {
+ .cmd_rcgr = 0x408c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk5_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk6_clk_src = {
+ .cmd_rcgr = 0x40a8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk6_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_mclk7_clk_src = {
+ .cmd_rcgr = 0x40c4,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk7_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_bist_mclk_cc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_bist_mclk_cc_sleep_clk_src = {
+ .cmd_rcgr = 0x40e0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_bist_mclk_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_bist_mclk_cc_sleep_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_sleep_clk_src",
+ .parent_data = cam_bist_mclk_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_bist_mclk_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk0_clk = {
+ .halt_reg = 0x4018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk1_clk = {
+ .halt_reg = 0x4034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk2_clk = {
+ .halt_reg = 0x4050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk3_clk = {
+ .halt_reg = 0x406c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x406c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk4_clk = {
+ .halt_reg = 0x4088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk5_clk = {
+ .halt_reg = 0x40a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x40a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk6_clk = {
+ .halt_reg = 0x40c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x40c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_bist_mclk_cc_mclk7_clk = {
+ .halt_reg = 0x40dc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x40dc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_bist_mclk_cc_mclk7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_bist_mclk_cc_mclk7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *cam_bist_mclk_cc_eliza_clocks[] = {
+ [CAM_BIST_MCLK_CC_MCLK0_CLK] = &cam_bist_mclk_cc_mclk0_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK0_CLK_SRC] = &cam_bist_mclk_cc_mclk0_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK1_CLK] = &cam_bist_mclk_cc_mclk1_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK1_CLK_SRC] = &cam_bist_mclk_cc_mclk1_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK2_CLK] = &cam_bist_mclk_cc_mclk2_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK2_CLK_SRC] = &cam_bist_mclk_cc_mclk2_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK3_CLK] = &cam_bist_mclk_cc_mclk3_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK3_CLK_SRC] = &cam_bist_mclk_cc_mclk3_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK4_CLK] = &cam_bist_mclk_cc_mclk4_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK4_CLK_SRC] = &cam_bist_mclk_cc_mclk4_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK5_CLK] = &cam_bist_mclk_cc_mclk5_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK5_CLK_SRC] = &cam_bist_mclk_cc_mclk5_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK6_CLK] = &cam_bist_mclk_cc_mclk6_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK6_CLK_SRC] = &cam_bist_mclk_cc_mclk6_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_MCLK7_CLK] = &cam_bist_mclk_cc_mclk7_clk.clkr,
+ [CAM_BIST_MCLK_CC_MCLK7_CLK_SRC] = &cam_bist_mclk_cc_mclk7_clk_src.clkr,
+ [CAM_BIST_MCLK_CC_PLL0] = &cam_bist_mclk_cc_pll0.clkr,
+ [CAM_BIST_MCLK_CC_SLEEP_CLK_SRC] = &cam_bist_mclk_cc_sleep_clk_src.clkr,
+};
+
+static struct clk_alpha_pll *cam_bist_mclk_cc_eliza_plls[] = {
+ &cam_bist_mclk_cc_pll0,
+};
+
+static u32 cam_bist_mclk_cc_eliza_critical_cbcrs[] = {
+ 0x40f8, /* CAM_BIST_MCLK_CC_SLEEP_CLK */
+};
+
+static const struct regmap_config cam_bist_mclk_cc_eliza_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x5010,
+ .fast_io = true,
+};
+
+static struct qcom_cc_driver_data cam_bist_mclk_cc_eliza_driver_data = {
+ .alpha_plls = cam_bist_mclk_cc_eliza_plls,
+ .num_alpha_plls = ARRAY_SIZE(cam_bist_mclk_cc_eliza_plls),
+ .clk_cbcrs = cam_bist_mclk_cc_eliza_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(cam_bist_mclk_cc_eliza_critical_cbcrs),
+};
+
+static const struct qcom_cc_desc cam_bist_mclk_cc_eliza_desc = {
+ .config = &cam_bist_mclk_cc_eliza_regmap_config,
+ .clks = cam_bist_mclk_cc_eliza_clocks,
+ .num_clks = ARRAY_SIZE(cam_bist_mclk_cc_eliza_clocks),
+ .use_rpm = true,
+ .driver_data = &cam_bist_mclk_cc_eliza_driver_data,
+};
+
+static const struct of_device_id cam_bist_mclk_cc_eliza_match_table[] = {
+ { .compatible = "qcom,eliza-cambistmclkcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cam_bist_mclk_cc_eliza_match_table);
+
+static int cam_bist_mclk_cc_eliza_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &cam_bist_mclk_cc_eliza_desc);
+}
+
+static struct platform_driver cam_bist_mclk_cc_eliza_driver = {
+ .probe = cam_bist_mclk_cc_eliza_probe,
+ .driver = {
+ .name = "cambistmclkcc-eliza",
+ .of_match_table = cam_bist_mclk_cc_eliza_match_table,
+ },
+};
+
+module_platform_driver(cam_bist_mclk_cc_eliza_driver);
+
+MODULE_DESCRIPTION("QTI CAMBISTMCLKCC Eliza Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/camcc-eliza.c b/drivers/clk/qcom/camcc-eliza.c
new file mode 100644
index 0000000000000000000000000000000000000000..52cef1827ffb43b82c68234349baa1988d7a1527
--- /dev/null
+++ b/drivers/clk/qcom/camcc-eliza.c
@@ -0,0 +1,2803 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,eliza-camcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_AHB_CLK,
+ DT_BI_TCXO,
+ DT_SLEEP_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_CAM_CC_PLL0_OUT_EVEN,
+ P_CAM_CC_PLL0_OUT_MAIN,
+ P_CAM_CC_PLL0_OUT_ODD,
+ P_CAM_CC_PLL1_OUT_EVEN,
+ P_CAM_CC_PLL2_OUT_EVEN,
+ P_CAM_CC_PLL3_OUT_EVEN,
+ P_CAM_CC_PLL4_OUT_EVEN,
+ P_CAM_CC_PLL5_OUT_EVEN,
+ P_CAM_CC_PLL6_OUT_EVEN,
+ P_CAM_CC_PLL6_OUT_ODD,
+ P_SLEEP_CLK,
+};
+
+static const struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2300000000, 0 },
+};
+
+/* 1200.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll0_config = {
+ .l = 0x3e,
+ .cal_l = 0x44,
+ .alpha = 0x8000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00008400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll0 = {
+ .offset = 0x0,
+ .config = &cam_cc_pll0_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll0_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = {
+ { 0x2, 3 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = {
+ .offset = 0x0,
+ .post_div_shift = 14,
+ .post_div_table = post_div_table_cam_cc_pll0_out_odd,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_odd),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll0_out_odd",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 900.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll1_config = {
+ .l = 0x2e,
+ .cal_l = 0x44,
+ .alpha = 0xe000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll1 = {
+ .offset = 0x1000,
+ .config = &cam_cc_pll1_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll1_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll1_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll1_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll1_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll1.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 872.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll2_config = {
+ .l = 0x2d,
+ .cal_l = 0x44,
+ .alpha = 0x6aaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll2 = {
+ .offset = 0x2000,
+ .config = &cam_cc_pll2_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll2",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll2_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll2_out_even = {
+ .offset = 0x2000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll2_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll2_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll2_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll2.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 890.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll3_config = {
+ .l = 0x2e,
+ .cal_l = 0x44,
+ .alpha = 0x5aaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll3 = {
+ .offset = 0x3000,
+ .config = &cam_cc_pll3_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll3",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
+ .offset = 0x3000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll3_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll3_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll3_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll3.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 890.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll4_config = {
+ .l = 0x2e,
+ .cal_l = 0x44,
+ .alpha = 0x5aaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll4 = {
+ .offset = 0x4000,
+ .config = &cam_cc_pll4_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll4",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll4_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = {
+ .offset = 0x4000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll4_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll4_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll4_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll4.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 890.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll5_config = {
+ .l = 0x2e,
+ .cal_l = 0x44,
+ .alpha = 0x5aaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll5 = {
+ .offset = 0x5000,
+ .config = &cam_cc_pll5_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll5",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll5_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = {
+ .offset = 0x5000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll5_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll5_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll5_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll5.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 960.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll6_config = {
+ .l = 0x32,
+ .cal_l = 0x44,
+ .alpha = 0x0,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00008400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll6 = {
+ .offset = 0x6000,
+ .config = &cam_cc_pll6_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll6",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll6_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = {
+ .offset = 0x6000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll6_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll6_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll6_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll6.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll6_out_odd[] = {
+ { 0x2, 3 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll6_out_odd = {
+ .offset = 0x6000,
+ .post_div_shift = 14,
+ .post_div_table = post_div_table_cam_cc_pll6_out_odd,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll6_out_odd),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll6_out_odd",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll6.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static const struct parent_map cam_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL0_OUT_MAIN, 1 },
+ { P_CAM_CC_PLL0_OUT_EVEN, 2 },
+ { P_CAM_CC_PLL0_OUT_ODD, 3 },
+ { P_CAM_CC_PLL6_OUT_ODD, 4 },
+ { P_CAM_CC_PLL6_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll0.clkr.hw },
+ { .hw = &cam_cc_pll0_out_even.clkr.hw },
+ { .hw = &cam_cc_pll0_out_odd.clkr.hw },
+ { .hw = &cam_cc_pll6_out_odd.clkr.hw },
+ { .hw = &cam_cc_pll6_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL0_OUT_MAIN, 1 },
+ { P_CAM_CC_PLL0_OUT_EVEN, 2 },
+ { P_CAM_CC_PLL0_OUT_ODD, 3 },
+ { P_CAM_CC_PLL6_OUT_ODD, 4 },
+ { P_CAM_CC_PLL6_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll0.clkr.hw },
+ { .hw = &cam_cc_pll0_out_even.clkr.hw },
+ { .hw = &cam_cc_pll0_out_odd.clkr.hw },
+ { .hw = &cam_cc_pll6_out_odd.clkr.hw },
+ { .hw = &cam_cc_pll6_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL1_OUT_EVEN, 4 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll1_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL2_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll2_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_4[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_4[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map cam_cc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL3_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll3_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL4_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll4_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL5_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll5_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct freq_tbl ftbl_cam_cc_camnoc_rt_axi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_camnoc_rt_axi_clk_src = {
+ .cmd_rcgr = 0x112e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_camnoc_rt_axi_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_axi_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = {
+ F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cci_0_clk_src = {
+ .cmd_rcgr = 0x1126c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_0_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_cci_1_clk_src = {
+ .cmd_rcgr = 0x11288,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_1_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_cci_2_clk_src = {
+ .cmd_rcgr = 0x112a4,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_2_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = {
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+ .cmd_rcgr = 0x11068,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cphy_rx_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cre_clk_src[] = {
+ F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cre_clk_src = {
+ .cmd_rcgr = 0x111ac,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cre_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cre_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = {
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x10000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi0phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x10024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi1phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x10044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi2phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+ .cmd_rcgr = 0x10064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi3phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = {
+ .cmd_rcgr = 0x10084,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi4phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = {
+ .cmd_rcgr = 0x100a4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi5phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csid_clk_src = {
+ .cmd_rcgr = 0x112c0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csid_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = {
+ F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+ .cmd_rcgr = 0x100dc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_fast_ahb_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_icp_0_clk_src[] = {
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_icp_0_clk_src = {
+ .cmd_rcgr = 0x11214,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_icp_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_0_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_icp_1_clk_src = {
+ .cmd_rcgr = 0x1123c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_icp_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_1_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+ .cmd_rcgr = 0x11150,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+ .cmd_rcgr = 0x1117c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_csid_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ipe_nps_clk_src[] = {
+ F(450000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(575000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(675000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(825000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ipe_nps_clk_src = {
+ .cmd_rcgr = 0x10190,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_2,
+ .freq_tbl = ftbl_cam_cc_ipe_nps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_clk_src",
+ .parent_data = cam_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+ .cmd_rcgr = 0x111d0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cre_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_jpeg_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ofe_clk_src[] = {
+ F(436000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ F(570000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ F(675000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ F(757000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ofe_clk_src = {
+ .cmd_rcgr = 0x1011c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_3,
+ .freq_tbl = ftbl_cam_cc_ofe_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_clk_src",
+ .parent_data = cam_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_qdss_debug_clk_src[] = {
+ F(60000000, P_CAM_CC_PLL6_OUT_EVEN, 8, 0, 0),
+ F(120000000, P_CAM_CC_PLL0_OUT_EVEN, 5, 0, 0),
+ F(240000000, P_CAM_CC_PLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_qdss_debug_clk_src = {
+ .cmd_rcgr = 0x1132c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_qdss_debug_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_sleep_clk_src = {
+ .cmd_rcgr = 0x11380,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_4,
+ .freq_tbl = ftbl_cam_cc_sleep_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_sleep_clk_src",
+ .parent_data = cam_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = {
+ F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+ .cmd_rcgr = 0x10100,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_slow_ahb_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_tfe_0_clk_src[] = {
+ F(445000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(567000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(644000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(785000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_tfe_0_clk_src = {
+ .cmd_rcgr = 0x11018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_5,
+ .freq_tbl = ftbl_cam_cc_tfe_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_0_clk_src",
+ .parent_data = cam_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_tfe_1_clk_src[] = {
+ F(445000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(567000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(644000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(785000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_tfe_1_clk_src = {
+ .cmd_rcgr = 0x11098,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_6,
+ .freq_tbl = ftbl_cam_cc_tfe_1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_1_clk_src",
+ .parent_data = cam_cc_parent_data_6,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_tfe_2_clk_src[] = {
+ F(445000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+ F(567000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+ F(644000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+ F(785000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_tfe_2_clk_src = {
+ .cmd_rcgr = 0x11100,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_7,
+ .freq_tbl = ftbl_cam_cc_tfe_2_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_2_clk_src",
+ .parent_data = cam_cc_parent_data_7,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_xo_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_xo_clk_src = {
+ .cmd_rcgr = 0x11364,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_8,
+ .freq_tbl = ftbl_cam_cc_xo_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_xo_clk_src",
+ .parent_data = cam_cc_parent_data_8,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_branch cam_cc_cam_top_ahb_clk = {
+ .halt_reg = 0x113ac,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x113ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cam_top_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cam_top_fast_ahb_clk = {
+ .halt_reg = 0x1139c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1139c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cam_top_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_dcd_xo_clk = {
+ .halt_reg = 0x11320,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11320,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_dcd_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_axi_clk = {
+ .halt_reg = 0x11310,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x11310,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x11310,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_nrt_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_rt_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_cre_clk = {
+ .halt_reg = 0x111c8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_nrt_cre_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cre_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ipe_nps_clk = {
+ .halt_reg = 0x101b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x101b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_nrt_ipe_nps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ofe_anchor_clk = {
+ .halt_reg = 0x10158,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10158,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_nrt_ofe_anchor_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ofe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ofe_hdr_clk = {
+ .halt_reg = 0x1016c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1016c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_nrt_ofe_hdr_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ofe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_nrt_ofe_main_clk = {
+ .halt_reg = 0x10144,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10144,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_nrt_ofe_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ofe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_axi_clk = {
+ .halt_reg = 0x11300,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11300,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_rt_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_ife_lite_clk = {
+ .halt_reg = 0x11178,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11178,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_ife_lite_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_0_bayer_clk = {
+ .halt_reg = 0x11054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_tfe_0_bayer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_0_main_clk = {
+ .halt_reg = 0x11040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_tfe_0_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_1_bayer_clk = {
+ .halt_reg = 0x110d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_tfe_1_bayer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_1_main_clk = {
+ .halt_reg = 0x110c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_tfe_1_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_2_bayer_clk = {
+ .halt_reg = 0x1113c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1113c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_tfe_2_bayer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_rt_tfe_2_main_clk = {
+ .halt_reg = 0x11128,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11128,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_rt_tfe_2_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_xo_clk = {
+ .halt_reg = 0x11324,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11324,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_0_clk = {
+ .halt_reg = 0x11284,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11284,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_1_clk = {
+ .halt_reg = 0x112a0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x112a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_2_clk = {
+ .halt_reg = 0x112bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x112bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_core_ahb_clk = {
+ .halt_reg = 0x11360,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x11360,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_core_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cre_ahb_clk = {
+ .halt_reg = 0x111cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cre_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cre_clk = {
+ .halt_reg = 0x111c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cre_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cre_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi0phytimer_clk = {
+ .halt_reg = 0x10018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi0phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi1phytimer_clk = {
+ .halt_reg = 0x1003c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1003c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi1phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi2phytimer_clk = {
+ .halt_reg = 0x1005c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1005c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi2phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi2phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi3phytimer_clk = {
+ .halt_reg = 0x1007c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1007c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi3phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi3phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi4phytimer_clk = {
+ .halt_reg = 0x1009c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1009c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi4phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi4phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi5phytimer_clk = {
+ .halt_reg = 0x100bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x100bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi5phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi5phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csid_clk = {
+ .halt_reg = 0x112d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x112d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csid_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csid_csiphy_rx_clk = {
+ .halt_reg = 0x10020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csid_csiphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy0_clk = {
+ .halt_reg = 0x1001c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1001c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy1_clk = {
+ .halt_reg = 0x10040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy2_clk = {
+ .halt_reg = 0x10060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy3_clk = {
+ .halt_reg = 0x10080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy4_clk = {
+ .halt_reg = 0x100a0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x100a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy5_clk = {
+ .halt_reg = 0x100c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x100c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_drv_ahb_clk = {
+ .halt_reg = 0x113c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x113c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_drv_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_drv_xo_clk = {
+ .halt_reg = 0x113c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x113c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_drv_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_0_ahb_clk = {
+ .halt_reg = 0x11264,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11264,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_0_clk = {
+ .halt_reg = 0x1122c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1122c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_icp_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_1_ahb_clk = {
+ .halt_reg = 0x11268,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11268,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_1_clk = {
+ .halt_reg = 0x11254,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11254,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_icp_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_ahb_clk = {
+ .halt_reg = 0x111a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_clk = {
+ .halt_reg = 0x11168,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11168,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = {
+ .halt_reg = 0x111a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_csid_clk = {
+ .halt_reg = 0x11194,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11194,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_csid_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_nps_ahb_clk = {
+ .halt_reg = 0x101d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x101d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_nps_clk = {
+ .halt_reg = 0x101a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x101a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_nps_fast_ahb_clk = {
+ .halt_reg = 0x101d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x101d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_pps_clk = {
+ .halt_reg = 0x101bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x101bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_pps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_pps_fast_ahb_clk = {
+ .halt_reg = 0x101dc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x101dc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_pps_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_jpeg_0_clk = {
+ .halt_reg = 0x111e8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_jpeg_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_jpeg_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_jpeg_1_clk = {
+ .halt_reg = 0x111f8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x111f8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_jpeg_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_jpeg_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_ahb_clk = {
+ .halt_reg = 0x10118,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10118,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_anchor_clk = {
+ .halt_reg = 0x10148,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10148,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_anchor_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ofe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_anchor_fast_ahb_clk = {
+ .halt_reg = 0x100f8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x100f8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_anchor_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_hdr_clk = {
+ .halt_reg = 0x1015c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1015c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_hdr_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ofe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_hdr_fast_ahb_clk = {
+ .halt_reg = 0x100fc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x100fc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_hdr_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_main_clk = {
+ .halt_reg = 0x10134,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10134,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ofe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ofe_main_fast_ahb_clk = {
+ .halt_reg = 0x100f4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x100f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ofe_main_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_qdss_debug_clk = {
+ .halt_reg = 0x11344,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11344,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_qdss_debug_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_qdss_debug_xo_clk = {
+ .halt_reg = 0x11348,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11348,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_0_bayer_clk = {
+ .halt_reg = 0x11044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_0_bayer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_0_bayer_fast_ahb_clk = {
+ .halt_reg = 0x11064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_0_bayer_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_0_main_clk = {
+ .halt_reg = 0x11030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_0_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_0_main_fast_ahb_clk = {
+ .halt_reg = 0x11060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_0_main_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_1_bayer_clk = {
+ .halt_reg = 0x110c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_1_bayer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_1_bayer_fast_ahb_clk = {
+ .halt_reg = 0x110e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_1_bayer_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_1_main_clk = {
+ .halt_reg = 0x110b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_1_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_1_main_fast_ahb_clk = {
+ .halt_reg = 0x110e0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110e0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_1_main_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_2_bayer_clk = {
+ .halt_reg = 0x1112c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1112c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_2_bayer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_2_bayer_fast_ahb_clk = {
+ .halt_reg = 0x1114c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1114c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_2_bayer_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_2_main_clk = {
+ .halt_reg = 0x11118,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11118,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_2_main_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_tfe_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_tfe_2_main_fast_ahb_clk = {
+ .halt_reg = 0x11148,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11148,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_tfe_2_main_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc cam_cc_titan_top_gdsc = {
+ .gdscr = 0x1134c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_titan_top_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_ipe_0_gdsc = {
+ .gdscr = 0x1017c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_ipe_0_gdsc",
+ },
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_ofe_gdsc = {
+ .gdscr = 0x100c8,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_ofe_gdsc",
+ },
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_tfe_0_gdsc = {
+ .gdscr = 0x11004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_tfe_0_gdsc",
+ },
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_tfe_1_gdsc = {
+ .gdscr = 0x11084,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_tfe_1_gdsc",
+ },
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_tfe_2_gdsc = {
+ .gdscr = 0x110ec,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_tfe_2_gdsc",
+ },
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *cam_cc_eliza_clocks[] = {
+ [CAM_CC_CAM_TOP_AHB_CLK] = &cam_cc_cam_top_ahb_clk.clkr,
+ [CAM_CC_CAM_TOP_FAST_AHB_CLK] = &cam_cc_cam_top_fast_ahb_clk.clkr,
+ [CAM_CC_CAMNOC_DCD_XO_CLK] = &cam_cc_camnoc_dcd_xo_clk.clkr,
+ [CAM_CC_CAMNOC_NRT_AXI_CLK] = &cam_cc_camnoc_nrt_axi_clk.clkr,
+ [CAM_CC_CAMNOC_NRT_CRE_CLK] = &cam_cc_camnoc_nrt_cre_clk.clkr,
+ [CAM_CC_CAMNOC_NRT_IPE_NPS_CLK] = &cam_cc_camnoc_nrt_ipe_nps_clk.clkr,
+ [CAM_CC_CAMNOC_NRT_OFE_ANCHOR_CLK] = &cam_cc_camnoc_nrt_ofe_anchor_clk.clkr,
+ [CAM_CC_CAMNOC_NRT_OFE_HDR_CLK] = &cam_cc_camnoc_nrt_ofe_hdr_clk.clkr,
+ [CAM_CC_CAMNOC_NRT_OFE_MAIN_CLK] = &cam_cc_camnoc_nrt_ofe_main_clk.clkr,
+ [CAM_CC_CAMNOC_RT_AXI_CLK] = &cam_cc_camnoc_rt_axi_clk.clkr,
+ [CAM_CC_CAMNOC_RT_AXI_CLK_SRC] = &cam_cc_camnoc_rt_axi_clk_src.clkr,
+ [CAM_CC_CAMNOC_RT_IFE_LITE_CLK] = &cam_cc_camnoc_rt_ife_lite_clk.clkr,
+ [CAM_CC_CAMNOC_RT_TFE_0_BAYER_CLK] = &cam_cc_camnoc_rt_tfe_0_bayer_clk.clkr,
+ [CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK] = &cam_cc_camnoc_rt_tfe_0_main_clk.clkr,
+ [CAM_CC_CAMNOC_RT_TFE_1_BAYER_CLK] = &cam_cc_camnoc_rt_tfe_1_bayer_clk.clkr,
+ [CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK] = &cam_cc_camnoc_rt_tfe_1_main_clk.clkr,
+ [CAM_CC_CAMNOC_RT_TFE_2_BAYER_CLK] = &cam_cc_camnoc_rt_tfe_2_bayer_clk.clkr,
+ [CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK] = &cam_cc_camnoc_rt_tfe_2_main_clk.clkr,
+ [CAM_CC_CAMNOC_XO_CLK] = &cam_cc_camnoc_xo_clk.clkr,
+ [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr,
+ [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr,
+ [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr,
+ [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr,
+ [CAM_CC_CCI_2_CLK] = &cam_cc_cci_2_clk.clkr,
+ [CAM_CC_CCI_2_CLK_SRC] = &cam_cc_cci_2_clk_src.clkr,
+ [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr,
+ [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr,
+ [CAM_CC_CRE_AHB_CLK] = &cam_cc_cre_ahb_clk.clkr,
+ [CAM_CC_CRE_CLK] = &cam_cc_cre_clk.clkr,
+ [CAM_CC_CRE_CLK_SRC] = &cam_cc_cre_clk_src.clkr,
+ [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr,
+ [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr,
+ [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr,
+ [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr,
+ [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr,
+ [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr,
+ [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr,
+ [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr,
+ [CAM_CC_CSI4PHYTIMER_CLK] = &cam_cc_csi4phytimer_clk.clkr,
+ [CAM_CC_CSI4PHYTIMER_CLK_SRC] = &cam_cc_csi4phytimer_clk_src.clkr,
+ [CAM_CC_CSI5PHYTIMER_CLK] = &cam_cc_csi5phytimer_clk.clkr,
+ [CAM_CC_CSI5PHYTIMER_CLK_SRC] = &cam_cc_csi5phytimer_clk_src.clkr,
+ [CAM_CC_CSID_CLK] = &cam_cc_csid_clk.clkr,
+ [CAM_CC_CSID_CLK_SRC] = &cam_cc_csid_clk_src.clkr,
+ [CAM_CC_CSID_CSIPHY_RX_CLK] = &cam_cc_csid_csiphy_rx_clk.clkr,
+ [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
+ [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
+ [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
+ [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr,
+ [CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr,
+ [CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr,
+ [CAM_CC_DRV_AHB_CLK] = &cam_cc_drv_ahb_clk.clkr,
+ [CAM_CC_DRV_XO_CLK] = &cam_cc_drv_xo_clk.clkr,
+ [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
+ [CAM_CC_ICP_0_AHB_CLK] = &cam_cc_icp_0_ahb_clk.clkr,
+ [CAM_CC_ICP_0_CLK] = &cam_cc_icp_0_clk.clkr,
+ [CAM_CC_ICP_0_CLK_SRC] = &cam_cc_icp_0_clk_src.clkr,
+ [CAM_CC_ICP_1_AHB_CLK] = &cam_cc_icp_1_ahb_clk.clkr,
+ [CAM_CC_ICP_1_CLK] = &cam_cc_icp_1_clk.clkr,
+ [CAM_CC_ICP_1_CLK_SRC] = &cam_cc_icp_1_clk_src.clkr,
+ [CAM_CC_IFE_LITE_AHB_CLK] = &cam_cc_ife_lite_ahb_clk.clkr,
+ [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr,
+ [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr,
+ [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr,
+ [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr,
+ [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr,
+ [CAM_CC_IPE_NPS_AHB_CLK] = &cam_cc_ipe_nps_ahb_clk.clkr,
+ [CAM_CC_IPE_NPS_CLK] = &cam_cc_ipe_nps_clk.clkr,
+ [CAM_CC_IPE_NPS_CLK_SRC] = &cam_cc_ipe_nps_clk_src.clkr,
+ [CAM_CC_IPE_NPS_FAST_AHB_CLK] = &cam_cc_ipe_nps_fast_ahb_clk.clkr,
+ [CAM_CC_IPE_PPS_CLK] = &cam_cc_ipe_pps_clk.clkr,
+ [CAM_CC_IPE_PPS_FAST_AHB_CLK] = &cam_cc_ipe_pps_fast_ahb_clk.clkr,
+ [CAM_CC_JPEG_0_CLK] = &cam_cc_jpeg_0_clk.clkr,
+ [CAM_CC_JPEG_1_CLK] = &cam_cc_jpeg_1_clk.clkr,
+ [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr,
+ [CAM_CC_OFE_AHB_CLK] = &cam_cc_ofe_ahb_clk.clkr,
+ [CAM_CC_OFE_ANCHOR_CLK] = &cam_cc_ofe_anchor_clk.clkr,
+ [CAM_CC_OFE_ANCHOR_FAST_AHB_CLK] = &cam_cc_ofe_anchor_fast_ahb_clk.clkr,
+ [CAM_CC_OFE_CLK_SRC] = &cam_cc_ofe_clk_src.clkr,
+ [CAM_CC_OFE_HDR_CLK] = &cam_cc_ofe_hdr_clk.clkr,
+ [CAM_CC_OFE_HDR_FAST_AHB_CLK] = &cam_cc_ofe_hdr_fast_ahb_clk.clkr,
+ [CAM_CC_OFE_MAIN_CLK] = &cam_cc_ofe_main_clk.clkr,
+ [CAM_CC_OFE_MAIN_FAST_AHB_CLK] = &cam_cc_ofe_main_fast_ahb_clk.clkr,
+ [CAM_CC_PLL0] = &cam_cc_pll0.clkr,
+ [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr,
+ [CAM_CC_PLL0_OUT_ODD] = &cam_cc_pll0_out_odd.clkr,
+ [CAM_CC_PLL1] = &cam_cc_pll1.clkr,
+ [CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr,
+ [CAM_CC_PLL2] = &cam_cc_pll2.clkr,
+ [CAM_CC_PLL2_OUT_EVEN] = &cam_cc_pll2_out_even.clkr,
+ [CAM_CC_PLL3] = &cam_cc_pll3.clkr,
+ [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr,
+ [CAM_CC_PLL4] = &cam_cc_pll4.clkr,
+ [CAM_CC_PLL4_OUT_EVEN] = &cam_cc_pll4_out_even.clkr,
+ [CAM_CC_PLL5] = &cam_cc_pll5.clkr,
+ [CAM_CC_PLL5_OUT_EVEN] = &cam_cc_pll5_out_even.clkr,
+ [CAM_CC_PLL6] = &cam_cc_pll6.clkr,
+ [CAM_CC_PLL6_OUT_EVEN] = &cam_cc_pll6_out_even.clkr,
+ [CAM_CC_PLL6_OUT_ODD] = &cam_cc_pll6_out_odd.clkr,
+ [CAM_CC_QDSS_DEBUG_CLK] = &cam_cc_qdss_debug_clk.clkr,
+ [CAM_CC_QDSS_DEBUG_CLK_SRC] = &cam_cc_qdss_debug_clk_src.clkr,
+ [CAM_CC_QDSS_DEBUG_XO_CLK] = &cam_cc_qdss_debug_xo_clk.clkr,
+ [CAM_CC_SLEEP_CLK_SRC] = &cam_cc_sleep_clk_src.clkr,
+ [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr,
+ [CAM_CC_TFE_0_BAYER_CLK] = &cam_cc_tfe_0_bayer_clk.clkr,
+ [CAM_CC_TFE_0_BAYER_FAST_AHB_CLK] = &cam_cc_tfe_0_bayer_fast_ahb_clk.clkr,
+ [CAM_CC_TFE_0_CLK_SRC] = &cam_cc_tfe_0_clk_src.clkr,
+ [CAM_CC_TFE_0_MAIN_CLK] = &cam_cc_tfe_0_main_clk.clkr,
+ [CAM_CC_TFE_0_MAIN_FAST_AHB_CLK] = &cam_cc_tfe_0_main_fast_ahb_clk.clkr,
+ [CAM_CC_TFE_1_BAYER_CLK] = &cam_cc_tfe_1_bayer_clk.clkr,
+ [CAM_CC_TFE_1_BAYER_FAST_AHB_CLK] = &cam_cc_tfe_1_bayer_fast_ahb_clk.clkr,
+ [CAM_CC_TFE_1_CLK_SRC] = &cam_cc_tfe_1_clk_src.clkr,
+ [CAM_CC_TFE_1_MAIN_CLK] = &cam_cc_tfe_1_main_clk.clkr,
+ [CAM_CC_TFE_1_MAIN_FAST_AHB_CLK] = &cam_cc_tfe_1_main_fast_ahb_clk.clkr,
+ [CAM_CC_TFE_2_BAYER_CLK] = &cam_cc_tfe_2_bayer_clk.clkr,
+ [CAM_CC_TFE_2_BAYER_FAST_AHB_CLK] = &cam_cc_tfe_2_bayer_fast_ahb_clk.clkr,
+ [CAM_CC_TFE_2_CLK_SRC] = &cam_cc_tfe_2_clk_src.clkr,
+ [CAM_CC_TFE_2_MAIN_CLK] = &cam_cc_tfe_2_main_clk.clkr,
+ [CAM_CC_TFE_2_MAIN_FAST_AHB_CLK] = &cam_cc_tfe_2_main_fast_ahb_clk.clkr,
+ [CAM_CC_XO_CLK_SRC] = &cam_cc_xo_clk_src.clkr,
+};
+
+static struct gdsc *cam_cc_eliza_gdscs[] = {
+ [CAM_CC_IPE_0_GDSC] = &cam_cc_ipe_0_gdsc,
+ [CAM_CC_OFE_GDSC] = &cam_cc_ofe_gdsc,
+ [CAM_CC_TFE_0_GDSC] = &cam_cc_tfe_0_gdsc,
+ [CAM_CC_TFE_1_GDSC] = &cam_cc_tfe_1_gdsc,
+ [CAM_CC_TFE_2_GDSC] = &cam_cc_tfe_2_gdsc,
+ [CAM_CC_TITAN_TOP_GDSC] = &cam_cc_titan_top_gdsc,
+};
+
+static const struct qcom_reset_map cam_cc_eliza_resets[] = {
+ [CAM_CC_DRV_BCR] = { 0x113bc },
+ [CAM_CC_ICP_BCR] = { 0x11210 },
+ [CAM_CC_IPE_0_BCR] = { 0x10178 },
+ [CAM_CC_OFE_BCR] = { 0x100c4 },
+ [CAM_CC_QDSS_DEBUG_BCR] = { 0x11328 },
+ [CAM_CC_TFE_0_BCR] = { 0x11000 },
+ [CAM_CC_TFE_1_BCR] = { 0x11080 },
+ [CAM_CC_TFE_2_BCR] = { 0x110e8 },
+};
+
+static struct clk_alpha_pll *cam_cc_eliza_plls[] = {
+ &cam_cc_pll0,
+ &cam_cc_pll1,
+ &cam_cc_pll2,
+ &cam_cc_pll3,
+ &cam_cc_pll4,
+ &cam_cc_pll5,
+ &cam_cc_pll6,
+};
+
+static u32 cam_cc_eliza_critical_cbcrs[] = {
+ 0x1137c, /* CAM_CC_GDSC_CLK */
+ 0x11398, /* CAM_CC_SLEEP_CLK */
+};
+
+static const struct regmap_config cam_cc_eliza_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1601c,
+ .fast_io = true,
+};
+
+static struct qcom_cc_driver_data cam_cc_eliza_driver_data = {
+ .alpha_plls = cam_cc_eliza_plls,
+ .num_alpha_plls = ARRAY_SIZE(cam_cc_eliza_plls),
+ .clk_cbcrs = cam_cc_eliza_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(cam_cc_eliza_critical_cbcrs),
+};
+
+static const struct qcom_cc_desc cam_cc_eliza_desc = {
+ .config = &cam_cc_eliza_regmap_config,
+ .clks = cam_cc_eliza_clocks,
+ .num_clks = ARRAY_SIZE(cam_cc_eliza_clocks),
+ .resets = cam_cc_eliza_resets,
+ .num_resets = ARRAY_SIZE(cam_cc_eliza_resets),
+ .gdscs = cam_cc_eliza_gdscs,
+ .num_gdscs = ARRAY_SIZE(cam_cc_eliza_gdscs),
+ .driver_data = &cam_cc_eliza_driver_data,
+};
+
+static const struct of_device_id cam_cc_eliza_match_table[] = {
+ { .compatible = "qcom,eliza-camcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cam_cc_eliza_match_table);
+
+static int cam_cc_eliza_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &cam_cc_eliza_desc);
+}
+
+static struct platform_driver cam_cc_eliza_driver = {
+ .probe = cam_cc_eliza_probe,
+ .driver = {
+ .name = "camcc-eliza",
+ .of_match_table = cam_cc_eliza_match_table,
+ },
+};
+
+module_platform_driver(cam_cc_eliza_driver);
+
+MODULE_DESCRIPTION("QTI CAMCC Eliza Driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v2 5/8] clk: qcom: gpucc: Add GPU Clock Controller driver for Eliza
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Add Graphics Clock Controller (GPUCC) support for Eliza platform.
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
drivers/clk/qcom/Kconfig | 9 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/gpucc-eliza.c | 621 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 631 insertions(+)
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 4b0d40a38a6328fe9c41ebb15ae6821012223920..7626dfa536ece08e88ad198d8fa60972f06f14d5 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -37,6 +37,15 @@ config CLK_ELIZA_GCC
Say Y if you want to use peripheral devices such as UART, SPI,
I2C, USB, UFS, SDCC, etc.
+config CLK_ELIZA_GPUCC
+ tristate "Eliza Graphics Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select CLK_ELIZA_GCC
+ help
+ Support for the graphics clock controller on Eliza devices.
+ Say Y if you want to support graphics controller devices and
+ functionality such as 3D graphics.
+
config CLK_ELIZA_TCSRCC
tristate "Eliza TCSR Clock Controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index e7e239c5a0d088b2e78354bf421d871a4e4e6d9d..1c34797eb385963110614ba43eb9bbc9653699fb 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_CLK_ELIZA_DISPCC) += dispcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_GCC) += gcc-eliza.o
+obj-$(CONFIG_CLK_ELIZA_GPUCC) += gpucc-eliza.o
obj-$(CONFIG_CLK_ELIZA_TCSRCC) += tcsrcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_VIDEOCC) += videocc-eliza.o
obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o
diff --git a/drivers/clk/qcom/gpucc-eliza.c b/drivers/clk/qcom/gpucc-eliza.c
new file mode 100644
index 0000000000000000000000000000000000000000..85ae0ab1184053ce03809176a64f5d47d3a411b9
--- /dev/null
+++ b/drivers/clk/qcom/gpucc-eliza.c
@@ -0,0 +1,621 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,eliza-gpucc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_GPLL0_OUT_MAIN,
+ DT_GPLL0_OUT_MAIN_DIV,
+};
+
+enum {
+ P_BI_TCXO,
+ P_BI_TCXO_AO,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_MAIN_DIV,
+ P_GPU_CC_PLL0_OUT_MAIN,
+ P_GPU_CC_PLL1_OUT_MAIN,
+};
+
+static const struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2300000000, 0 },
+};
+
+/* 518.0 MHz Configuration */
+static const struct alpha_pll_config gpu_cc_pll0_config = {
+ .l = 0x1a,
+ .alpha = 0xfaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll gpu_cc_pll0 = {
+ .offset = 0x0,
+ .config = &gpu_cc_pll0_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+/* 440.0 MHz Configuration */
+static const struct alpha_pll_config gpu_cc_pll1_config = {
+ .l = 0x16,
+ .alpha = 0xeaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll gpu_cc_pll1 = {
+ .offset = 0x1000,
+ .config = &gpu_cc_pll1_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_GPLL0_OUT_MAIN },
+ { .index = DT_GPLL0_OUT_MAIN_DIV },
+};
+
+static const struct parent_map gpu_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL0_OUT_MAIN, 1 },
+ { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpu_cc_pll0.clkr.hw },
+ { .hw = &gpu_cc_pll1.clkr.hw },
+ { .index = DT_GPLL0_OUT_MAIN },
+ { .index = DT_GPLL0_OUT_MAIN_DIV },
+};
+
+static const struct parent_map gpu_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpu_cc_pll1.clkr.hw },
+ { .index = DT_GPLL0_OUT_MAIN },
+ { .index = DT_GPLL0_OUT_MAIN_DIV },
+};
+
+static const struct parent_map gpu_cc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = {
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_ff_clk_src = {
+ .cmd_rcgr = 0x94b8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_0,
+ .freq_tbl = ftbl_gpu_cc_ff_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_ff_clk_src",
+ .parent_data = gpu_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
+ F(220000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0),
+ F(550000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_gmu_clk_src = {
+ .cmd_rcgr = 0x935c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_1,
+ .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_gmu_clk_src",
+ .parent_data = gpu_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gpu_cc_hub_clk_src = {
+ .cmd_rcgr = 0x9430,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_2,
+ .freq_tbl = ftbl_gpu_cc_ff_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_hub_clk_src",
+ .parent_data = gpu_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_xo_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_xo_clk_src = {
+ .cmd_rcgr = 0x9010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_3,
+ .freq_tbl = ftbl_gpu_cc_xo_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_xo_clk_src",
+ .parent_data = gpu_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div gpu_cc_xo_div_clk_src = {
+ .reg = 0x9050,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_xo_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gpu_cc_ahb_clk = {
+ .halt_reg = 0x914c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x914c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+ .halt_reg = 0x9150,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9150,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_crc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_accu_shift_clk = {
+ .halt_reg = 0x9480,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9480,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_cx_accu_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_ff_clk = {
+ .halt_reg = 0x9184,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9184,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_cx_ff_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gmu_clk = {
+ .halt_reg = 0x916c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x916c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_cx_gmu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_gmu_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cxo_clk = {
+ .halt_reg = 0x917c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x917c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_cxo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_freq_measure_clk = {
+ .halt_reg = 0x9008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_freq_measure_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_xo_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gpu_smmu_vote_clk = {
+ .halt_reg = 0x7000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_gpu_smmu_vote_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
+ .halt_reg = 0x7000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_hub_aon_clk = {
+ .halt_reg = 0x942c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x942c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_hub_aon_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_hub_cx_int_clk = {
+ .halt_reg = 0x9180,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9180,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_hub_cx_int_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_memnoc_gfx_clk = {
+ .halt_reg = 0x9188,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9188,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_memnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_mnd1x_0_gfx3d_clk = {
+ .halt_reg = 0x92cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x92cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_mnd1x_0_gfx3d_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_mnd1x_1_gfx3d_clk = {
+ .halt_reg = 0x92d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x92d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_mnd1x_1_gfx3d_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_sleep_clk = {
+ .halt_reg = 0x9164,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9164,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc gpu_cc_cx_gdsc = {
+ .gdscr = 0x9110,
+ .gds_hw_ctrl = 0x9124,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x8,
+ .pd = {
+ .name = "gpu_cc_cx_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gpu_cc_gx_gdsc = {
+ .gdscr = 0x905c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gpu_cc_gx_gdsc",
+ .power_on = gdsc_gx_do_nothing_enable,
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *gpu_cc_eliza_clocks[] = {
+ [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
+ [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+ [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr,
+ [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr,
+ [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
+ [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
+ [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr,
+ [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr,
+ [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+ [GPU_CC_GPU_SMMU_VOTE_CLK] = &gpu_cc_gpu_smmu_vote_clk.clkr,
+ [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
+ [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,
+ [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,
+ [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,
+ [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr,
+ [GPU_CC_MND1X_0_GFX3D_CLK] = &gpu_cc_mnd1x_0_gfx3d_clk.clkr,
+ [GPU_CC_MND1X_1_GFX3D_CLK] = &gpu_cc_mnd1x_1_gfx3d_clk.clkr,
+ [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+ [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
+ [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr,
+ [GPU_CC_XO_CLK_SRC] = &gpu_cc_xo_clk_src.clkr,
+ [GPU_CC_XO_DIV_CLK_SRC] = &gpu_cc_xo_div_clk_src.clkr,
+};
+
+static struct gdsc *gpu_cc_eliza_gdscs[] = {
+ [GPU_CC_CX_GDSC] = &gpu_cc_cx_gdsc,
+ [GPU_CC_GX_GDSC] = &gpu_cc_gx_gdsc,
+};
+
+static const struct qcom_reset_map gpu_cc_eliza_resets[] = {
+ [GPU_CC_ACD_BCR] = { 0x939c },
+ [GPU_CC_CB_BCR] = { 0x93e4 },
+ [GPU_CC_CX_BCR] = { 0x910c },
+ [GPU_CC_FAST_HUB_BCR] = { 0x9428 },
+ [GPU_CC_FF_BCR] = { 0x94b4 },
+ [GPU_CC_GFX3D_AON_BCR] = { 0x91dc },
+ [GPU_CC_GMU_BCR] = { 0x9358 },
+ [GPU_CC_GX_BCR] = { 0x9058 },
+ [GPU_CC_RBCPR_BCR] = { 0x9224 },
+ [GPU_CC_XO_BCR] = { 0x9000 },
+};
+
+static struct clk_alpha_pll *gpu_cc_eliza_plls[] = {
+ &gpu_cc_pll0,
+ &gpu_cc_pll1,
+};
+
+static u32 gpu_cc_eliza_critical_cbcrs[] = {
+ 0x9004, /* GPU_CC_CXO_AON_CLK */
+ 0x900c, /* GPU_CC_DEMET_CLK */
+};
+
+static const struct regmap_config gpu_cc_eliza_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x9988,
+ .fast_io = true,
+};
+
+static struct qcom_cc_driver_data gpu_cc_eliza_driver_data = {
+ .alpha_plls = gpu_cc_eliza_plls,
+ .num_alpha_plls = ARRAY_SIZE(gpu_cc_eliza_plls),
+ .clk_cbcrs = gpu_cc_eliza_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(gpu_cc_eliza_critical_cbcrs),
+};
+
+static const struct qcom_cc_desc gpu_cc_eliza_desc = {
+ .config = &gpu_cc_eliza_regmap_config,
+ .clks = gpu_cc_eliza_clocks,
+ .num_clks = ARRAY_SIZE(gpu_cc_eliza_clocks),
+ .resets = gpu_cc_eliza_resets,
+ .num_resets = ARRAY_SIZE(gpu_cc_eliza_resets),
+ .gdscs = gpu_cc_eliza_gdscs,
+ .num_gdscs = ARRAY_SIZE(gpu_cc_eliza_gdscs),
+ .use_rpm = true,
+ .driver_data = &gpu_cc_eliza_driver_data,
+};
+
+static const struct of_device_id gpu_cc_eliza_match_table[] = {
+ { .compatible = "qcom,eliza-gpucc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_eliza_match_table);
+
+static int gpu_cc_eliza_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &gpu_cc_eliza_desc);
+}
+
+static struct platform_driver gpu_cc_eliza_driver = {
+ .probe = gpu_cc_eliza_probe,
+ .driver = {
+ .name = "gpucc-eliza",
+ .of_match_table = gpu_cc_eliza_match_table,
+ },
+};
+
+module_platform_driver(gpu_cc_eliza_driver);
+
+MODULE_DESCRIPTION("QTI GPUCC Eliza Driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v2 4/8] clk: qcom: videocc: Add video clock controller driver for Eliza
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das, Konrad Dybcio
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Add support for the video clock controller for video clients to be able
to request for videocc clocks on Eliza platform.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
drivers/clk/qcom/Kconfig | 9 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/videocc-eliza.c | 403 +++++++++++++++++++++++++++++++++++++++
3 files changed, 413 insertions(+)
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 22eb80be60ad3bde897f2c507ac9897951fbb8fe..4b0d40a38a6328fe9c41ebb15ae6821012223920 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -45,6 +45,15 @@ config CLK_ELIZA_TCSRCC
Support for the TCSR clock controller on Eliza devices.
Say Y if you want to use peripheral devices such as USB/PCIe/UFS.
+config CLK_ELIZA_VIDEOCC
+ tristate "Eliza Video Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select CLK_GLYMUR_GCC
+ help
+ Support for the video clock controller on Eliza devices.
+ Say Y if you want to support video devices and functionality such as
+ video encode and decode.
+
config CLK_GLYMUR_DISPCC
tristate "Glymur Display Clock Controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index b818fd5af8bfb85a51ee90fdc3baa93af30dc39a..e7e239c5a0d088b2e78354bf421d871a4e4e6d9d 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_CLK_ELIZA_DISPCC) += dispcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_GCC) += gcc-eliza.o
obj-$(CONFIG_CLK_ELIZA_TCSRCC) += tcsrcc-eliza.o
+obj-$(CONFIG_CLK_ELIZA_VIDEOCC) += videocc-eliza.o
obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o
obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o
obj-$(CONFIG_CLK_GLYMUR_GCC) += gcc-glymur.o
diff --git a/drivers/clk/qcom/videocc-eliza.c b/drivers/clk/qcom/videocc-eliza.c
new file mode 100644
index 0000000000000000000000000000000000000000..cb541cfec50c12761251a822e32094e763922cdb
--- /dev/null
+++ b/drivers/clk/qcom/videocc-eliza.c
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,eliza-videocc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_SLEEP_CLK,
+ DT_AHB_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_SLEEP_CLK,
+ P_VIDEO_CC_PLL0_OUT_MAIN,
+};
+
+static const struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2300000000, 0 },
+};
+
+/* 576.0 MHz Configuration */
+static const struct alpha_pll_config video_cc_pll0_config = {
+ .l = 0x1e,
+ .alpha = 0x0,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll video_cc_pll0 = {
+ .offset = 0x0,
+ .config = &video_cc_pll0_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map video_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data video_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map video_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data video_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &video_cc_pll0.clkr.hw },
+};
+
+static const struct parent_map video_cc_parent_map_2[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data video_cc_parent_data_2[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_ahb_clk_src = {
+ .cmd_rcgr = 0x8018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_0,
+ .freq_tbl = ftbl_video_cc_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_ahb_clk_src",
+ .parent_data = video_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
+ F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(633000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(1113000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(1600000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_mvs0_clk_src = {
+ .cmd_rcgr = 0x8000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_1,
+ .freq_tbl = ftbl_video_cc_mvs0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_clk_src",
+ .parent_data = video_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_sleep_clk_src = {
+ .cmd_rcgr = 0x8110,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_2,
+ .freq_tbl = ftbl_video_cc_sleep_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_sleep_clk_src",
+ .parent_data = video_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 video_cc_xo_clk_src = {
+ .cmd_rcgr = 0x80f4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_0,
+ .freq_tbl = ftbl_video_cc_ahb_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_xo_clk_src",
+ .parent_data = video_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
+ .reg = 0x80ac,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
+ .reg = 0x8058,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0c_div2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch video_cc_mvs0_clk = {
+ .halt_reg = 0x80a0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x80a0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x80a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0_shift_clk = {
+ .halt_reg = 0x8144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8144,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8144,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0c_clk = {
+ .halt_reg = 0x804c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x804c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0c_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0c_div2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0c_shift_clk = {
+ .halt_reg = 0x8148,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8148,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8148,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0c_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc video_cc_mvs0c_gdsc = {
+ .gdscr = 0x8034,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x6,
+ .pd = {
+ .name = "video_cc_mvs0c_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc video_cc_mvs0_gdsc = {
+ .gdscr = 0x808c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x6,
+ .pd = {
+ .name = "video_cc_mvs0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &video_cc_mvs0c_gdsc.pd,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL_TRIGGER,
+};
+
+static struct clk_regmap *video_cc_eliza_clocks[] = {
+ [VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr,
+ [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
+ [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
+ [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
+ [VIDEO_CC_MVS0_SHIFT_CLK] = &video_cc_mvs0_shift_clk.clkr,
+ [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
+ [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
+ [VIDEO_CC_MVS0C_SHIFT_CLK] = &video_cc_mvs0c_shift_clk.clkr,
+ [VIDEO_CC_PLL0] = &video_cc_pll0.clkr,
+ [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
+ [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,
+};
+
+static struct gdsc *video_cc_eliza_gdscs[] = {
+ [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
+ [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
+};
+
+static const struct qcom_reset_map video_cc_eliza_resets[] = {
+ [VIDEO_CC_INTERFACE_BCR] = { 0x80d8 },
+ [VIDEO_CC_MVS0_CLK_ARES] = { 0x80a0, 2 },
+ [VIDEO_CC_MVS0_BCR] = { 0x8088 },
+ [VIDEO_CC_MVS0C_CLK_ARES] = { 0x804c, 2 },
+ [VIDEO_CC_MVS0C_BCR] = { 0x8030 },
+ [VIDEO_CC_XO_CLK_ARES] = { 0x810c, 2 },
+};
+
+static struct clk_alpha_pll *video_cc_eliza_plls[] = {
+ &video_cc_pll0,
+};
+
+static u32 video_cc_eliza_critical_cbcrs[] = {
+ 0x80dc, /* VIDEO_CC_AHB_CLK */
+ 0x8128, /* VIDEO_CC_SLEEP_CLK */
+ 0x810c, /* VIDEO_CC_XO_CLK */
+};
+
+static const struct regmap_config video_cc_eliza_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x9f50,
+ .fast_io = true,
+};
+
+static struct qcom_cc_driver_data video_cc_eliza_driver_data = {
+ .alpha_plls = video_cc_eliza_plls,
+ .num_alpha_plls = ARRAY_SIZE(video_cc_eliza_plls),
+ .clk_cbcrs = video_cc_eliza_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(video_cc_eliza_critical_cbcrs),
+};
+
+static const struct qcom_cc_desc video_cc_eliza_desc = {
+ .config = &video_cc_eliza_regmap_config,
+ .clks = video_cc_eliza_clocks,
+ .num_clks = ARRAY_SIZE(video_cc_eliza_clocks),
+ .resets = video_cc_eliza_resets,
+ .num_resets = ARRAY_SIZE(video_cc_eliza_resets),
+ .gdscs = video_cc_eliza_gdscs,
+ .num_gdscs = ARRAY_SIZE(video_cc_eliza_gdscs),
+ .driver_data = &video_cc_eliza_driver_data,
+};
+
+static const struct of_device_id video_cc_eliza_match_table[] = {
+ { .compatible = "qcom,eliza-videocc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, video_cc_eliza_match_table);
+
+static int video_cc_eliza_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &video_cc_eliza_desc);
+}
+
+static struct platform_driver video_cc_eliza_driver = {
+ .probe = video_cc_eliza_probe,
+ .driver = {
+ .name = "videocc-eliza",
+ .of_match_table = video_cc_eliza_match_table,
+ },
+};
+
+module_platform_driver(video_cc_eliza_driver);
+
+MODULE_DESCRIPTION("QTI VIDEOCC Eliza Driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v2 3/8] dt-bindings: clock: qcom: Add support for CAMCC for Eliza
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Update the compatible and the bindings for CAMCC support on Eliza SoC.
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
.../bindings/clock/qcom,eliza-camcc.yaml | 55 ++++++++
.../dt-bindings/clock/qcom,eliza-cambistmclkcc.h | 32 +++++
include/dt-bindings/clock/qcom,eliza-camcc.h | 151 +++++++++++++++++++++
3 files changed, 238 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/qcom,eliza-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,eliza-camcc.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8f7c73707f713eba2e0938fcacbc5542e2de0892
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,eliza-camcc.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,eliza-camcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Camera Clock & Reset Controller on Eliza
+
+maintainers:
+ - Taniya Das <taniya.das@oss.qualcomm.com>
+
+description: |
+ Qualcomm camera clock control module provides the clocks, resets and power
+ domains on Eliza.
+
+ See also:
+ include/dt-bindings/clock/qcom,eliza-camcc.h
+ include/dt-bindings/clock/qcom,eliza-cambistmclkcc.h
+
+properties:
+ compatible:
+ enum:
+ - qcom,eliza-cambistmclkcc
+ - qcom,eliza-camcc
+
+ clocks:
+ items:
+ - description: Camera AHB clock from GCC
+ - description: Board XO source
+ - description: Sleep clock source
+
+required:
+ - compatible
+ - clocks
+
+allOf:
+ - $ref: qcom,gcc.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,eliza-gcc.h>
+ clock-controller@adb0000 {
+ compatible = "qcom,eliza-camcc";
+ reg = <0x0adb0000 0x40000>;
+ clocks = <&bi_tcxo_div2>,
+ <&sleep_clk>,
+ <&gcc GCC_CAMERA_AHB_CLK>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+...
diff --git a/include/dt-bindings/clock/qcom,eliza-cambistmclkcc.h b/include/dt-bindings/clock/qcom,eliza-cambistmclkcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b8b285f18d2714393885149fc97c715b3fbb042
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,eliza-cambistmclkcc.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_ELIZA_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_BIST_MCLK_CC_ELIZA_H
+
+/* CAM_BIST_MCLK_CC clocks */
+#define CAM_BIST_MCLK_CC_MCLK0_CLK 0
+#define CAM_BIST_MCLK_CC_MCLK0_CLK_SRC 1
+#define CAM_BIST_MCLK_CC_MCLK1_CLK 2
+#define CAM_BIST_MCLK_CC_MCLK1_CLK_SRC 3
+#define CAM_BIST_MCLK_CC_MCLK2_CLK 4
+#define CAM_BIST_MCLK_CC_MCLK2_CLK_SRC 5
+#define CAM_BIST_MCLK_CC_MCLK3_CLK 6
+#define CAM_BIST_MCLK_CC_MCLK3_CLK_SRC 7
+#define CAM_BIST_MCLK_CC_MCLK4_CLK 8
+#define CAM_BIST_MCLK_CC_MCLK4_CLK_SRC 9
+#define CAM_BIST_MCLK_CC_MCLK5_CLK 10
+#define CAM_BIST_MCLK_CC_MCLK5_CLK_SRC 11
+#define CAM_BIST_MCLK_CC_MCLK6_CLK 12
+#define CAM_BIST_MCLK_CC_MCLK6_CLK_SRC 13
+#define CAM_BIST_MCLK_CC_MCLK7_CLK 14
+#define CAM_BIST_MCLK_CC_MCLK7_CLK_SRC 15
+#define CAM_BIST_MCLK_CC_PLL0 16
+#define CAM_BIST_MCLK_CC_PLL_TEST_CLK 17
+#define CAM_BIST_MCLK_CC_PLL_TEST_DIV_CLK_SRC 18
+#define CAM_BIST_MCLK_CC_SLEEP_CLK 19
+#define CAM_BIST_MCLK_CC_SLEEP_CLK_SRC 20
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,eliza-camcc.h b/include/dt-bindings/clock/qcom,eliza-camcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..d85ef9777d08d12ec349d57f6da5e76a305404f8
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,eliza-camcc.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_ELIZA_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_CC_ELIZA_H
+
+/* CAM_CC clocks */
+#define CAM_CC_CAM_TOP_AHB_CLK 0
+#define CAM_CC_CAM_TOP_FAST_AHB_CLK 1
+#define CAM_CC_CAMNOC_DCD_XO_CLK 2
+#define CAM_CC_CAMNOC_NRT_AXI_CLK 3
+#define CAM_CC_CAMNOC_NRT_CRE_CLK 4
+#define CAM_CC_CAMNOC_NRT_IPE_NPS_CLK 5
+#define CAM_CC_CAMNOC_NRT_OFE_ANCHOR_CLK 6
+#define CAM_CC_CAMNOC_NRT_OFE_HDR_CLK 7
+#define CAM_CC_CAMNOC_NRT_OFE_MAIN_CLK 8
+#define CAM_CC_CAMNOC_RT_AXI_CLK 9
+#define CAM_CC_CAMNOC_RT_AXI_CLK_SRC 10
+#define CAM_CC_CAMNOC_RT_IFE_LITE_CLK 11
+#define CAM_CC_CAMNOC_RT_TFE_0_BAYER_CLK 12
+#define CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK 13
+#define CAM_CC_CAMNOC_RT_TFE_1_BAYER_CLK 14
+#define CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK 15
+#define CAM_CC_CAMNOC_RT_TFE_2_BAYER_CLK 16
+#define CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK 17
+#define CAM_CC_CAMNOC_XO_CLK 18
+#define CAM_CC_CCI_0_CLK 19
+#define CAM_CC_CCI_0_CLK_SRC 20
+#define CAM_CC_CCI_1_CLK 21
+#define CAM_CC_CCI_1_CLK_SRC 22
+#define CAM_CC_CCI_2_CLK 23
+#define CAM_CC_CCI_2_CLK_SRC 24
+#define CAM_CC_CORE_AHB_CLK 25
+#define CAM_CC_CPHY_RX_CLK_SRC 26
+#define CAM_CC_CRE_AHB_CLK 27
+#define CAM_CC_CRE_CLK 28
+#define CAM_CC_CRE_CLK_SRC 29
+#define CAM_CC_CSI0PHYTIMER_CLK 30
+#define CAM_CC_CSI0PHYTIMER_CLK_SRC 31
+#define CAM_CC_CSI1PHYTIMER_CLK 32
+#define CAM_CC_CSI1PHYTIMER_CLK_SRC 33
+#define CAM_CC_CSI2PHYTIMER_CLK 34
+#define CAM_CC_CSI2PHYTIMER_CLK_SRC 35
+#define CAM_CC_CSI3PHYTIMER_CLK 36
+#define CAM_CC_CSI3PHYTIMER_CLK_SRC 37
+#define CAM_CC_CSI4PHYTIMER_CLK 38
+#define CAM_CC_CSI4PHYTIMER_CLK_SRC 39
+#define CAM_CC_CSI5PHYTIMER_CLK 40
+#define CAM_CC_CSI5PHYTIMER_CLK_SRC 41
+#define CAM_CC_CSID_CLK 42
+#define CAM_CC_CSID_CLK_SRC 43
+#define CAM_CC_CSID_CSIPHY_RX_CLK 44
+#define CAM_CC_CSIPHY0_CLK 45
+#define CAM_CC_CSIPHY1_CLK 46
+#define CAM_CC_CSIPHY2_CLK 47
+#define CAM_CC_CSIPHY3_CLK 48
+#define CAM_CC_CSIPHY4_CLK 49
+#define CAM_CC_CSIPHY5_CLK 50
+#define CAM_CC_DRV_AHB_CLK 51
+#define CAM_CC_DRV_XO_CLK 52
+#define CAM_CC_FAST_AHB_CLK_SRC 53
+#define CAM_CC_GDSC_CLK 54
+#define CAM_CC_ICP_0_AHB_CLK 55
+#define CAM_CC_ICP_0_CLK 56
+#define CAM_CC_ICP_0_CLK_SRC 57
+#define CAM_CC_ICP_1_AHB_CLK 58
+#define CAM_CC_ICP_1_CLK 59
+#define CAM_CC_ICP_1_CLK_SRC 60
+#define CAM_CC_IFE_LITE_AHB_CLK 61
+#define CAM_CC_IFE_LITE_CLK 62
+#define CAM_CC_IFE_LITE_CLK_SRC 63
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK 64
+#define CAM_CC_IFE_LITE_CSID_CLK 65
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC 66
+#define CAM_CC_IPE_NPS_AHB_CLK 67
+#define CAM_CC_IPE_NPS_CLK 68
+#define CAM_CC_IPE_NPS_CLK_SRC 69
+#define CAM_CC_IPE_NPS_FAST_AHB_CLK 70
+#define CAM_CC_IPE_PPS_CLK 71
+#define CAM_CC_IPE_PPS_FAST_AHB_CLK 72
+#define CAM_CC_JPEG_0_CLK 73
+#define CAM_CC_JPEG_1_CLK 74
+#define CAM_CC_JPEG_CLK_SRC 75
+#define CAM_CC_OFE_AHB_CLK 76
+#define CAM_CC_OFE_ANCHOR_CLK 77
+#define CAM_CC_OFE_ANCHOR_FAST_AHB_CLK 78
+#define CAM_CC_OFE_CLK_SRC 79
+#define CAM_CC_OFE_HDR_CLK 80
+#define CAM_CC_OFE_HDR_FAST_AHB_CLK 81
+#define CAM_CC_OFE_MAIN_CLK 82
+#define CAM_CC_OFE_MAIN_FAST_AHB_CLK 83
+#define CAM_CC_PLL0 84
+#define CAM_CC_PLL0_OUT_EVEN 85
+#define CAM_CC_PLL0_OUT_ODD 86
+#define CAM_CC_PLL1 87
+#define CAM_CC_PLL1_OUT_EVEN 88
+#define CAM_CC_PLL2 89
+#define CAM_CC_PLL2_OUT_EVEN 90
+#define CAM_CC_PLL3 91
+#define CAM_CC_PLL3_OUT_EVEN 92
+#define CAM_CC_PLL4 93
+#define CAM_CC_PLL4_OUT_EVEN 94
+#define CAM_CC_PLL5 95
+#define CAM_CC_PLL5_OUT_EVEN 96
+#define CAM_CC_PLL6 97
+#define CAM_CC_PLL6_OUT_EVEN 98
+#define CAM_CC_PLL6_OUT_ODD 99
+#define CAM_CC_QDSS_DEBUG_CLK 100
+#define CAM_CC_QDSS_DEBUG_CLK_SRC 101
+#define CAM_CC_QDSS_DEBUG_XO_CLK 102
+#define CAM_CC_SLEEP_CLK 103
+#define CAM_CC_SLEEP_CLK_SRC 104
+#define CAM_CC_SLOW_AHB_CLK_SRC 105
+#define CAM_CC_TFE_0_BAYER_CLK 106
+#define CAM_CC_TFE_0_BAYER_FAST_AHB_CLK 107
+#define CAM_CC_TFE_0_CLK_SRC 108
+#define CAM_CC_TFE_0_MAIN_CLK 109
+#define CAM_CC_TFE_0_MAIN_FAST_AHB_CLK 110
+#define CAM_CC_TFE_1_BAYER_CLK 111
+#define CAM_CC_TFE_1_BAYER_FAST_AHB_CLK 112
+#define CAM_CC_TFE_1_CLK_SRC 113
+#define CAM_CC_TFE_1_MAIN_CLK 114
+#define CAM_CC_TFE_1_MAIN_FAST_AHB_CLK 115
+#define CAM_CC_TFE_2_BAYER_CLK 116
+#define CAM_CC_TFE_2_BAYER_FAST_AHB_CLK 117
+#define CAM_CC_TFE_2_CLK_SRC 118
+#define CAM_CC_TFE_2_MAIN_CLK 119
+#define CAM_CC_TFE_2_MAIN_FAST_AHB_CLK 120
+#define CAM_CC_XO_CLK_SRC 121
+
+/* CAM_CC power domains */
+#define CAM_CC_IPE_0_GDSC 0
+#define CAM_CC_OFE_GDSC 1
+#define CAM_CC_TFE_0_GDSC 2
+#define CAM_CC_TFE_1_GDSC 3
+#define CAM_CC_TFE_2_GDSC 4
+#define CAM_CC_TITAN_TOP_GDSC 5
+
+/* CAM_CC resets */
+#define CAM_CC_DRV_BCR 0
+#define CAM_CC_ICP_BCR 1
+#define CAM_CC_IPE_0_BCR 2
+#define CAM_CC_OFE_BCR 3
+#define CAM_CC_QDSS_DEBUG_BCR 4
+#define CAM_CC_TFE_0_BCR 5
+#define CAM_CC_TFE_1_BCR 6
+#define CAM_CC_TFE_2_BCR 7
+
+#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/8] dt-bindings: clock: qcom: document the Eliza GPU Clock Controller
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Add bindings documentation for the Eliza Graphics Clock Controller.
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
.../bindings/clock/qcom,sm8450-gpucc.yaml | 3 ++
include/dt-bindings/clock/qcom,eliza-gpucc.h | 52 ++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml
index fdbdf605ee695637512ce4f98c9b6fcfacb9154f..734bab762a30800bda94c726f48013679f9ec542 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml
@@ -15,6 +15,7 @@ description: |
domains on Qualcomm SoCs.
See also:
+ include/dt-bindings/clock/qcom,eliza-gpucc.h
include/dt-bindings/clock/qcom,glymur-gpucc.h
include/dt-bindings/clock/qcom,kaanapali-gpucc.h
include/dt-bindings/clock/qcom,milos-gpucc.h
@@ -30,6 +31,7 @@ description: |
properties:
compatible:
enum:
+ - qcom,eliza-gpucc
- qcom,glymur-gpucc
- qcom,kaanapali-gpucc
- qcom,milos-gpucc
@@ -71,6 +73,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,eliza-gpucc
- qcom,sm8750-gpucc
then:
required:
diff --git a/include/dt-bindings/clock/qcom,eliza-gpucc.h b/include/dt-bindings/clock/qcom,eliza-gpucc.h
new file mode 100644
index 0000000000000000000000000000000000000000..706e1c93240a8234dd8017ee181d19e58091fd6d
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,eliza-gpucc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_ELIZA_H
+#define _DT_BINDINGS_CLK_QCOM_GPU_CC_ELIZA_H
+
+/* GPU_CC clocks */
+#define GPU_CC_AHB_CLK 0
+#define GPU_CC_CRC_AHB_CLK 1
+#define GPU_CC_CX_ACCU_SHIFT_CLK 2
+#define GPU_CC_CX_FF_CLK 3
+#define GPU_CC_CX_GMU_CLK 4
+#define GPU_CC_CXO_AON_CLK 5
+#define GPU_CC_CXO_CLK 6
+#define GPU_CC_DEMET_CLK 7
+#define GPU_CC_DEMET_DIV_CLK_SRC 8
+#define GPU_CC_FF_CLK_SRC 9
+#define GPU_CC_FREQ_MEASURE_CLK 10
+#define GPU_CC_GMU_CLK_SRC 11
+#define GPU_CC_GPU_SMMU_VOTE_CLK 12
+#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK 13
+#define GPU_CC_HUB_AON_CLK 14
+#define GPU_CC_HUB_CLK_SRC 15
+#define GPU_CC_HUB_CX_INT_CLK 16
+#define GPU_CC_MEMNOC_GFX_CLK 17
+#define GPU_CC_MND1X_0_GFX3D_CLK 18
+#define GPU_CC_MND1X_1_GFX3D_CLK 19
+#define GPU_CC_PLL0 20
+#define GPU_CC_PLL1 21
+#define GPU_CC_SLEEP_CLK 22
+#define GPU_CC_XO_CLK_SRC 23
+#define GPU_CC_XO_DIV_CLK_SRC 24
+
+/* GPU_CC power domains */
+#define GPU_CC_CX_GDSC 0
+#define GPU_CC_GX_GDSC 1
+
+/* GPU_CC resets */
+#define GPU_CC_ACD_BCR 0
+#define GPU_CC_CB_BCR 1
+#define GPU_CC_CX_BCR 2
+#define GPU_CC_FAST_HUB_BCR 3
+#define GPU_CC_FF_BCR 4
+#define GPU_CC_GFX3D_AON_BCR 5
+#define GPU_CC_GMU_BCR 6
+#define GPU_CC_GX_BCR 7
+#define GPU_CC_RBCPR_BCR 8
+#define GPU_CC_XO_BCR 9
+
+#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/8] dt-bindings: clock: qcom: Add video clock controller on Eliza SoC
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-0-bc0c6dd77bc5@oss.qualcomm.com>
Add compatible string for Eliza video clock controller and the bindings
for Eliza Qualcomm SoC.
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
.../bindings/clock/qcom,eliza-videocc.yaml | 51 ++++++++++++++++++++++
include/dt-bindings/clock/qcom,eliza-videocc.h | 37 ++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/qcom,eliza-videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,eliza-videocc.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..26a0c85f26b13ca8e7a4f5f418e8c98235f10558
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,eliza-videocc.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,eliza-videocc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Video Clock & Reset Controller on Eliza
+
+maintainers:
+ - Taniya Das <taniya.das@oss.qualcomm.com>
+
+description: |
+ Qualcomm video clock control module provides the clocks, resets and power
+ domains on Eliza.
+
+ See also: include/dt-bindings/clock/qcom,eliza-videocc.h
+
+properties:
+ compatible:
+ const: qcom,eliza-videocc
+
+ clocks:
+ items:
+ - description: Board XO source
+ - description: Sleep clock source
+ - description: Video AHB clock from GCC
+
+required:
+ - compatible
+ - clocks
+
+allOf:
+ - $ref: qcom,gcc.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,eliza-gcc.h>
+ clock-controller@aaf0000 {
+ compatible = "qcom,eliza-videocc";
+ reg = <0x0aaf0000 0x10000>;
+ clocks = <&bi_tcxo_div2>,
+ <&sleep_clk>,
+ <&gcc GCC_VIDEO_AHB_CLK>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+...
diff --git a/include/dt-bindings/clock/qcom,eliza-videocc.h b/include/dt-bindings/clock/qcom,eliza-videocc.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e922250a7fae77f5c996208d50ff372b252aa51
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,eliza-videocc.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_VIDEO_CC_ELIZA_H
+#define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_ELIZA_H
+
+/* VIDEO_CC clocks */
+#define VIDEO_CC_AHB_CLK 0
+#define VIDEO_CC_AHB_CLK_SRC 1
+#define VIDEO_CC_MVS0_CLK 2
+#define VIDEO_CC_MVS0_CLK_SRC 3
+#define VIDEO_CC_MVS0_DIV_CLK_SRC 4
+#define VIDEO_CC_MVS0_SHIFT_CLK 5
+#define VIDEO_CC_MVS0C_CLK 6
+#define VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC 7
+#define VIDEO_CC_MVS0C_SHIFT_CLK 8
+#define VIDEO_CC_PLL0 9
+#define VIDEO_CC_SLEEP_CLK 10
+#define VIDEO_CC_SLEEP_CLK_SRC 11
+#define VIDEO_CC_XO_CLK 12
+#define VIDEO_CC_XO_CLK_SRC 13
+
+/* VIDEO_CC power domains */
+#define VIDEO_CC_MVS0_GDSC 0
+#define VIDEO_CC_MVS0C_GDSC 1
+
+/* VIDEO_CC resets */
+#define VIDEO_CC_INTERFACE_BCR 0
+#define VIDEO_CC_MVS0_CLK_ARES 1
+#define VIDEO_CC_MVS0_BCR 2
+#define VIDEO_CC_MVS0C_CLK_ARES 3
+#define VIDEO_CC_MVS0C_BCR 4
+#define VIDEO_CC_XO_CLK_ARES 5
+
+#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/8] Add support for Video, Camera, Graphics clock controllers on Eliza
From: Taniya Das @ 2026-04-09 18:10 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, Taniya Das, Konrad Dybcio
Add driver for Eliza SoC camera, graphics and Video clock controllers.
The camera clock controller supports the cambist clock controller and
the regular camera clock controller.
The patches have been tested on Qualcomm Eliza MTP board.
Changes in v2:
- rebased the patches on the latest linux-next.
- Add new bindings for Video and Camcc.
- Remove commented code in GPUCC (limiter code).
- Add device nodes for the corresponding clock controllers.
- Add RB-by tags for VideoCC and CamCC/Cambistmclk from v1.
- Link to v1: https://lore.kernel.org/r/20260317-eliza_mm_clock_controllers_v1-v1-0-4696eeda8cfb@oss.qualcomm.com
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
---
Taniya Das (8):
dt-bindings: clock: qcom: Add video clock controller on Eliza SoC
dt-bindings: clock: qcom: document the Eliza GPU Clock Controller
dt-bindings: clock: qcom: Add support for CAMCC for Eliza
clk: qcom: videocc: Add video clock controller driver for Eliza
clk: qcom: gpucc: Add GPU Clock Controller driver for Eliza
clk: qcom: camcc: Add support for camera clock controller for Eliza
arm64: defconfig: Enable clock controllers on Qualcomm Eliza SoC
arm64: dts: qcom: eliza: Add support for MM clock controllers
.../bindings/clock/qcom,eliza-camcc.yaml | 55 +
.../bindings/clock/qcom,eliza-videocc.yaml | 51 +
.../bindings/clock/qcom,sm8450-gpucc.yaml | 3 +
arch/arm64/boot/dts/qcom/eliza.dtsi | 54 +
arch/arm64/configs/defconfig | 3 +
drivers/clk/qcom/Kconfig | 28 +
drivers/clk/qcom/Makefile | 3 +
drivers/clk/qcom/cambistmclkcc-eliza.c | 465 ++++
drivers/clk/qcom/camcc-eliza.c | 2803 ++++++++++++++++++++
drivers/clk/qcom/gpucc-eliza.c | 621 +++++
drivers/clk/qcom/videocc-eliza.c | 403 +++
.../dt-bindings/clock/qcom,eliza-cambistmclkcc.h | 32 +
include/dt-bindings/clock/qcom,eliza-camcc.h | 151 ++
include/dt-bindings/clock/qcom,eliza-gpucc.h | 52 +
include/dt-bindings/clock/qcom,eliza-videocc.h | 37 +
15 files changed, 4761 insertions(+)
---
base-commit: db7efce4ae23ad5e42f5f55428f529ff62b86fab
change-id: 20260409-eliza_mm_cc_v2-701c34ddb74e
Best regards,
--
Taniya Das <taniya.das@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v2 0/2] pinctrl: qcom: Introduce Pinctrl for Hawi SoC
From: Trilok Soni @ 2026-04-09 17:59 UTC (permalink / raw)
To: Linus Walleij, Mukesh Ojha
Cc: Bjorn Andersson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-msm, linux-gpio, devicetree, linux-kernel,
Konrad Dybcio
In-Reply-To: <CAD++jLkVHZOBk3bgdqk0dX2q4v=+CD8jC+1vu2gi8CK9BLfX2w@mail.gmail.com>
On 4/9/2026 1:53 AM, Linus Walleij wrote:
> On Wed, Apr 8, 2026 at 4:16 PM Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> wrote:
>
>> Introduce Top Level Mode Multiplexer dt-binding and driver for upcoming
>> Qualcomm Hawi SoC.
>
> All was reviewed quickly so patches applied for kernel v7.1,
> because why not.
Thank you Linus.
---Trilok Soni
^ permalink raw reply
* Re: [PATCH 3/4] staging: iio: magnetometer: Add QST QMC5883P driver
From: Luka Gejak @ 2026-04-09 17:54 UTC (permalink / raw)
To: Hardik Phalet, Greg Kroah-Hartman
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brigham Campbell,
Shuah Khan, linux-iio, devicetree, linux-kernel, linux-staging,
Luka Gejak
In-Reply-To: <20260409162308.2590385-4-hardik.phalet@pm.me>
On Thu Apr 9, 2026 at 6:24 PM CEST, Hardik Phalet wrote:
> Add an IIO driver for the QST QMC5883P 3-axis magnetometer. The device
> communicates over I2C and is managed via regmap with an rbtree cache.
> Regmap fields are used to access the individual bit fields in CTRL_1 and
> CTRL_2 registers.
>
> The driver supports:
> - Raw magnetic field readings on X, Y and Z axes
> - Four full-scale ranges (±2 G, ±8 G, ±12 G, ±30 G)
> - Configurable output data rate (10, 50, 100, 200 Hz)
> - Configurable oversampling ratio (1, 2, 4, 8)
> - Configurable downsampling ratio (1, 2, 4, 8) via a custom sysfs attr
> - Runtime PM with a 2 s autosuspend delay
>
> Known limitations tracked in TODO:
> - No triggered buffer support
> - No DRDY interrupt support
> - Self-test register field is unused
>
> Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
> ---
> drivers/staging/iio/Kconfig | 1 +
> drivers/staging/iio/Makefile | 1 +
> drivers/staging/iio/magnetometer/Kconfig | 20 +
> drivers/staging/iio/magnetometer/Makefile | 7 +
> drivers/staging/iio/magnetometer/TODO | 5 +
> drivers/staging/iio/magnetometer/qmc5883p.c | 819 ++++++++++++++++++++
> 6 files changed, 853 insertions(+)
> create mode 100644 drivers/staging/iio/magnetometer/Kconfig
> create mode 100644 drivers/staging/iio/magnetometer/Makefile
> create mode 100644 drivers/staging/iio/magnetometer/TODO
> create mode 100644 drivers/staging/iio/magnetometer/qmc5883p.c
>
> diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
> index a60631c1f449..d363e163d248 100644
> --- a/drivers/staging/iio/Kconfig
> +++ b/drivers/staging/iio/Kconfig
> @@ -10,5 +10,6 @@ source "drivers/staging/iio/adc/Kconfig"
> source "drivers/staging/iio/addac/Kconfig"
> source "drivers/staging/iio/frequency/Kconfig"
> source "drivers/staging/iio/impedance-analyzer/Kconfig"
> +source "drivers/staging/iio/magnetometer/Kconfig"
>
> endmenu
> diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
> index 628583535393..7dcbb75d43f0 100644
> --- a/drivers/staging/iio/Makefile
> +++ b/drivers/staging/iio/Makefile
> @@ -8,3 +8,4 @@ obj-y += adc/
> obj-y += addac/
> obj-y += frequency/
> obj-y += impedance-analyzer/
> +obj-y += magnetometer/
> diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
> new file mode 100644
> index 000000000000..d631da9578a1
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/Kconfig
> @@ -0,0 +1,20 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Magnetometer sensors
> +#
> +# When adding new entries keep the list in alphabetical order
> +
> +menu "Magnetometer sensors"
> +
> +config QMC5883P
> + tristate "QMC5883P 3-Axis Magnetometer"
> + depends on I2C
> + select REGMAP_I2C
> + help
> + Say yes here to build support for QMC5883P I2C-based
> + 3-axis magnetometer chip.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called qmc5883p.
> +
> +endmenu
> diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
> new file mode 100644
> index 000000000000..8e650f2e3b02
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/Makefile
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Makefile for staging industrial I/O Magnetometer sensor devices
> +#
> +# When adding new entries keep the list in alphabetical order
> +
> +obj-$(CONFIG_QMC5883P) += qmc5883p.o
> diff --git a/drivers/staging/iio/magnetometer/TODO b/drivers/staging/iio/magnetometer/TODO
> new file mode 100644
> index 000000000000..6a8084c0dded
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/TODO
> @@ -0,0 +1,5 @@
> +TODO
> +====
> +- Implement triggered buffer support (iio_triggered_buffer_setup)
> +- Add interrupt (DRDY) support
> +- Implement self-test (selftest regmap field is unused)
> diff --git a/drivers/staging/iio/magnetometer/qmc5883p.c b/drivers/staging/iio/magnetometer/qmc5883p.c
> new file mode 100644
> index 000000000000..6a71dc47efb9
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/qmc5883p.c
> @@ -0,0 +1,819 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * qmc5883p.c - QMC5883P magnetometer driver
> + *
> + * Copyright 2026 Hardik Phalet <hardik.phalet@pm.me>
> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/cleanup.h>
> +#include <linux/delay.h>
> +#include <linux/dev_printk.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/types.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/pm.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +/* Register definition */
> +#define QMC5883P_REG_CHIP_ID 0x00
> +#define QMC5883P_REG_X_LSB 0x01
> +#define QMC5883P_REG_X_MSB 0x02
> +#define QMC5883P_REG_Y_LSB 0x03
> +#define QMC5883P_REG_Y_MSB 0x04
> +#define QMC5883P_REG_Z_LSB 0x05
> +#define QMC5883P_REG_Z_MSB 0x06
> +#define QMC5883P_REG_STATUS 0x09
> +#define QMC5883P_REG_CTRL_1 0x0A
> +#define QMC5883P_REG_CTRL_2 0x0B
> +
> +/* Value definition */
> +#define QMC5883P_MODE_SUSPEND 0x00
> +#define QMC5883P_MODE_NORMAL 0x01
> +#define QMC5883P_MODE_SINGLE 0x02
> +#define QMC5883P_MODE_CONTINUOUS 0x03
> +
> +/* Output data rate */
> +#define QMC5883P_ODR_10 0x00
> +#define QMC5883P_ODR_50 0x01
> +#define QMC5883P_ODR_100 0x02
> +#define QMC5883P_ODR_200 0x03
> +
> +/* Oversampling rate */
> +#define QMC5883P_OSR_8 0x00
> +#define QMC5883P_OSR_4 0x01
> +#define QMC5883P_OSR_2 0x02
> +#define QMC5883P_OSR_1 0x03
> +
> +/* Downsampling rate */
> +#define QMC5883P_DSR_1 0x00
> +#define QMC5883P_DSR_2 0x01
> +#define QMC5883P_DSR_4 0x02
> +#define QMC5883P_DSR_8 0x03
> +
> +#define QMC5883P_RSTCTRL_SET_RESET \
> + 0x00 /* Set and reset on, i.e. the offset of device is renewed */
> +#define QMC5883P_RSTCTRL_SET_ONLY 0x01 /* Set only on */
> +#define QMC5883P_RSTCTRL_OFF 0x02 /* Set and reset off */
> +
> +#define QMC5883P_RNG_30G 0x00
> +#define QMC5883P_RNG_12G 0x01
> +#define QMC5883P_RNG_08G 0x02
> +#define QMC5883P_RNG_02G 0x03
> +
> +#define QMC5883P_DEFAULT_ODR QMC5883P_ODR_100
> +#define QMC5883P_DEFAULT_OSR QMC5883P_OSR_4
> +#define QMC5883P_DEFAULT_DSR QMC5883P_DSR_4
> +#define QMC5883P_DEFAULT_RNG QMC5883P_RNG_08G
> +
> +#define QMC5883P_DRDY_POLL_US 1000
> +
> +#define QMC5883P_CHIP_ID 0x80
> +
> +#define QMC5883P_STATUS_DRDY BIT(0)
> +#define QMC5883P_STATUS_OVFL BIT(1)
> +
> +/*
> + * Scale factors in T/LSB for IIO_VAL_FRACTIONAL (val/val2), derived from
> + * datasheet Table 2 sensitivities (LSB/G) converted to LSB/T (1 G = 1e-4 T):
> + * sensitivity_T = sensitivity_G * 10000
> + * scale = 1 / sensitivity_T
> + *
> + * Index matches register value: RNG<1:0> = 0b00..0b11
> + */
> +static const int qmc5883p_scale[][2] = {
> + [QMC5883P_RNG_30G] = { 1, 10000000 },
> + [QMC5883P_RNG_12G] = { 1, 25000000 },
> + [QMC5883P_RNG_08G] = { 1, 37500000 },
> + [QMC5883P_RNG_02G] = { 1, 150000000 },
> +};
> +
> +static const int qmc5883p_odr[] = {
> + [QMC5883P_ODR_10] = 10,
> + [QMC5883P_ODR_50] = 50,
> + [QMC5883P_ODR_100] = 100,
> + [QMC5883P_ODR_200] = 200,
> +};
> +
> +static const int qmc5883p_osr[] = {
> + [QMC5883P_OSR_1] = 1,
> + [QMC5883P_OSR_2] = 2,
> + [QMC5883P_OSR_4] = 4,
> + [QMC5883P_OSR_8] = 8,
> +};
> +
> +static const unsigned int qmc5883p_dsr[] = {
> + [QMC5883P_DSR_1] = 1,
> + [QMC5883P_DSR_2] = 2,
> + [QMC5883P_DSR_4] = 4,
> + [QMC5883P_DSR_8] = 8,
> +};
> +
> +struct qmc5883p_rf {
> + struct regmap_field *osr;
> + struct regmap_field *dsr;
> + struct regmap_field *odr;
> + struct regmap_field *mode;
> + struct regmap_field *rng;
> + struct regmap_field *rstctrl;
> + struct regmap_field *sftrst;
> + struct regmap_field *selftest;
> + struct regmap_field *chip_id;
> +};
> +
> +static const struct regmap_range qmc5883p_readable_ranges[] = {
> + regmap_reg_range(QMC5883P_REG_CHIP_ID, QMC5883P_REG_STATUS),
> + regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2),
> +};
> +
> +static const struct regmap_range qmc5883p_writable_ranges[] = {
> + regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2),
> +};
> +
> +/*
> + * Volatile registers: hardware updates these independently of the driver.
> + * regmap will never serve these from cache.
> + */
> +static const struct regmap_range qmc5883p_volatile_ranges[] = {
> + regmap_reg_range(QMC5883P_REG_X_LSB, QMC5883P_REG_Z_MSB),
> + regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS),
> +};
> +
> +/*
> + * Precious registers: reading has a side effect (clears DRDY/OVFL bits).
> + * regmap will never read these speculatively.
> + */
> +static const struct regmap_range qmc5883p_precious_ranges[] = {
> + regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS),
> +};
> +
> +static const struct regmap_access_table qmc5883p_readable_table = {
> + .yes_ranges = qmc5883p_readable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(qmc5883p_readable_ranges),
> +};
> +
> +static const struct regmap_access_table qmc5883p_writable_table = {
> + .yes_ranges = qmc5883p_writable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(qmc5883p_writable_ranges),
> +};
> +
> +static const struct regmap_access_table qmc5883p_volatile_table = {
> + .yes_ranges = qmc5883p_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(qmc5883p_volatile_ranges),
> +};
> +
> +static const struct regmap_access_table qmc5883p_precious_table = {
> + .yes_ranges = qmc5883p_precious_ranges,
> + .n_yes_ranges = ARRAY_SIZE(qmc5883p_precious_ranges),
> +};
> +
> +static const struct regmap_config qmc5883p_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = 0x0B,
> + .cache_type = REGCACHE_RBTREE,
> + .rd_table = &qmc5883p_readable_table,
> + .wr_table = &qmc5883p_writable_table,
> + .volatile_table = &qmc5883p_volatile_table,
> + .precious_table = &qmc5883p_precious_table,
> +};
> +
> +struct qmc5883p_data {
> + struct device *dev;
> + struct regmap *regmap;
> + struct mutex mutex; /* protects regmap and rf field accesses */
> + struct qmc5883p_rf rf;
> +};
> +
> +enum qmc5883p_channels {
> + AXIS_X = 0,
> + AXIS_Y,
> + AXIS_Z,
> +};
> +
> +static const struct reg_field qmc5883p_rf_osr =
> + REG_FIELD(QMC5883P_REG_CTRL_1, 4, 5);
> +static const struct reg_field qmc5883p_rf_dsr =
> + REG_FIELD(QMC5883P_REG_CTRL_1, 6, 7);
> +static const struct reg_field qmc5883p_rf_odr =
> + REG_FIELD(QMC5883P_REG_CTRL_1, 2, 3);
> +static const struct reg_field qmc5883p_rf_mode =
> + REG_FIELD(QMC5883P_REG_CTRL_1, 0, 1);
> +static const struct reg_field qmc5883p_rf_rng =
> + REG_FIELD(QMC5883P_REG_CTRL_2, 2, 3);
> +static const struct reg_field qmc5883p_rf_rstctrl =
> + REG_FIELD(QMC5883P_REG_CTRL_2, 0, 1);
> +static const struct reg_field qmc5883p_rf_sftrst =
> + REG_FIELD(QMC5883P_REG_CTRL_2, 7, 7);
> +static const struct reg_field qmc5883p_rf_selftest =
> + REG_FIELD(QMC5883P_REG_CTRL_2, 6, 6);
> +static const struct reg_field qmc5883p_rf_chip_id =
> + REG_FIELD(QMC5883P_REG_CHIP_ID, 0, 7);
> +
> +static int qmc5883p_rf_init(struct qmc5883p_data *data)
> +{
> + struct regmap *regmap = data->regmap;
> + struct device *dev = data->dev;
> + struct qmc5883p_rf *rf = &data->rf;
> +
> + rf->osr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_osr);
> + if (IS_ERR(rf->osr))
> + return PTR_ERR(rf->osr);
> +
> + rf->dsr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_dsr);
> + if (IS_ERR(rf->dsr))
> + return PTR_ERR(rf->dsr);
> +
> + rf->odr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_odr);
> + if (IS_ERR(rf->odr))
> + return PTR_ERR(rf->odr);
> +
> + rf->mode = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_mode);
> + if (IS_ERR(rf->mode))
> + return PTR_ERR(rf->mode);
> +
> + rf->rng = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rng);
> + if (IS_ERR(rf->rng))
> + return PTR_ERR(rf->rng);
> +
> + rf->rstctrl = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rstctrl);
> + if (IS_ERR(rf->rstctrl))
> + return PTR_ERR(rf->rstctrl);
> +
> + rf->sftrst = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_sftrst);
> + if (IS_ERR(rf->sftrst))
> + return PTR_ERR(rf->sftrst);
> +
> + rf->selftest =
> + devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_selftest);
> + if (IS_ERR(rf->selftest))
> + return PTR_ERR(rf->selftest);
> +
> + rf->chip_id = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_chip_id);
> + if (IS_ERR(rf->chip_id))
> + return PTR_ERR(rf->chip_id);
> +
> + return 0;
> +}
> +
> +static int qmc5883p_verify_chip_id(struct qmc5883p_data *data)
> +{
> + int ret, regval;
> +
> + ret = regmap_field_read(data->rf.chip_id, ®val);
> + if (ret)
> + return dev_err_probe(data->dev, ret,
> + "failed to read chip ID\n");
> +
> + if (regval != QMC5883P_CHIP_ID)
> + return dev_err_probe(data->dev, -ENODEV,
> + "unexpected chip ID 0x%02x, expected 0x%02x\n",
> + regval, QMC5883P_CHIP_ID);
> + return ret;
> +}
> +
> +static int qmc5883p_chip_init(struct qmc5883p_data *data)
> +{
> + int ret;
> +
> + ret = regmap_field_write(data->rf.sftrst, 1);
> + if (ret)
> + return ret;
> +
> + usleep_range(1000, 2000);
> +
> + ret = regmap_field_write(data->rf.sftrst, 0);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.rstctrl, QMC5883P_RSTCTRL_SET_RESET);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.rng, QMC5883P_DEFAULT_RNG);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.osr, QMC5883P_DEFAULT_OSR);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.dsr, QMC5883P_DEFAULT_DSR);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.odr, QMC5883P_DEFAULT_ODR);
> + if (ret)
> + return ret;
> +
> + return regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
> +}
> +
> +/*
> + * qmc5883p_get_measure - read all three axes.
> + * Must be called with data->mutex held.
> + * Handles PM internally: resumes device, reads data, schedules autosuspend.
> + */
> +static int qmc5883p_get_measure(struct qmc5883p_data *data, s16 *x, s16 *y,
> + s16 *z)
> +{
...
> +
> + *x = (s16)((reg_data[1] << 8) | reg_data[0]);
> + *y = (s16)((reg_data[3] << 8) | reg_data[2]);
> + *z = (s16)((reg_data[5] << 8) | reg_data[4]);
> +
While functionally correct, the standard kernel idiom for deserializing
contiguous byte arrays is to use the unaligned access helpers. Consider
including <linux/unaligned.h> at the top of the file and using
get_unaligned_le16(). Also since it returns a u16, you must keep the
(s16) cast. Something like:
*x = (s16)get_unaligned_le16(®_data[0]);
*y = (s16)get_unaligned_le16(®_data[2]);
*z = (s16)get_unaligned_le16(®_data[4]);
> +out:
> + pm_runtime_mark_last_busy(data->dev);
> + pm_runtime_put_autosuspend(data->dev);
> + return ret;
> +}
> +
> +static int qmc5883p_write_scale(struct qmc5883p_data *data, int val, int val2)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(qmc5883p_scale); i++) {
> + if (qmc5883p_scale[i][0] == val && qmc5883p_scale[i][1] == val2)
> + return regmap_field_write(data->rf.rng, i);
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int qmc5883p_write_odr(struct qmc5883p_data *data, int val)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(qmc5883p_odr); i++) {
> + if (qmc5883p_odr[i] == val)
> + return regmap_field_write(data->rf.odr, i);
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int qmc5883p_write_osr(struct qmc5883p_data *data, int val)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(qmc5883p_osr); i++) {
> + if (qmc5883p_osr[i] == val)
> + return regmap_field_write(data->rf.osr, i);
> + }
> +
> + return -EINVAL;
> +}
> +
> +static ssize_t downsampling_ratio_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct qmc5883p_data *data = iio_priv(indio_dev);
> + unsigned int regval;
> + int ret;
> +
> + guard(mutex)(&data->mutex);
> +
> + ret = regmap_field_read(data->rf.dsr, ®val);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", qmc5883p_dsr[regval]);
> +}
> +
> +static ssize_t downsampling_ratio_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
...
> + guard(mutex)(&data->mutex);
> +
> + ret = pm_runtime_resume_and_get(dev);
For iio sysfs attributes, the dev pointer belongs to the iio device
(&indio_dev->dev), not the i2c parent device where runtime pm was
initialized. Calling pm operations on the iio device will lead to pm
refcount imbalances and potential kernel warnings. You should use
data->dev for all pm_runtime_* calls inside custom sysfs callbacks.
Something like ret = pm_runtime_resume_and_get(data->dev);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
> + if (ret)
> + goto out;
> +
> + ret = -EINVAL;
> + for (i = 0; i < ARRAY_SIZE(qmc5883p_dsr); i++) {
> + if (qmc5883p_dsr[i] == val) {
> + ret = regmap_field_write(data->rf.dsr, i);
> + break;
> + }
> + }
> +
> + restore = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
> + if (restore && !ret)
> + ret = restore;
> +
> +out:
> + pm_runtime_mark_last_busy(dev);
> + pm_runtime_put_autosuspend(dev);
You should change these to use data->dev as well.
> + return ret ? ret : (ssize_t)len;
> +}
> +
> +static int qmc5883p_read_raw(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan, int *val,
> + int *val2, long mask)
> +{
> + s16 x, y, z;
> + struct qmc5883p_data *data = iio_priv(indio_dev);
> + int ret;
> + unsigned int regval;
> +
> + guard(mutex)(&data->mutex);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + ret = qmc5883p_get_measure(data, &x, &y, &z);
> + if (ret < 0)
> + return ret;
> + switch (chan->address) {
> + case AXIS_X:
> + *val = x;
> + break;
> + case AXIS_Y:
> + *val = y;
> + break;
> + case AXIS_Z:
> + *val = z;
> + break;
> + }
> + return IIO_VAL_INT;
> +
> + case IIO_CHAN_INFO_SCALE:
> + ret = regmap_field_read(data->rf.rng, ®val);
> + if (ret < 0)
> + return ret;
> + *val = qmc5883p_scale[regval][0];
> + *val2 = qmc5883p_scale[regval][1];
> + return IIO_VAL_FRACTIONAL;
> +
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + ret = regmap_field_read(data->rf.odr, ®val);
> + if (ret < 0)
> + return ret;
> + *val = qmc5883p_odr[regval];
> + return IIO_VAL_INT;
> +
> + case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
> + ret = regmap_field_read(data->rf.osr, ®val);
> + if (ret < 0)
> + return ret;
> + *val = qmc5883p_osr[regval];
> + return IIO_VAL_INT;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int qmc5883p_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int val,
> + int val2, long mask)
> +{
> + struct qmc5883p_data *data = iio_priv(indio_dev);
> + int ret, restore;
> +
> + guard(mutex)(&data->mutex);
> +
> + ret = pm_runtime_resume_and_get(data->dev);
> + if (ret)
> + return ret;
> +
> + ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
> + if (ret)
> + goto out;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + ret = qmc5883p_write_odr(data, val);
> + break;
> + case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
> + ret = qmc5883p_write_osr(data, val);
> + break;
> + case IIO_CHAN_INFO_SCALE:
> + ret = qmc5883p_write_scale(data, val, val2);
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + restore = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
> + if (restore && !ret)
> + ret = restore;
> +
> +out:
> + pm_runtime_mark_last_busy(data->dev);
> + pm_runtime_put_autosuspend(data->dev);
> + return ret;
> +}
> +
> +/*
> + * qmc5883p_read_avail - expose available values to userspace.
> + *
> + * Creates the _available sysfs attributes automatically:
> + * in_magn_sampling_frequency_available
> + * in_magn_oversampling_ratio_available
> + * in_magn_scale_available
> + */
> +static int qmc5883p_read_avail(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int **vals, int *type, int *length,
> + long mask)
> +{
> + switch (mask) {
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + *vals = qmc5883p_odr;
> + *type = IIO_VAL_INT;
> + *length = ARRAY_SIZE(qmc5883p_odr);
> + return IIO_AVAIL_LIST;
> +
> + case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
> + *vals = qmc5883p_osr;
> + *type = IIO_VAL_INT;
> + *length = ARRAY_SIZE(qmc5883p_osr);
> + return IIO_AVAIL_LIST;
> +
> + case IIO_CHAN_INFO_SCALE:
> + *vals = (const int *)qmc5883p_scale;
> + *type = IIO_VAL_FRACTIONAL;
> + *length = ARRAY_SIZE(qmc5883p_scale) * 2;
> + return IIO_AVAIL_LIST;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static IIO_DEVICE_ATTR(downsampling_ratio, 0644, downsampling_ratio_show,
> + downsampling_ratio_store, 0);
> +static IIO_CONST_ATTR(downsampling_ratio_available, "1 2 4 8");
> +
> +static struct attribute *qmc5883p_attributes[] = {
> + &iio_dev_attr_downsampling_ratio.dev_attr.attr,
> + &iio_const_attr_downsampling_ratio_available.dev_attr.attr, NULL
> +};
> +
> +static const struct attribute_group qmc5883p_attribute_group = {
> + .attrs = qmc5883p_attributes,
> +};
> +
> +static const struct iio_info qmc5883p_info = {
> + .attrs = &qmc5883p_attribute_group,
> + .read_raw = qmc5883p_read_raw,
> + .write_raw = qmc5883p_write_raw,
> + .read_avail = qmc5883p_read_avail,
> +};
> +
> +static const struct iio_chan_spec qmc5883p_channels[] = {
> + {
> + .type = IIO_MAGN,
> + .channel2 = IIO_MOD_X,
> + .modified = 1,
> + .address = AXIS_X,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_shared_by_type =
> + BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + .info_mask_shared_by_type_available =
> + BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + },
> + {
> + .type = IIO_MAGN,
> + .channel2 = IIO_MOD_Y,
> + .modified = 1,
> + .address = AXIS_Y,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_shared_by_type =
> + BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + .info_mask_shared_by_type_available =
> + BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + },
> + {
> + .type = IIO_MAGN,
> + .channel2 = IIO_MOD_Z,
> + .modified = 1,
> + .address = AXIS_Z,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
> + .info_mask_shared_by_type =
> + BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + .info_mask_shared_by_type_available =
> + BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> + },
> +};
> +
> +static void qmc5883p_runtime_pm_disable(void *dev)
> +{
> + pm_runtime_disable(dev);
> + pm_runtime_set_suspended(dev);
> +}
> +
> +static int qmc5883p_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
Your dt-binding correctly documents an optional vdd-supply for the
2.5V-3.6V rail, but the driver never parses or enables it. If a board
physically powers down this regulator during system suspend or relies on
the driver to enable it at boot, the driver will fail. Please add
devm_regulator_get_optional() and enable the regulator here. Also, you
should ensure that your system resume callbacks correctly re-apply the
chip's initialization sequence if power is lost during suspend.
> + struct qmc5883p_data *data;
> + struct iio_dev *indio_dev;
> + struct regmap *regmap;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + regmap = devm_regmap_init_i2c(client, &qmc5883p_regmap_config);
> + if (IS_ERR(regmap))
> + return dev_err_probe(dev, PTR_ERR(regmap),
> + "regmap initialization failed\n");
> +
> + data = iio_priv(indio_dev);
> + data->dev = dev;
> + data->regmap = regmap;
> + mutex_init(&data->mutex);
> +
> + i2c_set_clientdata(client, indio_dev);
> +
> + ret = qmc5883p_rf_init(data);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to initialize regmap fields\n");
> +
> + ret = qmc5883p_verify_chip_id(data);
> + if (ret)
> + return ret;
> +
> + ret = qmc5883p_chip_init(data);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to initialize chip\n");
> +
> + indio_dev->name = "qmc5883p";
> + indio_dev->info = &qmc5883p_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->channels = qmc5883p_channels;
> + indio_dev->num_channels = ARRAY_SIZE(qmc5883p_channels);
> +
> + pm_runtime_set_autosuspend_delay(dev, 2000);
> + pm_runtime_use_autosuspend(dev);
> +
> + pm_runtime_set_active(dev);
> + pm_runtime_enable(dev);
> +
> + ret = devm_add_action_or_reset(dev,
> + (void (*)(void *))qmc5883p_runtime_pm_disable,
> + dev);
Casting function pointers like (void (*)(void *)) violates strict kcfi
checks, which will cause a kernel panic on modern architectures
(like arm64) compiled with cfi enabled. The pm core already provides a
safe helper for this. Plese drop your custom qmc5883p_runtime_pm_disable
function and the devm_add_action_or_reset call, and simply use
ret = devm_pm_runtime_enable(dev);
> + if (ret)
> + return ret;
> +
> + pm_runtime_mark_last_busy(dev);
> +
> + ret = devm_iio_device_register(dev, indio_dev);
Because you use devm_iio_device_register(), the iio interface is
unregistered automatically during the devres unwinding phase, which
happens after your .remove() callback completes. This creates a race
window. A concurrent userspace sysfs read/write could trigger a pm
resume exactly while or after remove() is putting the chip to sleep. To
fix this, create a custom devm action (via devm_add_action_or_reset) to
write QMC5883P_MODE_SUSPEND to the chip, and register it before this
devm_iio_device_register() call. Because devres unwinds in lifo order,
this guarantees the iio interface is fully unregistered before the
hardware is suspended.
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to register IIO device\n");
> + return 0;
> +}
> +
> +static int qmc5883p_runtime_suspend(struct device *dev)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct qmc5883p_data *data = iio_priv(indio_dev);
> +
> + return regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
> +}
> +
> +static int qmc5883p_runtime_resume(struct device *dev)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct qmc5883p_data *data = iio_priv(indio_dev);
> + int ret;
> +
> + ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
> + if (ret)
> + return ret;
> +
> + usleep_range(10000, 11000);
> + return 0;
> +}
> +
> +static int qmc5883p_runtime_idle(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static int qmc5883p_system_suspend(struct device *dev)
> +{
> + return pm_runtime_force_suspend(dev);
> +}
> +
> +static int qmc5883p_system_resume(struct device *dev)
> +{
> + return pm_runtime_force_resume(dev);
> +}
> +
> +static void qmc5883p_remove(struct i2c_client *client)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(client);
> + struct qmc5883p_data *data = iio_priv(indio_dev);
> +
> + /*
> + * Best effort: put device to sleep on removal.
> + * Ignore error since we cannot do anything useful with it here.
> + * Runtime PM disable is handled by the devm cleanup action registered
> + * in probe.
> + */
> + regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
> +}
Once you move the suspend logic into a devm action in probe() (as
mentioned above), you can delete this qmc5883p_remove() function and the
.remove hook in the i2c_driver struct entirely.
> +
> +static const struct dev_pm_ops qmc5883p_dev_pm_ops = {
> + SYSTEM_SLEEP_PM_OPS(qmc5883p_system_suspend, qmc5883p_system_resume)
> + RUNTIME_PM_OPS(qmc5883p_runtime_suspend, qmc5883p_runtime_resume, NULL)
> +};
> +
> +static const struct of_device_id qmc5883p_of_match[] = {
> + { .compatible = "qst,qmc5883p" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, qmc5883p_of_match);
> +
> +static const struct i2c_device_id qmc5883p_id[] = {
> + { "qmc5883p", 0 },
> + {},
> +};
> +MODULE_DEVICE_TABLE(i2c, qmc5883p_id);
> +
> +static struct i2c_driver qmc5883p_driver = {
> + .driver = {
> + .name = "qmc5883p",
> + .of_match_table = qmc5883p_of_match,
> + .pm = pm_ptr(&qmc5883p_dev_pm_ops),
> + },
> + .probe = qmc5883p_probe,
> + .remove = qmc5883p_remove,
> + .id_table = qmc5883p_id,
> +};
> +module_i2c_driver(qmc5883p_driver);
> +
> +MODULE_AUTHOR("Hardik Phalet <hardik.phalet@pm.me>");
> +MODULE_DESCRIPTION("QMC5883P magnetic sensor driver");
> +MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH 5/7] clk: qcom: gpucc: Add GPU Clock Controller driver for Eliza
From: Taniya Das @ 2026-04-09 17:44 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Vladimir Zapolskiy, Akhil P Oommen
Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
linux-clk, devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <d97237a6-7f3b-4358-8972-5fd4b65d8f27@oss.qualcomm.com>
On 3/19/2026 6:25 PM, Konrad Dybcio wrote:
>> +// [GPU_CC_FREQUENCY_LIMITER_IRQ_CLEAR] = { 0x9538 },
> dead code
>
> +Akhil is that useful?
>
> [...]
I will remove the code in the next patch. It is not required.
>
>> +static void clk_eliza_regs_configure(struct device *dev, struct regmap *regmap)
>> +{
>> + /* Enable frequency limiter irq */
>> + regmap_clear_bits(regmap, 0x9534, BIT(0));
>> +}
> ..sounds like it
I missed to clean it up.
--
Thanks,
Taniya Das
^ permalink raw reply
* Re: [PATCH v4 2/4] pwm: sun50i: Add H616 PWM support
From: Paul Kocialkowski @ 2026-04-09 17:30 UTC (permalink / raw)
To: Richard Genoud
Cc: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
Philipp Zabel, Thomas Petazzoni, John Stultz, Joao Schim,
linux-pwm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel
In-Reply-To: <20260305091959.2530374-3-richard.genoud@bootlin.com>
[-- Attachment #1: Type: text/plain, Size: 10986 bytes --]
Hi Richard,
On Thu 05 Mar 26, 10:19, Richard Genoud wrote:
> +/* PWM IRQ Enable Register */
> +#define H616_PWM_IER 0x0
I think it would make more sense to keep the full register names from the
manual after the suffix and stick to them. It makes things easier when
comparing the code with documentation or the reference implementation.
So something like SUN8I_PWM_PIER here.
> +
> +/* PWM IRQ Status Register */
> +#define H616_PWM_ISR 0x4
> +
> +/* PWM Capture IRQ Enable Register */
> +#define H616_PWM_CIER 0x10
> +
> +/* PWM Capture IRQ Status Register */
> +#define H616_PWM_CISR 0x14
> +
> +/* PWMCC Pairs Clock Configuration Registers */
> +#define H616_PWM_XY_CLK_CR(pair) (0x20 + ((pair) * 0x4))
> +#define H616_PWM_XY_CLK_CR_SRC_SHIFT 7
> +#define H616_PWM_XY_CLK_CR_SRC_MASK 1
> +#define H616_PWM_XY_CLK_CR_GATE_BIT 4
> +#define H616_PWM_XY_CLK_CR_BYPASS_BIT(chan) ((chan) % 2 + 5)
> +#define H616_PWM_XY_CLK_CR_DIV_M_SHIFT 0
> +
> +/* PWMCC Pairs Dead Zone Control Registers */
> +#define H616_PWM_XY_DZ(pair) (0x30 + ((pair) * 0x4))
> +
> +/* PWM Enable Register */
> +#define H616_PWM_ENR 0x40
> +#define H616_PWM_ENABLE(x) BIT(x)
> +
> +/* PWM Capture Enable Register */
> +#define H616_PWM_CER 0x44
> +
> +/* PWM Control Register */
> +#define H616_PWM_CTRL_REG(chan) (0x60 + (chan) * 0x20)
You're sometimes calling the register offset _REG and sometimes not.
Both options are fine but you need to keep it consistent across the whole
definitions. I would be enclined to not use it after using the register names
coming from the manual as suggested above.
Also you're sometimes using "chan", sometimes "ch" for the argument to the
register macros. This is inconsistent and you might as well just use "c"
everywhere so it doesn't take too much space.
> +#define H616_PWM_CTRL_PRESCAL_K_SHIFT 0
> +#define H616_PWM_CTRL_PRESCAL_K_WIDTH 8
> +#define H616_PWM_CTRL_ACTIVE_STATE BIT(8)
> +
> +/* PWM Period Register */
> +#define H616_PWM_PERIOD_REG(ch) (0x64 + (ch) * 0x20)
> +#define H616_PWM_PERIOD_MASK GENMASK(31, 16)
> +#define H616_PWM_DUTY_MASK GENMASK(15, 0)
> +#define H616_PWM_REG_PERIOD(reg) (FIELD_GET(H616_PWM_PERIOD_MASK, reg) + 1)
> +#define H616_PWM_REG_DUTY(reg) FIELD_GET(H616_PWM_DUTY_MASK, reg)
> +#define H616_PWM_PERIOD(prd) FIELD_PREP(H616_PWM_PERIOD_MASK, (prd) - 1)
> +#define H616_PWM_DUTY(dty) FIELD_PREP(H616_PWM_DUTY_MASK, dty)
> +#define H616_PWM_PERIOD_MAX (FIELD_MAX(H616_PWM_PERIOD_MASK) + 1)
Using REG as a prefix feels a bit confusing here. I would rather see:
#define SUN8I_PWM_PPR(c) (0x64 + (c) * 0x20)
#define SUN8I_PWM_PPR_PERIOD(p) FIELD_PREP(...)
#define SUN8I_PWM_PPR_PERIOD_VALUE(r) FIELD_GET(...)
#define SUN8I_PWN_PPR_PERIOD_MAX FIELD_MAX(...)
#define SUN8I_PWM_PPR_DUTY(d) FIELD_PREP(...)
#define SUN8I_PWM_PPR_DUTY_VALUE(r) FIELD_GET(...)
> +
> +/* PWM Count Register */
> +#define H616_PWM_CNT_REG(x) (0x68 + (x) * 0x20)
> +
> +/* PWM Capture Control Register */
> +#define H616_PWM_CCR(x) (0x6c + (x) * 0x20)
> +
> +/* PWM Capture Rise Lock Register */
> +#define H616_PWM_CRLR(x) (0x70 + (x) * 0x20)
> +
> +/* PWM Capture Fall Lock Register */
> +#define H616_PWM_CFLR(x) (0x74 + (x) * 0x20)
> +
> +#define H616_PWM_PAIR_IDX(chan) ((chan) >> 2)
> +
> +/*
> + * Block diagram of the PWM clock controller:
> + *
> + * _____ ______ ________
> + * OSC24M --->| | | | | |
> + * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> H616_PWM_clock_src_xy
> + * |_____| |______| |________|
> + * ________
> + * | |
> + * +->| /div_k |---> H616_PWM_clock_x
> + * | |________|
> + * | ______
> + * | | |
> + * +-->| Gate |----> H616_PWM_bypass_clock_x
> + * | |______|
> + * H616_PWM_clock_src_xy ----+ ________
> + * | | |
> + * +->| /div_k |---> H616_PWM_clock_y
> + * | |________|
> + * | ______
> + * | | |
> + * +-->| Gate |----> H616_PWM_bypass_clock_y
> + * |______|
> + *
> + * NB: when the bypass is set, all the PWM logic is bypassed.
> + * So, the duty cycle and polarity can't be modified (we just have a clock).
> + * The bypass in PWM mode is used to achieve a 1/2 relative duty cycle with the
> + * fastest clock.
> + *
> + * H616_PWM_clock_x/y serve for the PWM purpose.
> + * H616_PWM_bypass_clock_x/y serve for the clock-provider purpose.
> + *
> + */
> +
> +/*
> + * Table used for /div_m (diviser before obtaining H616_PWM_clock_src_xy)
> + * It's actually CLK_DIVIDER_POWER_OF_TWO, but limited to /256
> + */
> +#define CLK_TABLE_DIV_M_ENTRY(i) { \
> + .val = (i), .div = 1 << (i) \
> +}
> +
> +static const struct clk_div_table clk_table_div_m[] = {
> + CLK_TABLE_DIV_M_ENTRY(0),
> + CLK_TABLE_DIV_M_ENTRY(1),
> + CLK_TABLE_DIV_M_ENTRY(2),
> + CLK_TABLE_DIV_M_ENTRY(3),
> + CLK_TABLE_DIV_M_ENTRY(4),
> + CLK_TABLE_DIV_M_ENTRY(5),
> + CLK_TABLE_DIV_M_ENTRY(6),
> + CLK_TABLE_DIV_M_ENTRY(7),
> + CLK_TABLE_DIV_M_ENTRY(8),
> + { /* sentinel */ }
> +};
> +
> +#define H616_PWM_XY_SRC_GATE(_pair, _reg) \
> +struct clk_gate gate_xy_##_pair = { \
> + .reg = (void *)(_reg), \
> + .bit_idx = H616_PWM_XY_CLK_CR_GATE_BIT, \
> + .hw.init = &(struct clk_init_data){ \
> + .ops = &clk_gate_ops, \
> + } \
> +}
> +
> +#define H616_PWM_XY_SRC_MUX(_pair, _reg) \
> +struct clk_mux mux_xy_##_pair = { \
> + .reg = (void *)(_reg), \
> + .shift = H616_PWM_XY_CLK_CR_SRC_SHIFT, \
> + .mask = H616_PWM_XY_CLK_CR_SRC_MASK, \
> + .flags = CLK_MUX_ROUND_CLOSEST, \
> + .hw.init = &(struct clk_init_data){ \
> + .ops = &clk_mux_ops, \
> + } \
> +}
> +
> +#define H616_PWM_XY_SRC_DIV(_pair, _reg) \
> +struct clk_divider rate_xy_##_pair = { \
> + .reg = (void *)(_reg), \
> + .shift = H616_PWM_XY_CLK_CR_DIV_M_SHIFT, \
> + .table = clk_table_div_m, \
> + .hw.init = &(struct clk_init_data){ \
> + .ops = &clk_divider_ops, \
> + } \
> +}
> +
> +#define H616_PWM_X_DIV(_idx, _reg) \
> +struct clk_divider rate_x_##_idx = { \
> + .reg = (void *)(_reg), \
> + .shift = H616_PWM_CTRL_PRESCAL_K_SHIFT, \
> + .width = H616_PWM_CTRL_PRESCAL_K_WIDTH, \
> + .hw.init = &(struct clk_init_data){ \
> + .ops = &clk_divider_ops, \
> + } \
> +}
> +
> +#define H616_PWM_X_BYPASS_GATE(_idx) \
> +struct clk_gate gate_x_bypass_##_idx = { \
> + .reg = (void *)H616_PWM_ENR, \
> + .bit_idx = _idx, \
> + .hw.init = &(struct clk_init_data){ \
> + .ops = &clk_gate_ops, \
> + } \
> +}
> +
> +#define H616_PWM_XY_CLK_SRC(_pair, _reg) \
> + static H616_PWM_XY_SRC_MUX(_pair, _reg); \
> + static H616_PWM_XY_SRC_GATE(_pair, _reg); \
> + static H616_PWM_XY_SRC_DIV(_pair, _reg)
> +
> +#define H616_PWM_X_CLK(_idx) \
> + static H616_PWM_X_DIV(_idx, H616_PWM_CTRL_REG(_idx))
> +
> +#define H616_PWM_X_BYPASS_CLK(_idx) \
> + H616_PWM_X_BYPASS_GATE(_idx)
> +
> +#define REF_CLK_XY_SRC(_pair) \
> + { \
> + .name = "pwm-clk-src" #_pair, \
> + .mux_hw = &mux_xy_##_pair.hw, \
> + .gate_hw = &gate_xy_##_pair.hw, \
> + .rate_hw = &rate_xy_##_pair.hw, \
> + }
> +
> +#define REF_CLK_X(_idx, _pair) \
> + { \
> + .name = "pwm-clk" #_idx, \
> + .parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
> + .num_parents = 1, \
> + .rate_hw = &rate_x_##_idx.hw, \
> + .flags = CLK_SET_RATE_PARENT, \
> + }
> +
> +#define REF_CLK_BYPASS(_idx, _pair) \
> + { \
> + .name = "pwm-clk-bypass" #_idx, \
> + .parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
> + .num_parents = 1, \
> + .gate_hw = &gate_x_bypass_##_idx.hw, \
> + .flags = CLK_SET_RATE_PARENT, \
> + }
> +
> +/*
> + * H616_PWM_clock_src_xy generation:
> + * _____ ______ ________
> + * OSC24M --->| | | | | |
> + * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> H616_PWM_clock_src_xy
> + * |_____| |______| |________|
> + */
> +H616_PWM_XY_CLK_SRC(01, H616_PWM_XY_CLK_CR(0));
> +H616_PWM_XY_CLK_SRC(23, H616_PWM_XY_CLK_CR(1));
> +H616_PWM_XY_CLK_SRC(45, H616_PWM_XY_CLK_CR(2));
> +
> +/*
> + * H616_PWM_clock_x_div generation:
> + * ________
> + * | | H616_PWM_clock_x/y
> + * H616_PWM_clock_src_xy --->| /div_k |--------------->
> + * |________|
> + */
> +H616_PWM_X_CLK(0);
> +H616_PWM_X_CLK(1);
> +H616_PWM_X_CLK(2);
> +H616_PWM_X_CLK(3);
> +H616_PWM_X_CLK(4);
> +H616_PWM_X_CLK(5);
> +
> +/*
> + * H616_PWM_bypass_clock_xy generation:
> + * ______
> + * | |
> + * H616_PWM_clock_src_xy ---->| Gate |-------> H616_PWM_bypass_clock_x
> + * |______|
> + *
> + * The gate is actually H616_PWM_ENR register.
> + */
> +H616_PWM_X_BYPASS_CLK(0);
> +H616_PWM_X_BYPASS_CLK(1);
> +H616_PWM_X_BYPASS_CLK(2);
> +H616_PWM_X_BYPASS_CLK(3);
> +H616_PWM_X_BYPASS_CLK(4);
> +H616_PWM_X_BYPASS_CLK(5);
> +
> +struct clk_pwm_data {
> + const char *name;
> + const char **parent_names;
> + unsigned int num_parents;
> + struct clk_hw *mux_hw;
> + struct clk_hw *rate_hw;
> + struct clk_hw *gate_hw;
> + unsigned long flags;
> +};
> +
> +#define CLK_BYPASS(h616chip, ch) ((h616chip)->data->npwm + (ch))
> +#define CLK_XY_SRC_IDX(h616chip, ch) ((h616chip)->data->npwm * 2 + ((ch) >> 1))
> +static struct clk_pwm_data pwmcc_data[] = {
> + REF_CLK_X(0, 01),
> + REF_CLK_X(1, 01),
> + REF_CLK_X(2, 23),
> + REF_CLK_X(3, 23),
> + REF_CLK_X(4, 45),
> + REF_CLK_X(5, 45),
> + REF_CLK_BYPASS(0, 01),
> + REF_CLK_BYPASS(1, 01),
> + REF_CLK_BYPASS(2, 23),
> + REF_CLK_BYPASS(3, 23),
> + REF_CLK_BYPASS(4, 45),
> + REF_CLK_BYPASS(5, 45),
> + REF_CLK_XY_SRC(01),
> + REF_CLK_XY_SRC(23),
> + REF_CLK_XY_SRC(45),
> + { /* sentinel */ }
> +};
We'll probably need a way to tie these static definitions to a particular
instance of the unit for a given chip. But I guess that can be done later
when adding more chips to the driver.
I'm not too versed in the clk and pwm APIs but the rest generally looks good
to me.
All the best,
Paul
--
Paul Kocialkowski,
Independent contractor - sys-base - https://www.sys-base.io/
Free software developer - https://www.paulk.fr/
Expert in multimedia, graphics and embedded hardware support with Linux.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v3 09/11] dt-bindings: input: Document hid-over-spi DT schema
From: Dmitry Torokhov @ 2026-04-09 17:16 UTC (permalink / raw)
To: Conor Dooley
Cc: Jingyuan Liang, Jiri Kosina, Benjamin Tissoires, Jonathan Corbet,
Mark Brown, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-input,
linux-doc, linux-kernel, linux-spi, linux-trace-kernel,
devicetree, hbarnor, tfiga, Dmitry Antipov, Jarrett Schultz
In-Reply-To: <20260409-defuse-thank-4b038128fac5@spud>
On Thu, Apr 09, 2026 at 05:02:11PM +0100, Conor Dooley wrote:
> On Thu, Apr 02, 2026 at 01:59:46AM +0000, Jingyuan Liang wrote:
> > Documentation describes the required and optional properties for
> > implementing Device Tree for a Microsoft G6 Touch Digitizer that
> > supports HID over SPI Protocol 1.0 specification.
> >
> > The properties are common to HID over SPI.
> >
> > Signed-off-by: Dmitry Antipov <dmanti@microsoft.com>
> > Signed-off-by: Jarrett Schultz <jaschultz@microsoft.com>
> > Signed-off-by: Jingyuan Liang <jingyliang@chromium.org>
> > ---
> > .../devicetree/bindings/input/hid-over-spi.yaml | 126 +++++++++++++++++++++
> > 1 file changed, 126 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/input/hid-over-spi.yaml b/Documentation/devicetree/bindings/input/hid-over-spi.yaml
> > new file mode 100644
> > index 000000000000..d1b0a2e26c32
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/input/hid-over-spi.yaml
> > @@ -0,0 +1,126 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/input/hid-over-spi.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: HID over SPI Devices
> > +
> > +maintainers:
> > + - Benjamin Tissoires <benjamin.tissoires@redhat.com>
> > + - Jiri Kosina <jkosina@suse.cz>
>
> Why them and not you, the developers of the series?
>
> > +
> > +description: |+
> > + HID over SPI provides support for various Human Interface Devices over the
> > + SPI bus. These devices can be for example touchpads, keyboards, touch screens
> > + or sensors.
> > +
> > + The specification has been written by Microsoft and is currently available
> > + here: https://www.microsoft.com/en-us/download/details.aspx?id=103325
> > +
> > + If this binding is used, the kernel module spi-hid will handle the
> > + communication with the device and the generic hid core layer will handle the
> > + protocol.
>
> This is not relevant to the binding, please remove it.
>
> > +
> > +allOf:
> > + - $ref: /schemas/input/touchscreen/touchscreen.yaml#
> > +
> > +properties:
> > + compatible:
> > + oneOf:
> > + - items:
> > + - enum:
> > + - microsoft,g6-touch-digitizer
> > + - const: hid-over-spi
> > + - description: Just "hid-over-spi" alone is allowed, but not recommended.
> > + const: hid-over-spi
>
> Why is it allowed but not recommended? Seems to me like we should
> require device-specific compatibles.
Why would we want to change the driver code to add a new compatible each
time a vendor decides to create a chip that is fully hid-spi-protocol
compliant? Or is the plan to still allow "hid-over-spi" fallback but
require device-specific compatible that will be ignored unless there is
device-specific quirk needed?
>
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + interrupts:
> > + maxItems: 1
> > +
> > + reset-gpios:
> > + maxItems: 1
> > + description:
> > + GPIO specifier for the digitizer's reset pin (active low). The line must
> > + be flagged with GPIO_ACTIVE_LOW.
> > +
> > + vdd-supply:
> > + description:
> > + Regulator for the VDD supply voltage.
> > +
> > + input-report-header-address:
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + minimum: 0
> > + maximum: 0xffffff
> > + description:
> > + A value to be included in the Read Approval packet, listing an address of
> > + the input report header to be put on the SPI bus. This address has 24
> > + bits.
> > +
> > + input-report-body-address:
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + minimum: 0
> > + maximum: 0xffffff
> > + description:
> > + A value to be included in the Read Approval packet, listing an address of
> > + the input report body to be put on the SPI bus. This address has 24 bits.
> > +
> > + output-report-address:
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + minimum: 0
> > + maximum: 0xffffff
> > + description:
> > + A value to be included in the Output Report sent by the host, listing an
> > + address where the output report on the SPI bus is to be written to. This
> > + address has 24 bits.
> > +
> > + read-opcode:
> > + $ref: /schemas/types.yaml#/definitions/uint8
> > + description:
> > + Value to be used in Read Approval packets. 1 byte.
> > +
> > + write-opcode:
> > + $ref: /schemas/types.yaml#/definitions/uint8
> > + description:
> > + Value to be used in Write Approval packets. 1 byte.
>
> Why can none of these things be determined from the device's compatible?
> On the surface, they like the kinds of things that could/should be.
Why would we want to keep tables of these values in the kernel and again
have to update the driver for each new chip? It also probably
firmware-dependent.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v4 0/4] Introduce Allwinner H616 PWM controller
From: Paul Kocialkowski @ 2026-04-09 17:16 UTC (permalink / raw)
To: Richard Genoud
Cc: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
Philipp Zabel, Thomas Petazzoni, John Stultz, Joao Schim,
linux-pwm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel
In-Reply-To: <20260305091959.2530374-1-richard.genoud@bootlin.com>
[-- Attachment #1: Type: text/plain, Size: 7856 bytes --]
Hi Richard,
On Thu 05 Mar 26, 10:19, Richard Genoud wrote:
> Allwinner H616 PWM controller is quite different from the A10 one.
As I've mentionned before, this PWM controller is not specific to the H616
but also appears in other chips, so the name of the driver and registers
should not mention H616.
After further investigation, I can see multiple versions of this new PWM IP
being used in different chips, starting with the R40/V40 (sun8iw11) in 2016.
The latest downstream BSP driver has a list of the different generations:
https://github.com/radxa/allwinner-bsp/blob/cubie-aiot-v1.4.6/drivers/pwm/pwm-sunxi.c#L1901
We have a first generation called v100/v101 for the following chips:
H616, R328 and R40. A second generation is called v200 and brings slight
register layout differences for A133, D1/T113-S3 and V851. Subsequent
iterations (v201-5) are used in more recent chips like A527 and A733 and
seem register-compatible with v200 (from a quick look).
So what I suggest here is to rename the driver "sun8i-pwm" and eventually add
a list of generations to the driver and different registers when needed, with
an appropriate suffix in their name.
But since you're currently only dealing with H616, this work can be done later
when introducing support for more chips.
> It can drive 6 PWM channels, and like for the A10, each channel has a
> bypass that permits to output a clock, bypassing the PWM logic, when
> enabled.
>
> But, the channels are paired 2 by 2, sharing a first set of
> MUX/prescaler/gate.
> Then, for each channel, there's another prescaler (that will be bypassed
> if the bypass is enabled for this channel).
>
> It looks like that:
> _____ ______ ________
> OSC24M --->| | | | | |
> APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
> |_____| |______| |________|
> ________
> | |
> +->| /div_k |---> PWM_clock_x
> | |________|
> | ______
> | | |
> +-->| Gate |----> PWM_bypass_clock_x
> | |______|
> PWM_clock_src_xy -----+ ________
> | | |
> +->| /div_k |---> PWM_clock_y
> | |________|
> | ______
> | | |
> +-->| Gate |----> PWM_bypass_clock_y
> |______|
>
> Where xy can be 0/1, 2/3, 4/5
>
> PWM_clock_x/y serve for the PWM purpose.
> PWM_bypass_clock_x/y serve for the clock-provider purpose.
> The common clock framework has been used to manage those clocks.
>
> This PWM driver serves as a clock-provider for PWM_bypass_clocks.
> This is needed for example by the embedded AC300 PHY which clock comes
> from PMW5 pin (PB12).
>
> Usually, to get a clock from a PWM driver, we use the pwm-clock driver
> so that the PWM driver doesn't need to be a clk-provider itself.
> While this works in most cases, here it just doesn't.
> That's because the pwm-clock request a period from the PWM driver,
> without any clue that it actually wants a clock at a specific frequency,
> and not a PWM signal with duty cycle capability.
From what I understand the pwm-clock driver will either assume a fixed rate
set in device-tree or deduce the rate from the pwm period. In any case it will
check that the pwm period (which it cannot change) is the same as the requested
clock period.
So I agree that pwm-clock is unable to change the clock rate at runtime and will
just use whatever frequency the pwm is running at (which is typically set
in the device-tree consumer property).
> So, the PWM driver doesn't know if it can use the bypass or not, it
> doesn't even have the real accurate frequency information (23809524 Hz
> instead of 24MHz) because PWM drivers only deal with periods.
I agree that the driver needs to register as a proper clock provider in
addition to pwm. But what happens if the same PWM clock is requested both from
the clk side and the pwm side?
> With pwm-clock, we loose a precious information along the way (that we
> actually want a clock and not a PWM signal).
> That's ok with simple PWM drivers that don't have multiple input clocks,
> but in this case, without this information, we can't know for sure which
> clock to use.
> And here, for instance, if we ask for a 24MHz clock, pwm-clock will
> requests 42ns (assigned-clocks doesn't help for that matter). The logic
> is to select the highest clock (100MHz) with no prescaler and a duty
> cycle value of 2/4 => we have 25MHz instead of 24MHz.
> And that's a perfectly fine choice for a PMW, because we still can
> change the duty cycle in the range [0-4]/4.
> But obviously for a clock, we don't care about the duty cycle, but more
> about the clock accuracy.
>
> And actually, this PWM is really a PWM AND a real clock when the bypass
> is set.
Make sense to me.
> This series is based onto v6.19-rc4
>
> NB: checkpatch is not happy with patch 2, but it's a false positive.
> It doesn't detect that PWM_XY_SRC_MUX/GATE/DIV are structures, but as
> it's more readable like that, I prefer keeping it that way.
>
> NB2: for geopolitical reasons, I didn't re-use the old series that Paul
> was referring to.
>
> Changes since v3:
> - gather Acked-by/Tested-by
> - fix cast from pointer to integer of different size (kernel test robot
> with arc platform)
> - add devm_action for clk_hw_unregister_composite as suggested by Philipp
> - remove now unused pwm_remove as suggested by Philipp
>
> Changes since v2:
> - use U32_MAX instead of defining UINT32_MAX
> - add a comment on U32_MAX usage in clk_round_rate()
> - change clk_table_div_m (use macros)
> - fix formatting (double space, superfluous comma, extra line feed)
> - fix the parent clock order
> - simplify code by using scoped_guard()
> - add missing const in to_h616_pwm_chip() and rename to
> h616_pwm_from_chip()
> - add/remove missing/superflous error messages
> - rename cnt->period_ticks, duty_cnt->duty_ticks
> - fix PWM_PERIOD_MAX
> - add .remove() callback
> - fix DIV_ROUND_CLOSEST_ULL->DIV_ROUND_UP_ULL
> - add H616_ prefix
> - protect _reg in macros
> - switch to waveforms instead of apply/get_state
> - shrink struct h616_pwm_channel
> - rebase on v6.19-rc4
>
> Changes since v1:
> - rebase onto v6.19-rc1
> - add missing headers
> - remove MODULE_ALIAS (suggested by Krzysztof)
> - use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof)
> - retrieve the parent clocks from the devicetree
> - switch num_parents to unsigned int
>
> Richard Genoud (4):
> dt-bindings: pwm: allwinner: add h616 pwm compatible
> pwm: sun50i: Add H616 PWM support
> arm64: dts: allwinner: h616: add PWM controller
> MAINTAINERS: Add entry on Allwinner H616 PWM driver
>
> .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml | 19 +-
> MAINTAINERS | 5 +
> .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 47 +
> drivers/pwm/Kconfig | 12 +
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-sun50i-h616.c | 936 ++++++++++++++++++
> 6 files changed, 1019 insertions(+), 1 deletion(-)
> create mode 100644 drivers/pwm/pwm-sun50i-h616.c
>
>
> base-commit: 11439c4635edd669ae435eec308f4ab8a0804808
--
Paul Kocialkowski,
Independent contractor - sys-base - https://www.sys-base.io/
Free software developer - https://www.paulk.fr/
Expert in multimedia, graphics and embedded hardware support with Linux.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v3 1/2] leds: ltc3208: add driver
From: Lee Jones @ 2026-04-09 16:59 UTC (permalink / raw)
To: Jan Carlo Roleda
Cc: Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-leds, devicetree
In-Reply-To: <20260406-upstream-ltc3208-v3-1-7f0b1d20ee7a@analog.com>
"Add driver" is not a good subject line.
> Kernel driver implementation for LTC3208 Multidisplay LED Driver
A one line commit messages is not suitable fore a 300 line driver!
What is the LTC3208 Multidisplay LED?
What does it do?
How does it operate?
What's special about it?
Any quirks?
> Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
> ---
> MAINTAINERS | 7 ++
> drivers/leds/Kconfig | 11 ++
> drivers/leds/Makefile | 1 +
> drivers/leds/leds-ltc3208.c | 298 ++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 317 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 55af015174a5..48bae02057d5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15126,6 +15126,13 @@ W: https://ez.analog.com/linux-software-drivers
> F: Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
> F: drivers/iio/temperature/ltc2983.c
>
> +LTC3208 LED DRIVER
> +M: Jan Carlo Roleda <jancarlo.roleda@analog.com>
> +L: linux-leds@vger.kernel.org
> +S: Maintained
> +W: https://ez.analog.com/linux-software-drivers
> +F: drivers/leds/leds-ltc3208.c
> +
> LTC4282 HARDWARE MONITOR DRIVER
> M: Nuno Sa <nuno.sa@analog.com>
> L: linux-hwmon@vger.kernel.org
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 597d7a79c988..867b120ea8ba 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -1029,6 +1029,17 @@ config LEDS_ACER_A500
> This option enables support for the Power Button LED of
> Acer Iconia Tab A500.
>
> +config LEDS_LTC3208
> + tristate "LED Driver for Analog Devices LTC3208"
> + depends on LEDS_CLASS && I2C
> + select REGMAP_I2C
> + help
> + Say Y to enable the LTC3208 LED driver.
> + This supports the LED device LTC3208.
You can do better!
> + To compile this driver as a module, choose M here: the module will
> + be called ltc3208.
> +
> source "drivers/leds/blink/Kconfig"
>
> comment "Flash and Torch LED drivers"
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 8fdb45d5b439..b08b539112b6 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -61,6 +61,7 @@ obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
> obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
> obj-$(CONFIG_LEDS_LP8864) += leds-lp8864.o
> obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
> +obj-$(CONFIG_LEDS_LTC3208) += leds-ltc3208.o
> obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o
> obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
> obj-$(CONFIG_LEDS_MAX77705) += leds-max77705.o
> diff --git a/drivers/leds/leds-ltc3208.c b/drivers/leds/leds-ltc3208.c
> new file mode 100644
> index 000000000000..65e65cd73d73
> --- /dev/null
> +++ b/drivers/leds/leds-ltc3208.c
> @@ -0,0 +1,298 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * LED driver for Analog Devices LTC3208 Multi-Display Driver
> + *
> + * Copyright 2026 Analog Devices Inc.
> + *
> + * Author: Jan Carlo Roleda <jancarlo.roleda@analog.com>
> + */
> +#include <linux/bitfield.h>
> +#include <linux/errno.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/leds.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/types.h>
> +#include <linux/workqueue.h>
Are all of these headers strictly necessary? For instance, it doesn't appear we
are using GPIOs, platform devices, or workqueues in this driver.
> +#define LTC3208_SET_HIGH_BYTE_DATA(x) FIELD_PREP(GENMASK(7, 4), (x))
> +
> +/* Registers */
> +#define LTC3208_REG_A_GRNRED 0x1 /* Green (High half-byte) and Red (Low half-byte) current DAC*/
> +#define LTC3208_REG_B_AUXBLU 0x2 /* AUX (High half-byte) and Blue (Low half-byte) current DAC*/
> +#define LTC3208_REG_C_MAIN 0x3 /* Main current DAC */
> +#define LTC3208_REG_D_SUB 0x4 /* Sub current DAC */
> +#define LTC3208_REG_E_AUX 0x5 /* AUX DAC Select */
> +#define LTC3208_REG_F_CAM 0x6 /* CAM (High half-byte and Low half-byte) current DAC*/
> +#define LTC3208_REG_G_OPT 0x7 /* Device Options */
> +
> +/* Device Options register */
> +#define LTC3208_OPT_CPO_MASK GENMASK(7, 6)
> +#define LTC3208_OPT_DIS_RGBDROP BIT(3)
> +#define LTC3208_OPT_DIS_CAMHILO BIT(2)
> +#define LTC3208_OPT_EN_RGBS BIT(1)
Nit: This can look nicer nested:
#define LTC3208_REG_A_GRNRED 0x1 /* Green (High half-byte) and Red (Low half-byte) current DAC*/
#define LTC3208_REG_B_AUXBLU 0x2 /* AUX (High half-byte) and Blue (Low half-byte) current DAC*/
#define LTC3208_REG_C_MAIN 0x3 /* Main current DAC */
#define LTC3208_REG_D_SUB 0x4 /* Sub current DAC */
#define LTC3208_REG_E_AUX 0x5 /* AUX DAC Select */
#define LTC3208_AUX1_MASK GENMASK(1, 0)
#define LTC3208_AUX2_MASK GENMASK(3, 2)
#define LTC3208_AUX3_MASK GENMASK(5, 4)
#define LTC3208_AUX4_MASK GENMASK(7, 6)
#define LTC3208_REG_F_CAM 0x6 /* CAM (High half-byte and Low half-byte) current DAC*/
#define LTC3208_REG_G_OPT 0x7 /* Device Options */
#define LTC3208_OPT_CPO_MASK GENMASK(7, 6)
#define LTC3208_OPT_DIS_RGBDROP BIT(3)
#define LTC3208_OPT_DIS_CAMHILO BIT(2)
#define LTC3208_OPT_EN_RGBS BIT(1)
> +#define LTC3208_MAX_BRIGHTNESS_4BIT 0xF
> +#define LTC3208_MAX_BRIGHTNESS_8BIT 0xFF
> +
> +#define LTC3208_NUM_LED_GRPS 8
> +#define LTC3208_NUM_AUX_LEDS 4
> +
> +#define LTC3208_NUM_AUX_OPT 4
> +#define LTC3208_MAX_CPO_OPT 3
Nit: Can we have _all_ of the values line up nicely?
#define LTC3208_NUM_AUX_OPT 4
#define LTC3208_MAX_CPO_OPT 3
> +enum ltc3208_aux_channel {
> + LTC3208_AUX_CHAN_AUX = 0,
> + LTC3208_AUX_CHAN_MAIN,
> + LTC3208_AUX_CHAN_SUB,
> + LTC3208_AUX_CHAN_CAM
> +};
> +
> +enum ltc3208_channel {
> + LTC3208_CHAN_MAIN = 0,
> + LTC3208_CHAN_SUB,
> + LTC3208_CHAN_AUX,
> + LTC3208_CHAN_CAML,
> + LTC3208_CHAN_CAMH,
> + LTC3208_CHAN_RED,
> + LTC3208_CHAN_BLUE,
> + LTC3208_CHAN_GREEN
> +};
> +
> +static const char * const ltc3208_dt_aux_channels[] = {
> + "adi,aux1-channel", "adi,aux2-channel",
> + "adi,aux3-channel", "adi,aux4-channel"
> +};
> +
> +static const char * const ltc3208_aux_opt[] = {
> + "aux", "main", "sub", "cam"
> +};
> +
> +
?
> +struct ltc3208_led {
> + struct led_classdev cdev;
> + struct i2c_client *client;
> + enum ltc3208_channel channel;
> +};
> +
> +struct ltc3208_dev {
> + struct i2c_client *client;
> + struct regmap *map;
> + struct ltc3208_led *leds;
> +};
> +
> +static const struct regmap_config ltc3208_regmap_cfg = {
> + .reg_bits = 8,
> + .val_bits = 8,
> +};
> +
> +static int ltc3208_led_set_brightness(struct led_classdev *led_cdev,
> + enum led_brightness brightness)
> +{
> + struct ltc3208_led *led = container_of(led_cdev,
> + struct ltc3208_led, cdev);
You can use 100-chars to avoid this awkwardness.
> + struct i2c_client *client = led->client;
> + struct ltc3208_dev *dev = i2c_get_clientdata(client);
> + struct regmap *map = dev->map;
> + u8 current_level = brightness;
> +
> + /*
> + * For registers with 4-bit splits (CAM, AUX/BLUE, GREEN/RED), the other
> + * half of the byte will be retrieved from the stored DAC value before
> + * updating the register.
> + */
> + switch (led->channel) {
> + case LTC3208_CHAN_MAIN:
> + return regmap_write(map, LTC3208_REG_C_MAIN, current_level);
> + case LTC3208_CHAN_SUB:
> + return regmap_write(map, LTC3208_REG_D_SUB, current_level);
> + case LTC3208_CHAN_AUX:
> + /* combine both low and high halves of byte */
> + current_level = LTC3208_SET_HIGH_BYTE_DATA(current_level);
> + current_level |= dev->leds[LTC3208_CHAN_BLUE].cdev.brightness;
> + return regmap_write(map, LTC3208_REG_B_AUXBLU, current_level);
Should we be using 'regmap_update_bits()' or 'regmap_field' here instead?
Constructing the register value by reading the software state of another LED
instance could lead to races.
> + case LTC3208_CHAN_BLUE:
> + /* apply high bits stored in other led */
> + current_level |= LTC3208_SET_HIGH_BYTE_DATA(dev->leds[LTC3208_CHAN_AUX].cdev.brightness);
> + return regmap_write(map, LTC3208_REG_B_AUXBLU, current_level);
> + case LTC3208_CHAN_CAMH:
> + current_level = LTC3208_SET_HIGH_BYTE_DATA(current_level);
> + current_level |= dev->leds[LTC3208_CHAN_CAML].cdev.brightness;
> + return regmap_write(map, LTC3208_REG_F_CAM, current_level);
> + case LTC3208_CHAN_CAML:
> + current_level |= LTC3208_SET_HIGH_BYTE_DATA(dev->leds[LTC3208_CHAN_CAMH].cdev.brightness);
> + return regmap_write(map, LTC3208_REG_F_CAM, current_level);
> + case LTC3208_CHAN_GREEN:
> + current_level = LTC3208_SET_HIGH_BYTE_DATA(current_level);
> + current_level |= dev->leds[LTC3208_CHAN_RED].cdev.brightness;
> + return regmap_write(map, LTC3208_REG_A_GRNRED, current_level);
> + case LTC3208_CHAN_RED:
> + current_level |= LTC3208_SET_HIGH_BYTE_DATA(dev->leds[LTC3208_CHAN_GREEN].cdev.brightness);
> + return regmap_write(map, LTC3208_REG_A_GRNRED, current_level);
This lot is begging for a sub function:
static int ltc3208_led_set_current_level(struct regmap *regmap, u8 reg, u8 low, u8 high) {
{
return regmap_write(regmap, reg, SET_HIGH_BYTE(high) | low);
}
> + default:
> + dev_err(&client->dev, "Invalid LED Channel\n");
> + return -EINVAL;
> + }
> +}
> +
> +static int ltc3208_update_options(struct ltc3208_dev *dev,
> + bool is_sub, bool is_cam_hi, bool is_rgb_drop)
> +{
> + struct regmap *map = dev->map;
> + u8 val = FIELD_PREP(LTC3208_OPT_EN_RGBS, is_sub) |
> + FIELD_PREP(LTC3208_OPT_DIS_CAMHILO, is_cam_hi) |
> + FIELD_PREP(LTC3208_OPT_DIS_RGBDROP, is_rgb_drop);
> +
That tabbing is awkward. In these cases it's better to do the
allocation after the declaration.
> + return regmap_write(map, LTC3208_REG_G_OPT, val);
> +}
> +
> +static int ltc3208_update_aux_dac(struct ltc3208_dev *dev,
> + enum ltc3208_aux_channel aux_1, enum ltc3208_aux_channel aux_2,
> + enum ltc3208_aux_channel aux_3, enum ltc3208_aux_channel aux_4)
These should sit under the '('.
> +{
> + struct regmap *map = dev->map;
> + u8 val = FIELD_PREP(LTC3208_AUX1_MASK, aux_1) |
> + FIELD_PREP(LTC3208_AUX2_MASK, aux_2) |
> + FIELD_PREP(LTC3208_AUX3_MASK, aux_3) |
> + FIELD_PREP(LTC3208_AUX4_MASK, aux_4);
As above.
> + return regmap_write(map, LTC3208_REG_E_AUX, val);
> +}
> +
> +static int ltc3208_probe(struct i2c_client *client)
> +{
> + enum ltc3208_aux_channel aux_channels[LTC3208_NUM_AUX_LEDS];
> + struct ltc3208_dev *data;
'data' is a terrible variable name.
> + struct ltc3208_led *leds;
> + struct regmap *map;
'regmap'
> + int ret, i;
> + u32 val;
> + bool dropdis_rgb_aux4;
> + bool dis_camhl;
> + bool en_rgbs;
> +
> + map = devm_regmap_init_i2c(client, <c3208_regmap_cfg);
> + if (IS_ERR(map))
> + return dev_err_probe(&client->dev, PTR_ERR(map),
> + "Failed to initialize regmap\n");
> +
> + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + leds = devm_kcalloc(&client->dev, LTC3208_NUM_LED_GRPS,
> + sizeof(struct ltc3208_led), GFP_KERNEL);
> + if (!leds)
> + return -ENOMEM;
> +
> + data->client = client;
> + data->map = map;
> +
> + /* initialize options from devicetree */
Capitalise comments and it's "Device Tree", although honestly, I think
the whole comment is superfluous.
> + dis_camhl = device_property_read_bool(&client->dev,
> + "adi,disable-camhl-pin");
> + en_rgbs = device_property_read_bool(&client->dev,
> + "adi,cfg-enrgbs-pin");
> + dropdis_rgb_aux4 = device_property_read_bool(&client->dev,
> + "adi,disable-rgb-aux4-dropout");
Use 100-chars.
> + ret = ltc3208_update_options(data, en_rgbs, dis_camhl,
> + dropdis_rgb_aux4);
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "error writing to options register\n");
Capitalise.
> + /* initialize aux channel configurations from devicetree */
As above and throughout.
> + for (i = 0; i < LTC3208_NUM_AUX_LEDS; i++) {
for (int i = 0; ...
> + ret = device_property_match_property_string(&client->dev,
> + ltc3208_dt_aux_channels[i],
> + ltc3208_aux_opt,
> + LTC3208_NUM_AUX_OPT);
> + /* use default value if absent in devicetree */
> + if (ret == -EINVAL)
> + aux_channels[i] = LTC3208_AUX_CHAN_AUX;
> + else if (ret >= 0)
> + aux_channels[i] = ret;
> + else
> + return dev_err_probe(&client->dev, ret,
> + "Failed getting aux-channel.\n");
> + }
> +
> + ret = ltc3208_update_aux_dac(data, aux_channels[0], aux_channels[1],
> + aux_channels[2], aux_channels[3]);
Why not just aux_channels and pull the values out in the function.
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "error writing to aux %u channel register.\n", i);
When is 'i' not 'LTC3208_NUM_AUX_LEDS'?
> + i2c_set_clientdata(client, data);
> +
> + device_for_each_child_node_scoped(&client->dev, child) {
> + struct ltc3208_led *led;
> + struct led_init_data init_data = {};
> +
> + ret = fwnode_property_read_u32(child, "reg", &val);
> + if (ret || val >= LTC3208_NUM_LED_GRPS)
> + return dev_err_probe(&client->dev, -EINVAL,
> + "Invalid reg property for LED\n");
Why aren't we propagating the real error?
> +
> + led = &leds[val];
> + led->client = client;
> + led->channel = val;
> + led->cdev.brightness_set_blocking = ltc3208_led_set_brightness;
> + led->cdev.max_brightness = LTC3208_MAX_BRIGHTNESS_4BIT;
> + if (val == LTC3208_CHAN_MAIN || val == LTC3208_CHAN_SUB)
> + led->cdev.max_brightness = LTC3208_MAX_BRIGHTNESS_8BIT;
> +
> + init_data.fwnode = child;
> +
> + ret = devm_led_classdev_register_ext(&client->dev, &led->cdev,
> + &init_data);
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "Failed to register LED %u\n", val);
> + }
> +
> + data->leds = leds;
> +
> + return 0;
> +}
> +
> +static const struct of_device_id ltc3208_match_table[] = {
> + {.compatible = "adi,ltc3208"},
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, ltc3208_match_table);
> +
> +static const struct i2c_device_id ltc3208_idtable[] = {
> + { "ltc3208" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, ltc3208_idtable);
> +
> +static struct i2c_driver ltc3208_driver = {
> + .driver = {
> + .name = "ltc3208",
> + .of_match_table = ltc3208_match_table,
> + },
> + .id_table = ltc3208_idtable,
> + .probe = ltc3208_probe,
> +};
> +module_i2c_driver(ltc3208_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Jan Carlo Roleda <jancarlo.roleda@analog.com>");
> +MODULE_DESCRIPTION("LTC3208 LED Driver");
>
> --
> 2.43.0
>
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH V11 02/12] PCI: host-generic: Add common helpers for parsing Root Port properties
From: Manivannan Sadhasivam @ 2026-04-09 16:58 UTC (permalink / raw)
To: Sherry Sun
Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
Frank Li, s.hauer@pengutronix.de, kernel@pengutronix.de,
festevam@gmail.com, lpieralisi@kernel.org, kwilczynski@kernel.org,
bhelgaas@google.com, Hongxing Zhu, l.stach@pengutronix.de,
imx@lists.linux.dev, linux-pci@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <VI0PR04MB1211419BB996B4790AE04170F92582@VI0PR04MB12114.eurprd04.prod.outlook.com>
On Thu, Apr 09, 2026 at 02:58:21AM +0000, Sherry Sun wrote:
> > On Wed, Apr 08, 2026 at 06:34:02AM +0000, Sherry Sun wrote:
> >
> > [...]
> >
> > > > > +/**
> > > > > + * pci_host_common_parse_port - Parse a single Root Port node
> > > > > + * @dev: Device pointer
> > > > > + * @bridge: PCI host bridge
> > > > > + * @node: Device tree node of the Root Port
> > > > > + *
> > > > > + * Returns: 0 on success, negative error code on failure */
> > > > > +static int pci_host_common_parse_port(struct device *dev,
> > > > > + struct pci_host_bridge *bridge,
> > > > > + struct device_node *node) {
> > > > > + struct pci_host_port *port;
> > > > > + struct gpio_desc *reset;
> > > > > +
> > > > > + reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
> > > > > + "reset", GPIOD_ASIS, "PERST#");
> > > >
> > > > Sorry, I missed this earlier.
> > > >
> > > > Since PERST# is optional, you cannot reliably detect whether the
> > > > Root Port binding intentionally skipped the PERST# GPIO or legacy
> > > > binding is used, just by checking for PERST# in Root Port node.
> > > >
> > > > So this helper should do 3 things:
> > > >
> > > > 1. If PERST# is found in Root Port node, use it.
> > > > 2. If not, check the RC node and if present, return -ENOENT to
> > > > fallback to the legacy binding.
> > > > 3. If not found in both nodes, assume that the PERST# is not present
> > > > in the design, and proceed with parsing Root Port binding further.
> > >
> > > Hi Mani, understand, does the following code looks ok for above three
> > cases?
> > >
> > > /* Check if PERST# is present in Root Port node */
> > > reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
> > > "reset", GPIOD_ASIS, "PERST#");
> > > if (IS_ERR(reset)) {
> > > /* If error is not -ENOENT, it's a real error */
> > > if (PTR_ERR(reset) != -ENOENT)
> > > return PTR_ERR(reset);
> > >
> > > /* PERST# not found in Root Port node, check RC node */
> > > rc_has_reset = of_property_read_bool(dev->of_node, "reset-gpios") ||
> > > of_property_read_bool(dev->of_node, "reset-gpio");
> >
> > Just:
> > if (of_property_read_bool(dev->of_node, "reset-gpios") ||
> > of_property_read_bool(dev->of_node, "reset-gpio")) {
> > return -ENOENT;
> > }
>
> Ok, will do.
>
> >
> > > if (rc_has_reset)
> > > return -ENOENT;
> > >
> > > /* No PERST# in either node, assume not present in design */
> > > reset = NULL;
> > > }
> > >
> > > port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > > if (!port)
> > > return -ENOMEM;
> > > ...
> > >
> > > >
> > > > But there is one more important limitation here. Right now, this API
> > > > only handles PERST#. But if another vendor tries to use it and if
> > > > they need other properties such as PHY, clocks etc... those
> > > > resources should be fetched optionally only by this helper. But if
> > > > the controller has a hard dependency on those resources, the driver will
> > fail to operate.
> > > >
> > > > I don't think we can fix this limitation though and those platforms
> > > > should ensure that the resource dependency is correctly modeled in
> > > > DT binding and the DTS is validated properly. It'd be good to
> > > > mention this in the kernel doc of this API.
> > >
> > > Ok, I will add a NOTE for this in this API description.
> > >
> > > >
> > > > > + if (IS_ERR(reset))
> > > > > + return PTR_ERR(reset);
> > > > > +
> > > > > + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > > > > + if (!port)
> > > > > + return -ENOMEM;
> > > > > +
> > > > > + port->reset = reset;
> > > > > + INIT_LIST_HEAD(&port->list);
> > > > > + list_add_tail(&port->list, &bridge->ports);
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * pci_host_common_parse_ports - Parse Root Port nodes from
> > > > > +device tree
> > > > > + * @dev: Device pointer
> > > > > + * @bridge: PCI host bridge
> > > > > + *
> > > > > + * This function iterates through child nodes of the host bridge
> > > > > +and parses
> > > > > + * Root Port properties (currently only reset GPIO).
> > > > > + *
> > > > > + * Returns: 0 on success, -ENOENT if no ports found, other
> > > > > +negative error codes
> > > > > + * on failure
> > > > > + */
> > > > > +int pci_host_common_parse_ports(struct device *dev, struct
> > > > > +pci_host_bridge *bridge) {
> > > > > + int ret = -ENOENT;
> > > > > +
> > > > > + for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> > > > > + if (!of_node_is_type(of_port, "pci"))
> > > > > + continue;
> > > > > + ret = pci_host_common_parse_port(dev, bridge, of_port);
> > > > > + if (ret)
> > > > > + return ret;
> > > >
> > > > As Sashiko flagged, you need to make sure that
> > > > devm_add_action_or_reset() is added even during the error path:
> > >
> > > Yes, it needs to be fixed. We can handle it with the following two methods, I
> > am not sure which method is better or more preferable?
> > >
> > > #1: register cleanup action after first successful port parse and use
> > cleanup_registered flag to avoid duplicate register.
> > > int ret = -ENOENT;
> > > bool cleanup_registered = false;
> > >
> > > for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> > > if (!of_node_is_type(of_port, "pci"))
> > > continue;
> > > ret = pci_host_common_parse_port(dev, bridge, of_port);
> > > if (ret)
> > > return ret;
> > >
> > > /* Register cleanup action after first successful port parse */
> > > if (!cleanup_registered) {
> > > ret = devm_add_action_or_reset(dev,
> > > pci_host_common_delete_ports,
> > > &bridge->ports);
> >
> > Even if you register devm_add_action_or_reset(), it won't be called when
> > pci_host_common_parse_port() fails since the legacy fallback will be used.
> >
> > So you need to manually call pci_host_common_delete_ports() in the error
> > path.
>
> Get your point, so seems I should just add the err_cleanup handle path like this, right?
>
> for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> if (!of_node_is_type(of_port, "pci"))
> continue;
> ret = pci_host_common_parse_port(dev, bridge, of_port);
> if (ret)
> goto err_cleanup;
> }
>
> if (ret)
> return ret;
>
> return devm_add_action_or_reset(dev, pci_host_common_delete_ports,
> &bridge->ports);
>
> err_cleanup:
> pci_host_common_delete_ports(&bridge->ports);
> return ret;
>
Yes!
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* [PATCH 4/4] MAINTAINERS: Add entry for QST QMC5883P magnetometer driver
From: Hardik Phalet @ 2026-04-09 16:24 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brigham Campbell,
Shuah Khan, linux-iio, devicetree, linux-kernel, linux-staging,
Hardik Phalet
In-Reply-To: <20260409162308.2590385-1-hardik.phalet@pm.me>
Add a MAINTAINERS entry for the QST QMC5883P staging IIO driver,
covering the driver source and its device tree binding.
Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index a92290fffa16..d0b9bfceb283 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20274,6 +20274,13 @@ F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
F: drivers/bus/fsl-mc/
F: include/uapi/linux/fsl_mc.h
+QST QMC5883P MAGNETOMETER DRIVER
+M: Hardik Phalet <hardik.phalet@pm.me>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml
+F: drivers/staging/iio/magnetometer/
+
QT1010 MEDIA DRIVER
L: linux-media@vger.kernel.org
S: Orphan
--
2.53.0
^ permalink raw reply related
* [PATCH 3/4] staging: iio: magnetometer: Add QST QMC5883P driver
From: Hardik Phalet @ 2026-04-09 16:24 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brigham Campbell,
Shuah Khan, linux-iio, devicetree, linux-kernel, linux-staging,
Hardik Phalet
In-Reply-To: <20260409162308.2590385-1-hardik.phalet@pm.me>
Add an IIO driver for the QST QMC5883P 3-axis magnetometer. The device
communicates over I2C and is managed via regmap with an rbtree cache.
Regmap fields are used to access the individual bit fields in CTRL_1 and
CTRL_2 registers.
The driver supports:
- Raw magnetic field readings on X, Y and Z axes
- Four full-scale ranges (±2 G, ±8 G, ±12 G, ±30 G)
- Configurable output data rate (10, 50, 100, 200 Hz)
- Configurable oversampling ratio (1, 2, 4, 8)
- Configurable downsampling ratio (1, 2, 4, 8) via a custom sysfs attr
- Runtime PM with a 2 s autosuspend delay
Known limitations tracked in TODO:
- No triggered buffer support
- No DRDY interrupt support
- Self-test register field is unused
Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
drivers/staging/iio/Kconfig | 1 +
drivers/staging/iio/Makefile | 1 +
drivers/staging/iio/magnetometer/Kconfig | 20 +
drivers/staging/iio/magnetometer/Makefile | 7 +
drivers/staging/iio/magnetometer/TODO | 5 +
drivers/staging/iio/magnetometer/qmc5883p.c | 819 ++++++++++++++++++++
6 files changed, 853 insertions(+)
create mode 100644 drivers/staging/iio/magnetometer/Kconfig
create mode 100644 drivers/staging/iio/magnetometer/Makefile
create mode 100644 drivers/staging/iio/magnetometer/TODO
create mode 100644 drivers/staging/iio/magnetometer/qmc5883p.c
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index a60631c1f449..d363e163d248 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -10,5 +10,6 @@ source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
+source "drivers/staging/iio/magnetometer/Kconfig"
endmenu
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 628583535393..7dcbb75d43f0 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -8,3 +8,4 @@ obj-y += adc/
obj-y += addac/
obj-y += frequency/
obj-y += impedance-analyzer/
+obj-y += magnetometer/
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
new file mode 100644
index 000000000000..d631da9578a1
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Magnetometer sensors
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Magnetometer sensors"
+
+config QMC5883P
+ tristate "QMC5883P 3-Axis Magnetometer"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say yes here to build support for QMC5883P I2C-based
+ 3-axis magnetometer chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qmc5883p.
+
+endmenu
diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
new file mode 100644
index 000000000000..8e650f2e3b02
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for staging industrial I/O Magnetometer sensor devices
+#
+# When adding new entries keep the list in alphabetical order
+
+obj-$(CONFIG_QMC5883P) += qmc5883p.o
diff --git a/drivers/staging/iio/magnetometer/TODO b/drivers/staging/iio/magnetometer/TODO
new file mode 100644
index 000000000000..6a8084c0dded
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/TODO
@@ -0,0 +1,5 @@
+TODO
+====
+- Implement triggered buffer support (iio_triggered_buffer_setup)
+- Add interrupt (DRDY) support
+- Implement self-test (selftest regmap field is unused)
diff --git a/drivers/staging/iio/magnetometer/qmc5883p.c b/drivers/staging/iio/magnetometer/qmc5883p.c
new file mode 100644
index 000000000000..6a71dc47efb9
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/qmc5883p.c
@@ -0,0 +1,819 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * qmc5883p.c - QMC5883P magnetometer driver
+ *
+ * Copyright 2026 Hardik Phalet <hardik.phalet@pm.me>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/types.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+/* Register definition */
+#define QMC5883P_REG_CHIP_ID 0x00
+#define QMC5883P_REG_X_LSB 0x01
+#define QMC5883P_REG_X_MSB 0x02
+#define QMC5883P_REG_Y_LSB 0x03
+#define QMC5883P_REG_Y_MSB 0x04
+#define QMC5883P_REG_Z_LSB 0x05
+#define QMC5883P_REG_Z_MSB 0x06
+#define QMC5883P_REG_STATUS 0x09
+#define QMC5883P_REG_CTRL_1 0x0A
+#define QMC5883P_REG_CTRL_2 0x0B
+
+/* Value definition */
+#define QMC5883P_MODE_SUSPEND 0x00
+#define QMC5883P_MODE_NORMAL 0x01
+#define QMC5883P_MODE_SINGLE 0x02
+#define QMC5883P_MODE_CONTINUOUS 0x03
+
+/* Output data rate */
+#define QMC5883P_ODR_10 0x00
+#define QMC5883P_ODR_50 0x01
+#define QMC5883P_ODR_100 0x02
+#define QMC5883P_ODR_200 0x03
+
+/* Oversampling rate */
+#define QMC5883P_OSR_8 0x00
+#define QMC5883P_OSR_4 0x01
+#define QMC5883P_OSR_2 0x02
+#define QMC5883P_OSR_1 0x03
+
+/* Downsampling rate */
+#define QMC5883P_DSR_1 0x00
+#define QMC5883P_DSR_2 0x01
+#define QMC5883P_DSR_4 0x02
+#define QMC5883P_DSR_8 0x03
+
+#define QMC5883P_RSTCTRL_SET_RESET \
+ 0x00 /* Set and reset on, i.e. the offset of device is renewed */
+#define QMC5883P_RSTCTRL_SET_ONLY 0x01 /* Set only on */
+#define QMC5883P_RSTCTRL_OFF 0x02 /* Set and reset off */
+
+#define QMC5883P_RNG_30G 0x00
+#define QMC5883P_RNG_12G 0x01
+#define QMC5883P_RNG_08G 0x02
+#define QMC5883P_RNG_02G 0x03
+
+#define QMC5883P_DEFAULT_ODR QMC5883P_ODR_100
+#define QMC5883P_DEFAULT_OSR QMC5883P_OSR_4
+#define QMC5883P_DEFAULT_DSR QMC5883P_DSR_4
+#define QMC5883P_DEFAULT_RNG QMC5883P_RNG_08G
+
+#define QMC5883P_DRDY_POLL_US 1000
+
+#define QMC5883P_CHIP_ID 0x80
+
+#define QMC5883P_STATUS_DRDY BIT(0)
+#define QMC5883P_STATUS_OVFL BIT(1)
+
+/*
+ * Scale factors in T/LSB for IIO_VAL_FRACTIONAL (val/val2), derived from
+ * datasheet Table 2 sensitivities (LSB/G) converted to LSB/T (1 G = 1e-4 T):
+ * sensitivity_T = sensitivity_G * 10000
+ * scale = 1 / sensitivity_T
+ *
+ * Index matches register value: RNG<1:0> = 0b00..0b11
+ */
+static const int qmc5883p_scale[][2] = {
+ [QMC5883P_RNG_30G] = { 1, 10000000 },
+ [QMC5883P_RNG_12G] = { 1, 25000000 },
+ [QMC5883P_RNG_08G] = { 1, 37500000 },
+ [QMC5883P_RNG_02G] = { 1, 150000000 },
+};
+
+static const int qmc5883p_odr[] = {
+ [QMC5883P_ODR_10] = 10,
+ [QMC5883P_ODR_50] = 50,
+ [QMC5883P_ODR_100] = 100,
+ [QMC5883P_ODR_200] = 200,
+};
+
+static const int qmc5883p_osr[] = {
+ [QMC5883P_OSR_1] = 1,
+ [QMC5883P_OSR_2] = 2,
+ [QMC5883P_OSR_4] = 4,
+ [QMC5883P_OSR_8] = 8,
+};
+
+static const unsigned int qmc5883p_dsr[] = {
+ [QMC5883P_DSR_1] = 1,
+ [QMC5883P_DSR_2] = 2,
+ [QMC5883P_DSR_4] = 4,
+ [QMC5883P_DSR_8] = 8,
+};
+
+struct qmc5883p_rf {
+ struct regmap_field *osr;
+ struct regmap_field *dsr;
+ struct regmap_field *odr;
+ struct regmap_field *mode;
+ struct regmap_field *rng;
+ struct regmap_field *rstctrl;
+ struct regmap_field *sftrst;
+ struct regmap_field *selftest;
+ struct regmap_field *chip_id;
+};
+
+static const struct regmap_range qmc5883p_readable_ranges[] = {
+ regmap_reg_range(QMC5883P_REG_CHIP_ID, QMC5883P_REG_STATUS),
+ regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2),
+};
+
+static const struct regmap_range qmc5883p_writable_ranges[] = {
+ regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2),
+};
+
+/*
+ * Volatile registers: hardware updates these independently of the driver.
+ * regmap will never serve these from cache.
+ */
+static const struct regmap_range qmc5883p_volatile_ranges[] = {
+ regmap_reg_range(QMC5883P_REG_X_LSB, QMC5883P_REG_Z_MSB),
+ regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS),
+};
+
+/*
+ * Precious registers: reading has a side effect (clears DRDY/OVFL bits).
+ * regmap will never read these speculatively.
+ */
+static const struct regmap_range qmc5883p_precious_ranges[] = {
+ regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS),
+};
+
+static const struct regmap_access_table qmc5883p_readable_table = {
+ .yes_ranges = qmc5883p_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(qmc5883p_readable_ranges),
+};
+
+static const struct regmap_access_table qmc5883p_writable_table = {
+ .yes_ranges = qmc5883p_writable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(qmc5883p_writable_ranges),
+};
+
+static const struct regmap_access_table qmc5883p_volatile_table = {
+ .yes_ranges = qmc5883p_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(qmc5883p_volatile_ranges),
+};
+
+static const struct regmap_access_table qmc5883p_precious_table = {
+ .yes_ranges = qmc5883p_precious_ranges,
+ .n_yes_ranges = ARRAY_SIZE(qmc5883p_precious_ranges),
+};
+
+static const struct regmap_config qmc5883p_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x0B,
+ .cache_type = REGCACHE_RBTREE,
+ .rd_table = &qmc5883p_readable_table,
+ .wr_table = &qmc5883p_writable_table,
+ .volatile_table = &qmc5883p_volatile_table,
+ .precious_table = &qmc5883p_precious_table,
+};
+
+struct qmc5883p_data {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex mutex; /* protects regmap and rf field accesses */
+ struct qmc5883p_rf rf;
+};
+
+enum qmc5883p_channels {
+ AXIS_X = 0,
+ AXIS_Y,
+ AXIS_Z,
+};
+
+static const struct reg_field qmc5883p_rf_osr =
+ REG_FIELD(QMC5883P_REG_CTRL_1, 4, 5);
+static const struct reg_field qmc5883p_rf_dsr =
+ REG_FIELD(QMC5883P_REG_CTRL_1, 6, 7);
+static const struct reg_field qmc5883p_rf_odr =
+ REG_FIELD(QMC5883P_REG_CTRL_1, 2, 3);
+static const struct reg_field qmc5883p_rf_mode =
+ REG_FIELD(QMC5883P_REG_CTRL_1, 0, 1);
+static const struct reg_field qmc5883p_rf_rng =
+ REG_FIELD(QMC5883P_REG_CTRL_2, 2, 3);
+static const struct reg_field qmc5883p_rf_rstctrl =
+ REG_FIELD(QMC5883P_REG_CTRL_2, 0, 1);
+static const struct reg_field qmc5883p_rf_sftrst =
+ REG_FIELD(QMC5883P_REG_CTRL_2, 7, 7);
+static const struct reg_field qmc5883p_rf_selftest =
+ REG_FIELD(QMC5883P_REG_CTRL_2, 6, 6);
+static const struct reg_field qmc5883p_rf_chip_id =
+ REG_FIELD(QMC5883P_REG_CHIP_ID, 0, 7);
+
+static int qmc5883p_rf_init(struct qmc5883p_data *data)
+{
+ struct regmap *regmap = data->regmap;
+ struct device *dev = data->dev;
+ struct qmc5883p_rf *rf = &data->rf;
+
+ rf->osr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_osr);
+ if (IS_ERR(rf->osr))
+ return PTR_ERR(rf->osr);
+
+ rf->dsr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_dsr);
+ if (IS_ERR(rf->dsr))
+ return PTR_ERR(rf->dsr);
+
+ rf->odr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_odr);
+ if (IS_ERR(rf->odr))
+ return PTR_ERR(rf->odr);
+
+ rf->mode = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_mode);
+ if (IS_ERR(rf->mode))
+ return PTR_ERR(rf->mode);
+
+ rf->rng = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rng);
+ if (IS_ERR(rf->rng))
+ return PTR_ERR(rf->rng);
+
+ rf->rstctrl = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rstctrl);
+ if (IS_ERR(rf->rstctrl))
+ return PTR_ERR(rf->rstctrl);
+
+ rf->sftrst = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_sftrst);
+ if (IS_ERR(rf->sftrst))
+ return PTR_ERR(rf->sftrst);
+
+ rf->selftest =
+ devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_selftest);
+ if (IS_ERR(rf->selftest))
+ return PTR_ERR(rf->selftest);
+
+ rf->chip_id = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_chip_id);
+ if (IS_ERR(rf->chip_id))
+ return PTR_ERR(rf->chip_id);
+
+ return 0;
+}
+
+static int qmc5883p_verify_chip_id(struct qmc5883p_data *data)
+{
+ int ret, regval;
+
+ ret = regmap_field_read(data->rf.chip_id, ®val);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "failed to read chip ID\n");
+
+ if (regval != QMC5883P_CHIP_ID)
+ return dev_err_probe(data->dev, -ENODEV,
+ "unexpected chip ID 0x%02x, expected 0x%02x\n",
+ regval, QMC5883P_CHIP_ID);
+ return ret;
+}
+
+static int qmc5883p_chip_init(struct qmc5883p_data *data)
+{
+ int ret;
+
+ ret = regmap_field_write(data->rf.sftrst, 1);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = regmap_field_write(data->rf.sftrst, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.rstctrl, QMC5883P_RSTCTRL_SET_RESET);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.rng, QMC5883P_DEFAULT_RNG);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.osr, QMC5883P_DEFAULT_OSR);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.dsr, QMC5883P_DEFAULT_DSR);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.odr, QMC5883P_DEFAULT_ODR);
+ if (ret)
+ return ret;
+
+ return regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
+}
+
+/*
+ * qmc5883p_get_measure - read all three axes.
+ * Must be called with data->mutex held.
+ * Handles PM internally: resumes device, reads data, schedules autosuspend.
+ */
+static int qmc5883p_get_measure(struct qmc5883p_data *data, s16 *x, s16 *y,
+ s16 *z)
+{
+ int ret;
+ u8 reg_data[6];
+ unsigned int status;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Poll the status register until DRDY is set or timeout.
+ * Read the whole register in one shot so that OVFL is captured from
+ * the same read: reading 0x09 clears both DRDY and OVFL, so a second
+ * read would always see OVFL=0.
+ * At ODR=10Hz one period is 100ms; use 150ms as a safe upper bound.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, QMC5883P_REG_STATUS,
+ status, status & QMC5883P_STATUS_DRDY,
+ QMC5883P_DRDY_POLL_US, 150000);
+ if (ret)
+ goto out;
+
+ if (status & QMC5883P_STATUS_OVFL) {
+ dev_warn_ratelimited(data->dev,
+ "data overflow, consider reducing field range\n");
+ ret = -ERANGE;
+ goto out;
+ }
+
+ ret = regmap_bulk_read(data->regmap, QMC5883P_REG_X_LSB, reg_data,
+ ARRAY_SIZE(reg_data));
+ if (ret)
+ goto out;
+
+ *x = (s16)((reg_data[1] << 8) | reg_data[0]);
+ *y = (s16)((reg_data[3] << 8) | reg_data[2]);
+ *z = (s16)((reg_data[5] << 8) | reg_data[4]);
+
+out:
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
+ return ret;
+}
+
+static int qmc5883p_write_scale(struct qmc5883p_data *data, int val, int val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qmc5883p_scale); i++) {
+ if (qmc5883p_scale[i][0] == val && qmc5883p_scale[i][1] == val2)
+ return regmap_field_write(data->rf.rng, i);
+ }
+
+ return -EINVAL;
+}
+
+static int qmc5883p_write_odr(struct qmc5883p_data *data, int val)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qmc5883p_odr); i++) {
+ if (qmc5883p_odr[i] == val)
+ return regmap_field_write(data->rf.odr, i);
+ }
+
+ return -EINVAL;
+}
+
+static int qmc5883p_write_osr(struct qmc5883p_data *data, int val)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qmc5883p_osr); i++) {
+ if (qmc5883p_osr[i] == val)
+ return regmap_field_write(data->rf.osr, i);
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t downsampling_ratio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+ unsigned int regval;
+ int ret;
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_field_read(data->rf.dsr, ®val);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", qmc5883p_dsr[regval]);
+}
+
+static ssize_t downsampling_ratio_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+ unsigned int val;
+ int i, ret, restore;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&data->mutex);
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+ if (ret)
+ goto out;
+
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(qmc5883p_dsr); i++) {
+ if (qmc5883p_dsr[i] == val) {
+ ret = regmap_field_write(data->rf.dsr, i);
+ break;
+ }
+ }
+
+ restore = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
+ if (restore && !ret)
+ ret = restore;
+
+out:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ return ret ? ret : (ssize_t)len;
+}
+
+static int qmc5883p_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long mask)
+{
+ s16 x, y, z;
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int regval;
+
+ guard(mutex)(&data->mutex);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = qmc5883p_get_measure(data, &x, &y, &z);
+ if (ret < 0)
+ return ret;
+ switch (chan->address) {
+ case AXIS_X:
+ *val = x;
+ break;
+ case AXIS_Y:
+ *val = y;
+ break;
+ case AXIS_Z:
+ *val = z;
+ break;
+ }
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regmap_field_read(data->rf.rng, ®val);
+ if (ret < 0)
+ return ret;
+ *val = qmc5883p_scale[regval][0];
+ *val2 = qmc5883p_scale[regval][1];
+ return IIO_VAL_FRACTIONAL;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_field_read(data->rf.odr, ®val);
+ if (ret < 0)
+ return ret;
+ *val = qmc5883p_odr[regval];
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = regmap_field_read(data->rf.osr, ®val);
+ if (ret < 0)
+ return ret;
+ *val = qmc5883p_osr[regval];
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static int qmc5883p_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+ int ret, restore;
+
+ guard(mutex)(&data->mutex);
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+ if (ret)
+ goto out;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = qmc5883p_write_odr(data, val);
+ break;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = qmc5883p_write_osr(data, val);
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ ret = qmc5883p_write_scale(data, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ restore = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
+ if (restore && !ret)
+ ret = restore;
+
+out:
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
+ return ret;
+}
+
+/*
+ * qmc5883p_read_avail - expose available values to userspace.
+ *
+ * Creates the _available sysfs attributes automatically:
+ * in_magn_sampling_frequency_available
+ * in_magn_oversampling_ratio_available
+ * in_magn_scale_available
+ */
+static int qmc5883p_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = qmc5883p_odr;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(qmc5883p_odr);
+ return IIO_AVAIL_LIST;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = qmc5883p_osr;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(qmc5883p_osr);
+ return IIO_AVAIL_LIST;
+
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)qmc5883p_scale;
+ *type = IIO_VAL_FRACTIONAL;
+ *length = ARRAY_SIZE(qmc5883p_scale) * 2;
+ return IIO_AVAIL_LIST;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static IIO_DEVICE_ATTR(downsampling_ratio, 0644, downsampling_ratio_show,
+ downsampling_ratio_store, 0);
+static IIO_CONST_ATTR(downsampling_ratio_available, "1 2 4 8");
+
+static struct attribute *qmc5883p_attributes[] = {
+ &iio_dev_attr_downsampling_ratio.dev_attr.attr,
+ &iio_const_attr_downsampling_ratio_available.dev_attr.attr, NULL
+};
+
+static const struct attribute_group qmc5883p_attribute_group = {
+ .attrs = qmc5883p_attributes,
+};
+
+static const struct iio_info qmc5883p_info = {
+ .attrs = &qmc5883p_attribute_group,
+ .read_raw = qmc5883p_read_raw,
+ .write_raw = qmc5883p_write_raw,
+ .read_avail = qmc5883p_read_avail,
+};
+
+static const struct iio_chan_spec qmc5883p_channels[] = {
+ {
+ .type = IIO_MAGN,
+ .channel2 = IIO_MOD_X,
+ .modified = 1,
+ .address = AXIS_X,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ },
+ {
+ .type = IIO_MAGN,
+ .channel2 = IIO_MOD_Y,
+ .modified = 1,
+ .address = AXIS_Y,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ },
+ {
+ .type = IIO_MAGN,
+ .channel2 = IIO_MOD_Z,
+ .modified = 1,
+ .address = AXIS_Z,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ },
+};
+
+static void qmc5883p_runtime_pm_disable(void *dev)
+{
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+}
+
+static int qmc5883p_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct qmc5883p_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &qmc5883p_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "regmap initialization failed\n");
+
+ data = iio_priv(indio_dev);
+ data->dev = dev;
+ data->regmap = regmap;
+ mutex_init(&data->mutex);
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = qmc5883p_rf_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to initialize regmap fields\n");
+
+ ret = qmc5883p_verify_chip_id(data);
+ if (ret)
+ return ret;
+
+ ret = qmc5883p_chip_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize chip\n");
+
+ indio_dev->name = "qmc5883p";
+ indio_dev->info = &qmc5883p_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = qmc5883p_channels;
+ indio_dev->num_channels = ARRAY_SIZE(qmc5883p_channels);
+
+ pm_runtime_set_autosuspend_delay(dev, 2000);
+ pm_runtime_use_autosuspend(dev);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = devm_add_action_or_reset(dev,
+ (void (*)(void *))qmc5883p_runtime_pm_disable,
+ dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_mark_last_busy(dev);
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register IIO device\n");
+ return 0;
+}
+
+static int qmc5883p_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+
+ return regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+}
+
+static int qmc5883p_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
+ if (ret)
+ return ret;
+
+ usleep_range(10000, 11000);
+ return 0;
+}
+
+static int qmc5883p_runtime_idle(struct device *dev)
+{
+ return 0;
+}
+
+static int qmc5883p_system_suspend(struct device *dev)
+{
+ return pm_runtime_force_suspend(dev);
+}
+
+static int qmc5883p_system_resume(struct device *dev)
+{
+ return pm_runtime_force_resume(dev);
+}
+
+static void qmc5883p_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct qmc5883p_data *data = iio_priv(indio_dev);
+
+ /*
+ * Best effort: put device to sleep on removal.
+ * Ignore error since we cannot do anything useful with it here.
+ * Runtime PM disable is handled by the devm cleanup action registered
+ * in probe.
+ */
+ regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+}
+
+static const struct dev_pm_ops qmc5883p_dev_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(qmc5883p_system_suspend, qmc5883p_system_resume)
+ RUNTIME_PM_OPS(qmc5883p_runtime_suspend, qmc5883p_runtime_resume, NULL)
+};
+
+static const struct of_device_id qmc5883p_of_match[] = {
+ { .compatible = "qst,qmc5883p" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qmc5883p_of_match);
+
+static const struct i2c_device_id qmc5883p_id[] = {
+ { "qmc5883p", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, qmc5883p_id);
+
+static struct i2c_driver qmc5883p_driver = {
+ .driver = {
+ .name = "qmc5883p",
+ .of_match_table = qmc5883p_of_match,
+ .pm = pm_ptr(&qmc5883p_dev_pm_ops),
+ },
+ .probe = qmc5883p_probe,
+ .remove = qmc5883p_remove,
+ .id_table = qmc5883p_id,
+};
+module_i2c_driver(qmc5883p_driver);
+
+MODULE_AUTHOR("Hardik Phalet <hardik.phalet@pm.me>");
+MODULE_DESCRIPTION("QMC5883P magnetic sensor driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* [PATCH 2/4] dt-bindings: iio: magnetometer: Add binding for QST QMC5883P
From: Hardik Phalet @ 2026-04-09 16:24 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brigham Campbell,
Shuah Khan, linux-iio, devicetree, linux-kernel, linux-staging,
Hardik Phalet
In-Reply-To: <20260409162308.2590385-1-hardik.phalet@pm.me>
Add the device tree binding document for the QST QMC5883P, a 3-axis
anisotropic magneto-resistive (AMR) sensor with a 16-bit ADC that
communicates over I2C. The binding exposes the required 'compatible'
and 'reg' properties along with an optional 'vdd-supply' for the
2.5 V–3.6 V VDD rail.
Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
.../iio/magnetometer/qst,qmc5883p.yaml | 48 +++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml
diff --git a/Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml b/Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml
new file mode 100644
index 000000000000..84fec10d8b9a
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/magnetometer/qst,qmc5883p.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: QST QMC5883P 3-axis magnetometer
+
+maintainers:
+ - Hardik Phalet <hardik.phalet@pm.me>
+
+description:
+ The QMC5883P is a 3-axis anisotropic magneto-resistive (AMR) sensor with a
+ 16-bit ADC. It communicates over I2C (standard and fast modes) and is
+ targeted at compass, navigation, and industrial applications.
+
+properties:
+ compatible:
+ const: qst,qmc5883p
+
+ reg:
+ maxItems: 1
+ description: I2C address of the device; the default address is 0x2c.
+
+ vdd-supply:
+ description:
+ VDD power supply (2.5 V to 3.6 V). Powers all internal analog and
+ digital functional blocks.
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ magnetometer@2c {
+ compatible = "qst,qmc5883p";
+ reg = <0x2c>;
+ vdd-supply = <&vdd_3v3>;
+ };
+ };
+...
--
2.53.0
^ permalink raw reply related
* [PATCH 1/4] dt-bindings: vendor-prefixes: Add QST Corporation
From: Hardik Phalet @ 2026-04-09 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brigham Campbell,
Shuah Khan, linux-iio, devicetree, linux-kernel, linux-staging,
Hardik Phalet
In-Reply-To: <20260409162308.2590385-1-hardik.phalet@pm.me>
Add the vendor prefix 'qst' for QST Corporation, a manufacturer of
MEMS sensors.
Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 5d2a7a8d3ac6..71a1b9087c5e 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1244,6 +1244,8 @@ patternProperties:
description: Shenzhen QiShenglong Industrialist Co., Ltd.
"^qnap,.*":
description: QNAP Systems, Inc.
+ "^qst,.*":
+ description: QST Corporation
"^quanta,.*":
description: Quanta Computer Inc.
"^radxa,.*":
--
2.53.0
^ permalink raw reply related
* [PATCH 0/4] Add QST QMC5883P magnetometer driver
From: Hardik Phalet @ 2026-04-09 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Brigham Campbell,
Shuah Khan, linux-iio, devicetree, linux-kernel, linux-staging,
Hardik Phalet
This series adds initial Linux support for the QST QMC5883P, a 3-axis
anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC that
communicates over I2C. To my knowledge there is no existing upstream
driver for this device.
The driver supports:
- Raw magnetic field readings on X, Y, and Z axes
- Four selectable full-scale ranges (±2 G, ±8 G, ±12 G, ±30 G)
- Configurable output data rate (10, 50, 100, 200 Hz)
- Configurable oversampling ratio (1, 2, 4, 8)
- Configurable downsampling ratio (1, 2, 4, 8) via a custom sysfs
attribute
- Runtime PM with a 2 s autosuspend delay
- System suspend/resume via pm_runtime_force_suspend/resume
Regmap with an rbtree cache is used throughout. CTRL_1 and CTRL_2
bit fields are accessed via regmap_field to avoid read-modify-write
races. The STATUS register is marked precious so regmap never reads
it speculatively and clears the DRDY/OVFL bits unexpectedly.
The init sequence on probe is: soft reset → wait 1 ms → deassert
reset → configure SET/RESET control → apply default ODR/OSR/DSR/RNG
→ enter normal mode. This ordering was determined empirically on
hardware to produce reliable, non-zero axis readings.
The driver is placed under drivers/staging/iio/magnetometer/ with a
TODO file tracking the remaining work before it can graduate:
- Triggered buffer support (iio_triggered_buffer_setup)
- DRDY interrupt support
- Self-test implementation
Patches:
1/4 - dt-bindings: vendor-prefixes: Add 'qst' for QST Corporation
2/4 - dt-bindings: iio: magnetometer: Add binding for QST QMC5883P
3/4 - staging: iio: magnetometer: Add QST QMC5883P driver
4/4 - MAINTAINERS: Add entry for QST QMC5883P magnetometer driver
Testing
-------
Tested on a Raspberry Pi 4B running a mainline kernel (aarch64) with a
GY-271 HM-246 board connected via I2C bus 1. The chip was confirmed to
enumerate at address 0x2C via i2cdetect.
The driver was cross-compiled from Fedora (x86_64) targeting aarch64
and loaded as a module (qmc5883p.ko) with the Device Tree overlay
pointing at i2c1:0x2c.
Verification steps performed:
- Chip ID register (0x00) reads back 0x80 on probe, confirming the
correct device is present
- All three axes (in_magn_x_raw, in_magn_y_raw, in_magn_z_raw) return
non-zero, stable values when the board is held still and change
appropriately when the board is rotated
- in_magn_x_scale (and Y, Z) returns the expected fractional value for
the default ±8 G range (1/37500000)
- in_magn_sampling_frequency / _available, in_magn_oversampling_ratio /
_available, and downsampling_ratio / downsampling_ratio_available all
read and write correctly; the chip responds without error to each
valid setting
- Runtime PM: after 2 s of inactivity the device enters suspend mode
(MODE = 0x00 confirmed via i2cdump); the next sysfs read correctly
resumes the device and returns valid data
- System suspend/resume (echo mem > /sys/power/state) leaves the
driver in a consistent state; readings remain valid after resume
- dt_binding_check passes for patch 2/4
- Kernel builds cleanly with W=1 and no new warnings
Hardik Phalet (4):
dt-bindings: vendor-prefixes: Add QST Corporation
dt-bindings: iio: magnetometer: Add binding for QST QMC5883P
Subject: [PATCH 3/4] staging: iio: magnetometer: Add QST QMC5883P
driver
MAINTAINERS: Add entry for QST QMC5883P magnetometer driver
.../iio/magnetometer/qst,qmc5883p.yaml | 48 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 7 +
drivers/staging/iio/Kconfig | 1 +
drivers/staging/iio/Makefile | 1 +
drivers/staging/iio/magnetometer/Kconfig | 20 +
drivers/staging/iio/magnetometer/Makefile | 7 +
drivers/staging/iio/magnetometer/TODO | 5 +
drivers/staging/iio/magnetometer/qmc5883p.c | 819 ++++++++++++++++++
9 files changed, 910 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml
create mode 100644 drivers/staging/iio/magnetometer/Kconfig
create mode 100644 drivers/staging/iio/magnetometer/Makefile
create mode 100644 drivers/staging/iio/magnetometer/TODO
create mode 100644 drivers/staging/iio/magnetometer/qmc5883p.c
--
2.53.0
^ permalink raw reply
* Re: [PATCH] dt-bindings: i2c: nxp,pca9564: convert to DT schema
From: Akhila YS @ 2026-04-09 16:21 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Peter Rosin, linux-i2c, devicetree, linux-kernel
In-Reply-To: <7930789e-6930-45b9-997b-0e5c850db194@gmail.com>
On 09-04-2026 20:32, Akhila YS wrote:
> On 09-04-2026 13:56, Krzysztof Kozlowski wrote:
>> On Wed, Apr 08, 2026 at 08:23:31AM +0000, Akhila YS wrote:
>>> Convert NXP PCA PCA9564/PCA9665 I2C controller to YAML format.
>> DT schema, not YAML format. Look at your subject.
>
> Okay, i will change it.
>
>> ...
>>
>>> + reg:
>>> + maxItems: 1
>>> +
>>> + "#address-cells":
>>> + const: 1
>>> +
>>> + "#size-cells":
>>> + const: 0
>>> +
>>> + interrupts:
>>> + maxItems: 1
>>> +
>>> + reset-gpios:
>>> + maxItems: 1
>>> +
>>> + clock-frequency:
>>> + default: 100000
>>> +
>>> +required:
>>> + - compatible
>>> + - reg
>>> +
>>> +additionalProperties: false
>> And if you tested any DTS with this, you would see this cannot work.
>> Look at other bindings - you miss ref to i2c-controller and
>> unevaluatedProps. But the problem is that you are doing something which
>> would never work, so I have doubts that you know what you are doing. One
>> thing is to make a mistake, other thing is to post something can never
>> work thus putting quite noticeable requirements on review.
>
> You are right, i missed referencing the common i2c controller schema and
> did not handle unevaluated properties correctly,which makes binding invalid.
There is no file named i2c-controller.yaml to take ref to this yaml. I
tried testing the yaml file with the dts in my local machine and its
working as expected.
I even checked the status in patchwork and there it was marked as
successful.
>
>> Please first learn how DTS and DT bindings work, before you post new
>> patches.
>
> Thank you for the review, i will work on it.
>
>> Best regards,
>> Krzysztof
>>
--
Best Regards,
Akhila.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox