* [PATCH 1/6] net: ipa: fix GENERIC_CMD register field masks for IPA v5.0+
From: Luca Weiss @ 2026-04-03 16:43 UTC (permalink / raw)
To: Alex Elder, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, netdev, linux-kernel,
linux-arm-msm, devicetree, Luca Weiss
In-Reply-To: <20260403-milos-ipa-v1-0-01e9e4e03d3e@fairphone.com>
From: Alexander Koskovich <akoskovich@pm.me>
Fix the field masks to match the hardware layout documented in
downstream GSI (GSI_V3_0_EE_n_GSI_EE_GENERIC_CMD_*).
Notably this fixes a WARN I was seeing when I tried to send "stop"
to the MPSS remoteproc while IPA was up.
Fixes: faf0678ec8a0 ("net: ipa: add IPA v5.0 GSI register definitions")
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
drivers/net/ipa/reg/gsi_reg-v5.0.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ipa/reg/gsi_reg-v5.0.c b/drivers/net/ipa/reg/gsi_reg-v5.0.c
index 36d1e65df71b..3334d8e20ad2 100644
--- a/drivers/net/ipa/reg/gsi_reg-v5.0.c
+++ b/drivers/net/ipa/reg/gsi_reg-v5.0.c
@@ -156,9 +156,10 @@ REG_FIELDS(EV_CH_CMD, ev_ch_cmd, 0x00025010 + 0x12000 * GSI_EE_AP);
static const u32 reg_generic_cmd_fmask[] = {
[GENERIC_OPCODE] = GENMASK(4, 0),
- [GENERIC_CHID] = GENMASK(9, 5),
- [GENERIC_EE] = GENMASK(13, 10),
- /* Bits 14-31 reserved */
+ [GENERIC_CHID] = GENMASK(12, 5),
+ [GENERIC_EE] = GENMASK(16, 13),
+ /* Bits 17-23 reserved */
+ [GENERIC_PARAMS] = GENMASK(31, 24),
};
REG_FIELDS(GENERIC_CMD, generic_cmd, 0x00025018 + 0x12000 * GSI_EE_AP);
--
2.53.0
^ permalink raw reply related
* [PATCH 0/6] IPA v5.2 support for Milos and Fairphone (Gen. 6)
From: Luca Weiss @ 2026-04-03 16:43 UTC (permalink / raw)
To: Alex Elder, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, netdev, linux-kernel,
linux-arm-msm, devicetree, Luca Weiss
First, two fixes that unbreak IPA v5.0+, which can be applied
independently.
Then add support for IPA v5.2 which can be found in the Milos SoC. And
finally enable it on Fairphone (Gen. 6) so that mobile data (4G/5G/..)
starts working.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Alexander Koskovich (2):
net: ipa: fix GENERIC_CMD register field masks for IPA v5.0+
net: ipa: fix event ring index not programmed for IPA v5.0+
Luca Weiss (4):
dt-bindings: net: qcom,ipa: add Milos compatible
net: ipa: add IPA v5.2 configuration data
arm64: dts: qcom: milos: Add IPA node
arm64: dts: qcom: milos-fairphone-fp6: Enable IPA
.../devicetree/bindings/net/qcom,ipa.yaml | 1 +
arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 9 +
arch/arm64/boot/dts/qcom/milos.dtsi | 44 ++
drivers/net/ipa/Makefile | 2 +-
drivers/net/ipa/data/ipa_data-v5.2.c | 452 +++++++++++++++++++++
drivers/net/ipa/gsi_reg.c | 1 +
drivers/net/ipa/ipa_data.h | 1 +
drivers/net/ipa/ipa_main.c | 4 +
drivers/net/ipa/ipa_reg.c | 1 +
drivers/net/ipa/ipa_sysfs.c | 2 +
drivers/net/ipa/ipa_version.h | 2 +
drivers/net/ipa/reg/gsi_reg-v5.0.c | 9 +-
12 files changed, 523 insertions(+), 5 deletions(-)
---
base-commit: 83acad05dee54a5cff0c98dd7962e55d4c6b145a
change-id: 20260403-milos-ipa-e5705aa87245
prerequisite-change-id: 20260403-milos-imem-3a034224946a:v1
prerequisite-patch-id: 07ad87fc40adfb8dd146b9c0678d099bfe97f679
prerequisite-patch-id: 0f4436a42df3bccb92f753cecfbf24c81f4677c8
Best regards,
--
Luca Weiss <luca.weiss@fairphone.com>
^ permalink raw reply
* Re: [PATCH V10 04/13] PCI: imx6: Assert PERST# before enabling regulators
From: Manivannan Sadhasivam @ 2026-04-03 16:29 UTC (permalink / raw)
To: Sherry Sun
Cc: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
lpieralisi, kwilczynski, bhelgaas, hongxing.zhu, l.stach, imx,
linux-pci, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260402095107.205439-5-sherry.sun@nxp.com>
On Thu, Apr 02, 2026 at 05:50:58PM +0800, Sherry Sun wrote:
> According to the PCIe initialization requirements, PERST# signal should
> be asserted before applying power to the PCIe device, and deasserted
> after power and reference clock are stable.
>
Spec wording is not quite like this. Spec mandates asserting PERST# *before*
stopping refclk and powering down the device and deasserting it *after* applying
power and refclk stable.
I believe you want to assert PERST# before enabling regulator to prevent the
endpoint from functioning? If so, is it due to refclk not available yet or some
other reason?
> Currently, the driver enables the vpcie3v3aux regulator in
> imx_pcie_probe() before PERST# is asserted in imx_pcie_host_init(),
> which violates the PCIe power sequencing requirements. However, there
> is no issue so far because PERST# is requested as GPIOD_OUT_HIGH in
> imx_pcie_probe(), which guarantees that PERST# is asserted before
> enabling the vpcie3v3aux regulator.
>
> This is prepare for the upcoming changes that will parse the reset
> property using the new Root Port binding, which will use GPIOD_ASIS
> when requesting the reset GPIO. With GPIOD_ASIS, the GPIO state is not
> guaranteed, so explicit sequencing is required.
>
> Fix the power sequencing by:
> 1. Moving vpcie3v3aux regulator enable from probe to
> imx_pcie_host_init(), where it can be properly sequenced with PERST#.
> 2. Moving imx_pcie_assert_perst() before regulator and clock enable to
> ensure correct ordering.
>
> The vpcie3v3aux regulator is kept enabled for the entire PCIe controller
> lifecycle and automatically disabled on device removal via devm cleanup.
>
vpcie3v3aux handling should be in a separate patch.
- Mani
> Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
> ---
> drivers/pci/controller/dwc/pci-imx6.c | 49 +++++++++++++++++++++------
> 1 file changed, 39 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
> index 45d70ae7e04f..948ffb75d122 100644
> --- a/drivers/pci/controller/dwc/pci-imx6.c
> +++ b/drivers/pci/controller/dwc/pci-imx6.c
> @@ -166,6 +166,8 @@ struct imx_pcie {
> u32 tx_swing_full;
> u32 tx_swing_low;
> struct regulator *vpcie;
> + struct regulator *vpcie_aux;
> + bool vpcie_aux_enabled;
> struct regulator *vph;
> void __iomem *phy_base;
>
> @@ -1220,6 +1222,13 @@ static void imx_pcie_disable_device(struct pci_host_bridge *bridge,
> imx_pcie_remove_lut(imx_pcie, pci_dev_id(pdev));
> }
>
> +static void imx_pcie_vpcie_aux_disable(void *data)
> +{
> + struct regulator *vpcie_aux = data;
> +
> + regulator_disable(vpcie_aux);
> +}
> +
> static void imx_pcie_assert_perst(struct imx_pcie *imx_pcie, bool assert)
> {
> if (assert) {
> @@ -1240,6 +1249,24 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
> struct imx_pcie *imx_pcie = to_imx_pcie(pci);
> int ret;
>
> + imx_pcie_assert_perst(imx_pcie, true);
> +
> + /* Keep 3.3Vaux supply enabled for the entire PCIe controller lifecycle */
> + if (imx_pcie->vpcie_aux && !imx_pcie->vpcie_aux_enabled) {
> + ret = regulator_enable(imx_pcie->vpcie_aux);
> + if (ret) {
> + dev_err(dev, "failed to enable vpcie_aux regulator: %d\n",
> + ret);
> + return ret;
> + }
> + imx_pcie->vpcie_aux_enabled = true;
> +
> + ret = devm_add_action_or_reset(dev, imx_pcie_vpcie_aux_disable,
> + imx_pcie->vpcie_aux);
> + if (ret)
> + return ret;
> + }
> +
> if (imx_pcie->vpcie) {
> ret = regulator_enable(imx_pcie->vpcie);
> if (ret) {
> @@ -1249,25 +1276,24 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
> }
> }
>
> + ret = imx_pcie_clk_enable(imx_pcie);
> + if (ret) {
> + dev_err(dev, "unable to enable pcie clocks: %d\n", ret);
> + goto err_reg_disable;
> + }
> +
> if (pp->bridge && imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) {
> pp->bridge->enable_device = imx_pcie_enable_device;
> pp->bridge->disable_device = imx_pcie_disable_device;
> }
>
> imx_pcie_assert_core_reset(imx_pcie);
> - imx_pcie_assert_perst(imx_pcie, true);
>
> if (imx_pcie->drvdata->init_phy)
> imx_pcie->drvdata->init_phy(imx_pcie);
>
> imx_pcie_configure_type(imx_pcie);
>
> - ret = imx_pcie_clk_enable(imx_pcie);
> - if (ret) {
> - dev_err(dev, "unable to enable pcie clocks: %d\n", ret);
> - goto err_reg_disable;
> - }
> -
> if (imx_pcie->phy) {
> ret = phy_init(imx_pcie->phy);
> if (ret) {
> @@ -1780,9 +1806,12 @@ static int imx_pcie_probe(struct platform_device *pdev)
> of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed);
> imx_pcie->supports_clkreq = of_property_read_bool(node, "supports-clkreq");
>
> - ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux");
> - if (ret < 0 && ret != -ENODEV)
> - return dev_err_probe(dev, ret, "failed to enable Vaux supply\n");
> + imx_pcie->vpcie_aux = devm_regulator_get_optional(&pdev->dev, "vpcie3v3aux");
> + if (IS_ERR(imx_pcie->vpcie_aux)) {
> + if (PTR_ERR(imx_pcie->vpcie_aux) != -ENODEV)
> + return PTR_ERR(imx_pcie->vpcie_aux);
> + imx_pcie->vpcie_aux = NULL;
> + }
>
> imx_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie");
> if (IS_ERR(imx_pcie->vpcie)) {
> --
> 2.37.1
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v3 0/3] thermal: spacemit: Add support for SpacemiT K1 SoC thermal sensor
From: Gong Shuai @ 2026-04-03 16:28 UTC (permalink / raw)
To: Vincent Legoll, alex, aou, conor+dt, daniel.lezcano, devicetree,
dlan, krzk+dt, krzysztof.kozlowski, linux-kernel, linux-pm,
linux-riscv, lukasz.luba, p.zabel, palmer, pjw, rafael, robh,
rui.zhang, spacemit
In-Reply-To: <36cca49c-0cb4-42b9-87ae-702df825a4a4@online.fr>
Hi Vincent,
On 4/3/2026 8:57 PM, Vincent Legoll wrote:> Hello,
>
>
> I applied this series on top of:
>
> - next-20260402
>
> -
>
https://patchwork.kernel.org/project/linux-riscv/patch/20260330-orangepi-sd-card-uhs-v5-9-bd853604322d@gmail.com/
>
> I need the the SD card series to boot from SD card.
>
You're absolutely right! We do need the SD series patches.
I'm actually building the mainline kernel using meta-riscv, and it's
default config
already includes those patches. I completely forgot about that.
Thanks.
>
> I'm also seeing the same "it works" state as Gong Shuai.
>
> So you can add another:
>
> Tested-by: Vincent Legoll <legoll@online.fr> # OrangePi-RV2
>
> Regards
>
> Thanks
>
^ permalink raw reply
* Re: [PATCH V10 03/13] PCI: dwc: Parse Root Port nodes in dw_pcie_host_init()
From: Manivannan Sadhasivam @ 2026-04-03 16:20 UTC (permalink / raw)
To: Sherry Sun
Cc: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
lpieralisi, kwilczynski, bhelgaas, hongxing.zhu, l.stach, imx,
linux-pci, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260402095107.205439-4-sherry.sun@nxp.com>
On Thu, Apr 02, 2026 at 05:50:57PM +0800, Sherry Sun wrote:
> Add support for parsing Root Port child nodes in dw_pcie_host_init()
> using pci_host_common_parse_ports(). This allows DWC-based drivers to
> specify Root Port properties (like reset GPIOs) in individual Root Port
> nodes rather than in the host bridge node.
>
> Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
> ---
> drivers/pci/controller/dwc/pcie-designware-host.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index da152c31bb2e..f6fca984fb34 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -20,6 +20,7 @@
> #include <linux/platform_device.h>
>
> #include "../../pci.h"
> +#include "../pci-host-common.h"
> #include "pcie-designware.h"
>
> static struct pci_ops dw_pcie_ops;
> @@ -581,6 +582,13 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
>
> pp->bridge = bridge;
>
> + /* Parse Root Port nodes if present */
> + ret = pci_host_common_parse_ports(dev, bridge);
> + if (ret && ret != -ENOENT) {
> + dev_err(dev, "Failed to parse Root Port nodes: %d\n", ret);
> + return ret;
Won't this change break drivers that parse Root Ports on their own? Either you
need to modify them also in this change or call this API from imx6 driver and
let other drivers switch to it in a phased manner.
I perfer the latter.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v1 03/13] clk: starfive: Add system-0 domain PLL clock driver
From: Brian Masney @ 2026-04-03 16:10 UTC (permalink / raw)
To: Changhuang Liang
Cc: Michael Turquette, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Stephen Boyd, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Philipp Zabel, Emil Renner Berthing, Chen Wang,
Inochi Amaoto, Alexey Charkov, Thomas Bogendoerfer, Keguang Zhang,
linux-clk, linux-kernel, devicetree, linux-riscv, Ley Foon Tan
In-Reply-To: <20260403054945.467700-4-changhuang.liang@starfivetech.com>
Hi Changhuang,
On Thu, Apr 02, 2026 at 10:49:35PM -0700, Changhuang Liang wrote:
> Add system-0 domain PLL clock driver for StarFive JHB100 SoC.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
> drivers/clk/starfive/Kconfig | 8 +
> drivers/clk/starfive/Makefile | 1 +
> .../clk/starfive/clk-starfive-jhb100-pll.c | 498 ++++++++++++++++++
> 3 files changed, 507 insertions(+)
> create mode 100644 drivers/clk/starfive/clk-starfive-jhb100-pll.c
>
> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> index c612f1ede7d7..cc712da68bd0 100644
> --- a/drivers/clk/starfive/Kconfig
> +++ b/drivers/clk/starfive/Kconfig
> @@ -105,6 +105,14 @@ config CLK_STARFIVE_JHB100_PER3
> Say yes here to support the peripheral-3 clock controller
> on the StarFive JHB100 SoC.
>
> +config CLK_STARFIVE_JHB100_PLL
> + bool "StarFive JHB100 PLL clock support"
> + depends on ARCH_STARFIVE || COMPILE_TEST
> + default ARCH_STARFIVE
> + help
> + Say yes here to support the PLL clock controller on the
> + StarFive JHB100 SoC.
> +
> config CLK_STARFIVE_JHB100_SYS0
> bool "StarFive JHB100 system-0 clock support"
> depends on ARCH_STARFIVE || COMPILE_TEST
> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> index f00690f0cdad..547a8c170728 100644
> --- a/drivers/clk/starfive/Makefile
> +++ b/drivers/clk/starfive/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_CLK_STARFIVE_JHB100_PER0) += clk-starfive-jhb100-per0.o
> obj-$(CONFIG_CLK_STARFIVE_JHB100_PER1) += clk-starfive-jhb100-per1.o
> obj-$(CONFIG_CLK_STARFIVE_JHB100_PER2) += clk-starfive-jhb100-per2.o
> obj-$(CONFIG_CLK_STARFIVE_JHB100_PER3) += clk-starfive-jhb100-per3.o
> +obj-$(CONFIG_CLK_STARFIVE_JHB100_PLL) += clk-starfive-jhb100-pll.o
> obj-$(CONFIG_CLK_STARFIVE_JHB100_SYS0) += clk-starfive-jhb100-sys0.o
> obj-$(CONFIG_CLK_STARFIVE_JHB100_SYS1) += clk-starfive-jhb100-sys1.o
> obj-$(CONFIG_CLK_STARFIVE_JHB100_SYS2) += clk-starfive-jhb100-sys2.o
> diff --git a/drivers/clk/starfive/clk-starfive-jhb100-pll.c b/drivers/clk/starfive/clk-starfive-jhb100-pll.c
> new file mode 100644
> index 000000000000..1751a734ee83
> --- /dev/null
> +++ b/drivers/clk/starfive/clk-starfive-jhb100-pll.c
> @@ -0,0 +1,498 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * StarFive JHB100 PLL Clock Generator Driver
> + *
> + * Copyright (C) 2024 StarFive Technology Co., Ltd.
> + *
> + * Author: Changhuang Liang <changhuang.liang@starfivetech.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk-provider.h>
> +#include <linux/debugfs.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#include <dt-bindings/clock/starfive,jhb100-crg.h>
> +
> +/* this driver expects a 25MHz input frequency from the oscillator */
> +#define JHB100_PLL_OSC_RATE 25000000UL
You could include linux/units.h and then use: 25 * HZ_PER_MHZ
> +
> +/* System-0 domain PLL */
> +#define JHB100_PLL2_OFFSET 0x00
> +#define JHB100_PLL3_OFFSET 0x0c
> +#define JHB100_PLL4_OFFSET 0x18
> +#define JHB100_PLL5_OFFSET 0x24
> +
> +#define JHB100_PLL_CFG0_OFFSET 0x0
> +#define JHB100_PLL_CFG1_OFFSET 0x4
> +#define JHB100_PLL_CFG2_OFFSET 0x8
> +
> +#define JHB100_PLLX_CFG0(offset) ((offset) + JHB100_PLL_CFG0_OFFSET)
> +/* fbdiv value should be 16 to 4095 */
> +#define JHB100_PLL_FBDIV GENMASK(13, 2)
> +#define JHB100_PLL_FBDIV_SHIFT 2
> +#define JHB100_PLL_FOUTPOSTDIV_EN BIT(14)
> +#define JHB100_PLL_FOUTPOSTDIV_EN_SHIFT 14
> +#define JHB100_PLL_FOUTVCOP_EN BIT(16)
> +#define JHB100_PLL_FOUTVCOP_EN_SHIFT 16
> +
> +#define JHB100_PLLX_CFG1(offset) ((offset) + JHB100_PLL_CFG1_OFFSET)
> +/* frac value should be decimals multiplied by 2^24 */
> +#define JHB100_PLL_FRAC GENMASK(23, 0)
> +#define JHB100_PLL_FRAC_SHIFT 0
> +#define JHB100_PLL_LOCK BIT(24)
> +#define JHB100_PLL_LOCK_SHIFT 24
> +
> +#define JHB100_PLLX_CFG2(offset) ((offset) + JHB100_PLL_CFG2_OFFSET)
> +#define JHB100_PLL_PD BIT(13)
> +#define JHB100_PLL_PD_SHIFT 13
> +#define JHB100_PLL_POSTDIV GENMASK(15, 14)
> +#define JHB100_PLL_POSTDIV_SHIFT 14
> +#define JHB100_PLL_REFDIV GENMASK(23, 18)
> +#define JHB100_PLL_REFDIV_SHIFT 18
> +
> +#define JHB100_PLL_TIMEOUT_US 1000
> +#define JHB100_PLL_INTERVAL_US 100
> +
> +struct jhb100_pll_preset {
> + unsigned long freq;
> + u32 frac; /* frac value should be decimals multiplied by 2^24 */
> + unsigned fbdiv : 12; /* fbdiv value should be 8 to 4095 */
> + unsigned refdiv : 6;
> + unsigned postdiv : 2;
> + unsigned foutpostdiv_en : 1;
> + unsigned foutvcop_en : 1;
> +};
> +
> +struct jhb100_pll_info {
> + char *name;
> + const struct jhb100_pll_preset *presets;
> + unsigned int npresets;
> + unsigned long flag;
> + u8 offset;
> + bool continuous;
> +};
> +
> +#define _JHB100_PLL(_idx, _name, _presets, _npresets, _offset, _flag, _cont) \
> + [_idx] = { \
> + .name = _name, \
> + .offset = _offset, \
> + .presets = _presets, \
> + .npresets = _npresets, \
> + .flag = _flag, \
> + .continuous = _cont, \
> + }
> +
> +#define JHB100_PLL(idx, name, presets, npresets, offset, cont) \
> + _JHB100_PLL(idx, name, presets, npresets, offset, 0, cont)
> +
> +struct jhb100_pll_match_data {
> + const struct jhb100_pll_info *pll_info;
> + int num_pll;
> +};
> +
> +struct jhb100_pll_data {
> + struct clk_hw hw;
> + unsigned int idx;
> +};
> +
> +struct jhb100_pll_priv {
> + struct device *dev;
> + struct regmap *regmap;
> + const struct jhb100_pll_match_data *match_data;
> + struct jhb100_pll_data pll[];
> +};
> +
> +struct jhb100_pll_regvals {
> + u32 fbdiv;
> + u32 frac;
> + u32 postdiv;
> + u32 refdiv;
> + bool foutpostdiv_en;
> + bool foutvcop_en;
> +};
> +
> +static struct jhb100_pll_data *jhb100_pll_data_from(struct clk_hw *hw)
> +{
> + return container_of(hw, struct jhb100_pll_data, hw);
> +}
> +
> +static struct jhb100_pll_priv *jhb100_pll_priv_from(struct jhb100_pll_data *pll)
> +{
> + return container_of(pll, struct jhb100_pll_priv, pll[pll->idx]);
> +}
> +
> +static int jhb100_pll_enable(struct clk_hw *hw)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + const struct jhb100_pll_info *info = &priv->match_data->pll_info[pll->idx];
> +
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG2(info->offset),
> + JHB100_PLL_PD, 0);
Should the return value be checked here? Or just:
return regumap_update_bits(...);
> +
> + return 0;
> +}
> +
> +static void jhb100_pll_disable(struct clk_hw *hw)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + const struct jhb100_pll_info *info = &priv->match_data->pll_info[pll->idx];
> +
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG2(info->offset),
> + JHB100_PLL_PD, BIT(JHB100_PLL_PD_SHIFT));
> +}
> +
> +static int jhb100_pll_is_enabled(struct clk_hw *hw)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + const struct jhb100_pll_info *info = &priv->match_data->pll_info[pll->idx];
> + u32 val;
> +
> + regmap_read(priv->regmap, JHB100_PLLX_CFG2(info->offset), &val);
Should the return value be checked?
> +
> + return !(val & JHB100_PLL_PD);
If regmap_read() returns an error, then is val uninitialized?
> +}
> +
> +static void jhb100_pll_regvals_get(struct regmap *regmap,
> + const struct jhb100_pll_info *info,
> + struct jhb100_pll_regvals *ret)
> +{
> + u32 val;
> +
> + regmap_read(regmap, JHB100_PLLX_CFG0(info->offset), &val);
> + ret->fbdiv = (val & JHB100_PLL_FBDIV) >> JHB100_PLL_FBDIV_SHIFT;
> + ret->foutpostdiv_en = !!((val & JHB100_PLL_FOUTPOSTDIV_EN) >>
> + JHB100_PLL_FOUTPOSTDIV_EN_SHIFT);
> + ret->foutvcop_en = !!((val & JHB100_PLL_FOUTVCOP_EN) >>
> + JHB100_PLL_FOUTVCOP_EN_SHIFT);
> +
> + regmap_read(regmap, JHB100_PLLX_CFG1(info->offset), &val);
> + ret->frac = (val & JHB100_PLL_FRAC) >> JHB100_PLL_FRAC_SHIFT;
> +
> + regmap_read(regmap, JHB100_PLLX_CFG2(info->offset), &val);
> + ret->postdiv = (val & JHB100_PLL_POSTDIV) >> JHB100_PLL_POSTDIV_SHIFT;
> + ret->refdiv = (val & JHB100_PLL_REFDIV) >> JHB100_PLL_REFDIV_SHIFT;
Should these regmap return values be checked, and the error code returned?
> +}
> +
> +static unsigned long jhb100_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + struct jhb100_pll_regvals val;
> + unsigned long rate;
> + u32 power = 0;
> +
> + jhb100_pll_regvals_get(priv->regmap, &priv->match_data->pll_info[pll->idx], &val);
> +
> + /*
> + *
> + * if (foutvcop_en)
> + * rate = parent * (fbdiv + frac / 2^24) / refdiv
> + *
> + * if (foutpostdiv_en)
> + * rate = parent * (fbdiv + frac / 2^24) / refdiv / 2^(postdiv + 1)
> + *
> + * parent * (fbdiv + frac / 2^24) = parent * fbdiv + parent * frac / 2^24
> + */
> +
> + if (!!val.foutvcop_en == !!val.foutpostdiv_en)
> + return 0;
> +
> + rate = (parent_rate * val.frac) >> 24;
> +
> + if (val.foutpostdiv_en)
> + power = val.postdiv + 1;
> +
> + rate += parent_rate * val.fbdiv;
> + rate /= val.refdiv << power;
Could val.refdiv ever be zero?
> +
> + return rate;
> +}
> +
> +static int jhb100_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + const struct jhb100_pll_info *info = &priv->match_data->pll_info[pll->idx];
> + const struct jhb100_pll_preset *selected = &info->presets[0];
> + unsigned int idx;
> +
> + /* if the parent rate doesn't match our expectations the presets won't work */
> + if (req->best_parent_rate != JHB100_PLL_OSC_RATE) {
> + req->rate = jhb100_pll_recalc_rate(hw, req->best_parent_rate);
> + return 0;
> + }
> +
> + /* continuous means support any rate */
> + if (info->continuous)
> + return 0;
> +
> + /* find highest rate lower or equal to the requested rate */
> + for (idx = 1; idx < info->npresets; idx++) {
> + const struct jhb100_pll_preset *val = &info->presets[idx];
> +
> + if (req->rate < val->freq)
> + break;
> +
> + selected = val;
> + }
> +
> + req->rate = selected->freq;
> +
> + return 0;
> +}
> +
> +static int jhb100_pll_set_preset(struct clk_hw *hw, struct jhb100_pll_preset *val)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + const struct jhb100_pll_info *info = &priv->match_data->pll_info[pll->idx];
> + unsigned int value;
> +
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG0(info->offset), JHB100_PLL_FBDIV,
> + (u32)val->fbdiv << JHB100_PLL_FBDIV_SHIFT);
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG0(info->offset), JHB100_PLL_FOUTPOSTDIV_EN,
> + (u32)val->foutpostdiv_en << JHB100_PLL_FOUTPOSTDIV_EN_SHIFT);
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG0(info->offset), JHB100_PLL_FOUTVCOP_EN,
> + (u32)val->foutvcop_en << JHB100_PLL_FOUTVCOP_EN_SHIFT);
These are writing to the same register. Should the values be combined
into one, and written once to the register?
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG1(info->offset), JHB100_PLL_FRAC,
> + val->frac << JHB100_PLL_FRAC_SHIFT);
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG2(info->offset), JHB100_PLL_REFDIV,
> + (u32)val->refdiv << JHB100_PLL_REFDIV_SHIFT);
> + regmap_update_bits(priv->regmap, JHB100_PLLX_CFG2(info->offset), JHB100_PLL_POSTDIV,
> + (u32)val->postdiv << JHB100_PLL_POSTDIV_SHIFT);
The last two calls to JHB100_PLLX_CFG2 also write to the same register.
Should the two writes be combined into one?
Should the return values from regmap_update_bits() be checked?
> +
> + /* waiting for PLL to lock */
> + return regmap_read_poll_timeout_atomic(priv->regmap, JHB100_PLLX_CFG1(info->offset),
> + value, value & JHB100_PLL_LOCK,
> + JHB100_PLL_INTERVAL_US,
> + JHB100_PLL_TIMEOUT_US);
> +}
> +
> +static int jhb100_pll_rate_to_preset(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct jhb100_pll_preset val = {
> + .refdiv = 1,
> + .postdiv = 3,
> + .foutpostdiv_en = 1,
> + .foutvcop_en = 0,
> + };
> + unsigned int power = 0;
> + unsigned long fbdiv_24, t;
> +
> + if (val.foutpostdiv_en)
> + power = val.postdiv + 1;
> +
> + t = val.refdiv << power;
> + t *= rate;
> +
> + val.fbdiv = t / parent_rate;
Should a check for parent_rate == 0 be added?
> +
> + fbdiv_24 = (t << 24) / parent_rate;
> + val.frac = fbdiv_24 - (val.fbdiv << 24);
> +
> + return jhb100_pll_set_preset(hw, &val);
> +}
> +
> +static int jhb100_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + const struct jhb100_pll_info *info = &priv->match_data->pll_info[pll->idx];
> + const struct jhb100_pll_preset *val;
> + unsigned int idx;
> +
> + /* if the parent rate doesn't match our expectations the presets won't work */
> + if (parent_rate != JHB100_PLL_OSC_RATE)
> + return -EINVAL;
> +
> + if (info->continuous)
> + return jhb100_pll_rate_to_preset(hw, rate, parent_rate);
> +
> + for (idx = 0, val = &info->presets[0]; idx < info->npresets; idx++, val++) {
> + if (val->freq == rate)
> + return jhb100_pll_set_preset(hw, (struct jhb100_pll_preset *)val);
The cast looks to be here because of the const in
jhb100_pll_set_preset(). Can const be added to the declaration of
jhb100_pll_set_preset()?
> + }
> + return -EINVAL;
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +static int jhb100_pll_registers_read(struct seq_file *s, void *unused)
> +{
> + struct jhb100_pll_data *pll = s->private;
> + struct jhb100_pll_priv *priv = jhb100_pll_priv_from(pll);
> + struct jhb100_pll_regvals val;
> +
> + jhb100_pll_regvals_get(priv->regmap, &priv->match_data->pll_info[pll->idx], &val);
> +
> + seq_printf(s, "fbdiv=%u\n"
> + "frac=%u\n"
> + "refdiv=%u\n"
> + "postdiv=%u\n"
> + "foutpostdiv_en=%u\n"
> + "foutvcop_en=%u\n",
> + val.fbdiv, val.frac, val.refdiv, val.postdiv,
> + val.foutpostdiv_en, val.foutvcop_en);
> +
> + return 0;
> +}
> +
> +static int jhb100_pll_registers_open(struct inode *inode, struct file *f)
> +{
> + return single_open(f, jhb100_pll_registers_read, inode->i_private);
> +}
> +
> +static const struct file_operations jhb100_pll_registers_ops = {
> + .owner = THIS_MODULE,
> + .open = jhb100_pll_registers_open,
> + .release = single_release,
> + .read = seq_read,
> + .llseek = seq_lseek
> +};
> +
> +static void jhb100_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
> +{
> + struct jhb100_pll_data *pll = jhb100_pll_data_from(hw);
> +
> + debugfs_create_file("registers", 0400, dentry, pll,
> + &jhb100_pll_registers_ops);
> +}
> +#else
> +#define jhb100_pll_debug_init NULL
> +#endif
> +
> +static const struct clk_ops jhb100_pll_ops = {
> + .enable = jhb100_pll_enable,
> + .disable = jhb100_pll_disable,
> + .is_enabled = jhb100_pll_is_enabled,
> + .recalc_rate = jhb100_pll_recalc_rate,
> + .determine_rate = jhb100_pll_determine_rate,
> + .set_rate = jhb100_pll_set_rate,
> + .debug_init = jhb100_pll_debug_init,
> +};
> +
> +static struct clk_hw *jhb100_pll_get(struct of_phandle_args *clkspec, void *data)
> +{
> + struct jhb100_pll_priv *priv = data;
> + unsigned int idx = clkspec->args[0];
> +
> + if (idx < priv->match_data->num_pll)
> + return &priv->pll[idx].hw;
> +
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static int __init jhb100_pll_probe(struct platform_device *pdev)
> +{
> + const struct jhb100_pll_match_data *match_data;
> + struct jhb100_pll_priv *priv;
> + unsigned int idx;
> + int ret;
> +
> + match_data = of_device_get_match_data(&pdev->dev);
> + if (!match_data)
> + return -EINVAL;
> +
> + priv = devm_kzalloc(&pdev->dev,
> + struct_size(priv, pll, match_data->num_pll),
> + GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->match_data = match_data;
> + priv->dev = &pdev->dev;
> + priv->regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + for (idx = 0; idx < match_data->num_pll; idx++) {
> + struct clk_parent_data parents = {
> + .index = 0,
> + };
> + struct clk_init_data init = {
> + .name = match_data->pll_info[idx].name,
> + .ops = &jhb100_pll_ops,
> + .parent_data = &parents,
> + .num_parents = 1,
> + .flags = match_data->pll_info[idx].flag,
> + };
> + struct jhb100_pll_data *pll = &priv->pll[idx];
> +
> + pll->hw.init = &init;
> + pll->idx = idx;
> +
> + ret = devm_clk_hw_register(&pdev->dev, &pll->hw);
> + if (ret)
> + return ret;
> + }
> +
> + return devm_of_clk_add_hw_provider(&pdev->dev, jhb100_pll_get, priv);
> +}
> +
> +static const struct jhb100_pll_preset jhb100_pll2_presets[] = {
> + {
> + .freq = 903168000,
> + .fbdiv = 72,
> + .frac = 4252017,
> + .refdiv = 1,
> + .postdiv = 0,
> + .foutpostdiv_en = 1,
> + .foutvcop_en = 0,
> + },
> +};
> +
> +static const struct jhb100_pll_preset jhb100_pll3_presets[] = {
> + {
> + .freq = 800000000,
> + .fbdiv = 64,
> + .frac = 0,
> + .refdiv = 1,
> + .postdiv = 0,
> + .foutpostdiv_en = 1,
> + .foutvcop_en = 0,
> + },
> +};
> +
> +static const struct jhb100_pll_info jhb100_sys0_pll_info[] = {
> + JHB100_PLL(JHB100_SYS0PLL_PLL2_OUT, "pll2_out", jhb100_pll2_presets,
> + ARRAY_SIZE(jhb100_pll2_presets), JHB100_PLL2_OFFSET, false),
> + _JHB100_PLL(JHB100_SYS0PLL_PLL3_OUT, "pll3_out", jhb100_pll3_presets,
> + ARRAY_SIZE(jhb100_pll3_presets), JHB100_PLL3_OFFSET,
> + CLK_IS_CRITICAL, false),
> + _JHB100_PLL(JHB100_SYS0PLL_PLL4_OUT, "pll4_out", NULL, 0,
> + JHB100_PLL4_OFFSET, CLK_IGNORE_UNUSED, true),
> + _JHB100_PLL(JHB100_SYS0PLL_PLL5_OUT, "pll5_out", NULL, 0,
> + JHB100_PLL5_OFFSET, CLK_IGNORE_UNUSED, true),
> +};
> +
> +static const struct jhb100_pll_match_data jhb100_sys0_pll = {
> + .pll_info = jhb100_sys0_pll_info,
> + .num_pll = ARRAY_SIZE(jhb100_sys0_pll_info),
> +};
> +
> +static const struct of_device_id jhb100_pll_match[] = {
> + {
> + .compatible = "starfive,jhb100-sys0-pll",
> + .data = (void *)&jhb100_sys0_pll,
The (void *) cast shouldn't be needed.
> + }, {
Put { on it's own newline.
Brian
> + /* sentinel */
> + }
> +};
> +MODULE_DEVICE_TABLE(of, jhb100_pll_match);
> +
> +static struct platform_driver jhb100_pll_driver = {
> + .driver = {
> + .name = "clk-starfive-jhb100-pll",
> + .of_match_table = jhb100_pll_match,
> + },
> +};
> +builtin_platform_driver_probe(jhb100_pll_driver, jhb100_pll_probe);
> --
> 2.25.1
>
^ permalink raw reply
* [PATCH v2 8/8] arm64: dts: amlogic: t7: khadas-vim4: Add i2c MCU fan node
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Enable and configure i2c MCU node to get fan working on Khadas VIM4.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index 69d6118ba57e7..5d7f5390f3a66 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -157,6 +157,19 @@ wifi32k: wifi32k {
};
};
+&i2c_m_ao_a {
+ status = "okay";
+ pinctrl-0 = <&i2c0_ao_d_pins>;
+ pinctrl-names = "default";
+
+ khadas_mcu: system-controller@18 {
+ compatible = "khadas,vim4-mcu";
+ reg = <0x18>;
+ fan-supply = <&vcc5v>;
+ #cooling-cells = <2>;
+ };
+};
+
&pwm_ab {
status = "okay";
pinctrl-0 = <&pwm_a_pins>;
--
2.49.0
^ permalink raw reply related
* [PATCH v2 5/8] thermal: khadas-mcu-fan: Add fan config from platform data Add regulator support
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Replace the hardcoded MAX_LEVEL constant and fan register
with values read from platform_data (fan_reg, max_level),
as new MCUs need different values.
Optionally acquire and enable a "fan" regulator supply
at probe time and on resume,
so boards that gate fan power through a regulator are handled.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
drivers/thermal/khadas_mcu_fan.c | 49 +++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 6 deletions(-)
diff --git a/drivers/thermal/khadas_mcu_fan.c b/drivers/thermal/khadas_mcu_fan.c
index d35e5313bea41..24559bf65de46 100644
--- a/drivers/thermal/khadas_mcu_fan.c
+++ b/drivers/thermal/khadas_mcu_fan.c
@@ -13,13 +13,15 @@
#include <linux/regmap.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
-
-#define MAX_LEVEL 3
+#include <linux/regulator/consumer.h>
struct khadas_mcu_fan_ctx {
struct khadas_mcu *mcu;
+ unsigned int fan_reg;
unsigned int level;
+ unsigned int max_level;
struct thermal_cooling_device *cdev;
+ struct regulator *power;
};
static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
@@ -27,8 +29,7 @@ static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
{
int ret;
- ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
- level);
+ ret = regmap_write(ctx->mcu->regmap, ctx->fan_reg, level);
if (ret)
return ret;
@@ -40,7 +41,9 @@ static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
- *state = MAX_LEVEL;
+ struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
+
+ *state = ctx->max_level;
return 0;
}
@@ -61,7 +64,7 @@ khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev,
{
struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
- if (state > MAX_LEVEL)
+ if (state > ctx->max_level)
return -EINVAL;
if (state == ctx->level)
@@ -83,11 +86,32 @@ static int khadas_mcu_fan_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct khadas_mcu_fan_ctx *ctx;
int ret;
+ const struct khadas_mcu_fan_pdata *pdata = dev_get_platdata(&pdev->dev);
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+
ctx->mcu = mcu;
+ ctx->fan_reg = pdata->fan_reg;
+ ctx->max_level = pdata->max_level;
+
+ ctx->power = devm_regulator_get_optional(dev->parent, "fan");
+ if (IS_ERR(ctx->power)) {
+ if (PTR_ERR(ctx->power) == -ENODEV)
+ ctx->power = NULL;
+ else
+ return PTR_ERR(ctx->power);
+ }
+
+ if (ctx->power) {
+ ret = regulator_enable(ctx->power);
+ if (ret) {
+ dev_err(dev, "Failed to enable fan power supply: %d\n", ret);
+ return ret;
+ }
+ }
+
platform_set_drvdata(pdev, ctx);
cdev = devm_thermal_of_cooling_device_register(dev->parent,
@@ -124,12 +148,25 @@ static int khadas_mcu_fan_suspend(struct device *dev)
ctx->level = level_save;
+ if (ctx->power) {
+ ret = regulator_disable(ctx->power);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
static int khadas_mcu_fan_resume(struct device *dev)
{
struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
+ int ret;
+
+ if (ctx->power) {
+ ret = regulator_enable(ctx->power);
+ if (ret)
+ return ret;
+ }
return khadas_mcu_fan_set_level(ctx, ctx->level);
}
--
2.49.0
^ permalink raw reply related
* [PATCH v2 7/8] arm64: dts: amlogic: t7: Add i2c controller node
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Add the T7 i2c controller node used by the Khadas VIM4
for MCU communication.
Use amlogic,meson-axg-i2c as fallback compatible.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index e96fe10b251a0..560c9dce35266 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -711,6 +711,16 @@ pwm_ao_cd: pwm@60000 {
status = "disabled";
};
+ i2c_m_ao_a: i2c@76000 {
+ compatible = "amlogic,t7-i2c", "amlogic,meson-axg-i2c";
+ reg = <0x0 0x76000 0x0 0x48>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc_periphs CLKID_SYS_I2C_AO_A>;
+ status = "disabled";
+ };
+
sd_emmc_a: mmc@88000 {
compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
reg = <0x0 0x88000 0x0 0x800>;
--
2.49.0
^ permalink raw reply related
* [PATCH v2 6/8] arm64: dts: amlogic: t7: Add i2c pinctrl node
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Add the T7 pinctrl used by the Khadas VIM4 for MCU communication.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 7fe72c94ed623..e96fe10b251a0 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -376,6 +376,16 @@ mux {
};
};
+ i2c0_ao_d_pins: i2c0-ao-d {
+ mux {
+ groups = "i2c0_ao_sck_d",
+ "i2c0_ao_sda_d";
+ function = "i2c0_ao";
+ bias-disable;
+ drive-strength-microamp = <3000>;
+ };
+ };
+
pwm_a_pins: pwm-a {
mux {
groups = "pwm_a";
--
2.49.0
^ permalink raw reply related
* [PATCH v2 4/8] mfd: khadas-mcu: Add support for VIM4 MCU variant
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Refactor probe() to use per-variant khadas_mcu_data
instead of hardcoded globals.
Add dedicated regmap configuration and device data for the VIM4 MCU,
with its own volatile/writeable registers.
Add the fan control register
(0–100 levels vs 0–3 for previous supported boards).
Add a new compatible string "khadas,vim4-mcu".
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
drivers/mfd/khadas-mcu.c | 106 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 95 insertions(+), 11 deletions(-)
diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c
index ba981a7886921..b36b3b3ab73c0 100644
--- a/drivers/mfd/khadas-mcu.c
+++ b/drivers/mfd/khadas-mcu.c
@@ -75,15 +75,91 @@ static const struct regmap_config khadas_mcu_regmap_config = {
.cache_type = REGCACHE_MAPLE,
};
+static const struct khadas_mcu_fan_pdata khadas_mcu_fan_pdata = {
+ .fan_reg = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
+ .max_level = 3,
+};
+
static struct mfd_cell khadas_mcu_fan_cells[] = {
/* VIM1/2 Rev13+ and VIM3 only */
- { .name = "khadas-mcu-fan-ctrl", },
+ {
+ .name = "khadas-mcu-fan-ctrl",
+ .platform_data = &khadas_mcu_fan_pdata,
+ .pdata_size = sizeof(khadas_mcu_fan_pdata),
+ },
};
static struct mfd_cell khadas_mcu_cells[] = {
{ .name = "khadas-mcu-user-mem", },
};
+static const struct khadas_mcu_data khadas_mcu_data = {
+ .regmap_config = &khadas_mcu_regmap_config,
+ .cells = khadas_mcu_cells,
+ .ncells = ARRAY_SIZE(khadas_mcu_cells),
+ .fan_cells = khadas_mcu_fan_cells,
+ .nfan_cells = ARRAY_SIZE(khadas_mcu_fan_cells),
+};
+
+static bool khadas_mcu_vim4_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case KHADAS_MCU_PWR_OFF_CMD_REG:
+ case KHADAS_MCU_VIM4_REST_CONF_REG:
+ case KHADAS_MCU_WOL_INIT_START_REG:
+ case KHADAS_MCU_VIM4_LED_ON_RAM_REG:
+ case KHADAS_MCU_VIM4_FAN_CTRL_REG:
+ case KHADAS_MCU_VIM4_WDT_EN_REG:
+ case KHADAS_MCU_VIM4_SYS_RST_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool khadas_mcu_vim4_reg_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case KHADAS_MCU_VERSION_0_REG:
+ case KHADAS_MCU_VERSION_1_REG:
+ case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config khadas_mcu_vim4_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .max_register = KHADAS_MCU_VIM4_SYS_RST_REG,
+ .volatile_reg = khadas_mcu_vim4_reg_volatile,
+ .writeable_reg = khadas_mcu_vim4_reg_writeable,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct khadas_mcu_fan_pdata khadas_vim4_fan_pdata = {
+ .fan_reg = KHADAS_MCU_VIM4_FAN_CTRL_REG,
+ .max_level = 0x64,
+};
+
+static const struct mfd_cell khadas_mcu_vim4_cells[] = {
+ {
+ .name = "khadas-mcu-fan-ctrl",
+ .platform_data = &khadas_vim4_fan_pdata,
+ .pdata_size = sizeof(khadas_vim4_fan_pdata),
+ },
+};
+
+static const struct khadas_mcu_data khadas_vim4_mcu_data = {
+ .regmap_config = &khadas_mcu_vim4_regmap_config,
+ .cells = NULL,
+ .ncells = 0,
+ .fan_cells = khadas_mcu_vim4_cells,
+ .nfan_cells = ARRAY_SIZE(khadas_mcu_vim4_cells),
+};
+
static int khadas_mcu_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -94,28 +170,35 @@ static int khadas_mcu_probe(struct i2c_client *client)
if (!ddata)
return -ENOMEM;
+ ddata->data = i2c_get_match_data(client);
+ if (!ddata->data)
+ return -EINVAL;
+
i2c_set_clientdata(client, ddata);
ddata->dev = dev;
- ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
+ ddata->regmap = devm_regmap_init_i2c(client,
+ ddata->data->regmap_config);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
dev_err(dev, "Failed to allocate register map: %d\n", ret);
return ret;
}
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_cells,
- ARRAY_SIZE(khadas_mcu_cells),
- NULL, 0, NULL);
- if (ret)
- return ret;
+ if (ddata->data->cells && ddata->data->ncells) {
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ ddata->data->cells,
+ ddata->data->ncells,
+ NULL, 0, NULL);
+ if (ret)
+ return ret;
+ }
if (of_property_present(dev->of_node, "#cooling-cells"))
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_fan_cells,
- ARRAY_SIZE(khadas_mcu_fan_cells),
+ ddata->data->fan_cells,
+ ddata->data->nfan_cells,
NULL, 0, NULL);
return 0;
@@ -123,7 +206,8 @@ static int khadas_mcu_probe(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id khadas_mcu_of_match[] = {
- { .compatible = "khadas,mcu", },
+ { .compatible = "khadas,mcu", .data = &khadas_mcu_data },
+ { .compatible = "khadas,vim4-mcu", .data = &khadas_vim4_mcu_data },
{},
};
MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
--
2.49.0
^ permalink raw reply related
* [PATCH v2 3/8] mfd: khadas-mcu: Add per-variant configuration infrastructure and VIM4 support
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Introduce a per-variant configuration structure (khadas_mcu_data)
holding the regmap config and MFD cells,
selected at probe time via the of_device_id match data.
This makes adding other variants straightforward.
Also introduce khadas_mcu_fan_pdata to pass fan register address and
maximum level to the fan sub-driver, removing the hardcoded constants.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
include/linux/mfd/khadas-mcu.h | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/include/linux/mfd/khadas-mcu.h b/include/linux/mfd/khadas-mcu.h
index a99ba2ed0e4e0..75e275d3fa8d9 100644
--- a/include/linux/mfd/khadas-mcu.h
+++ b/include/linux/mfd/khadas-mcu.h
@@ -70,6 +70,13 @@
#define KHADAS_MCU_WOL_INIT_START_REG 0x87 /* WO */
#define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG 0x88 /* WO */
+/* VIM4 specific registers */
+#define KHADAS_MCU_VIM4_REST_CONF_REG 0x2c /* WO - reset EEPROM */
+#define KHADAS_MCU_VIM4_LED_ON_RAM_REG 0x89 /* WO - LED volatile */
+#define KHADAS_MCU_VIM4_FAN_CTRL_REG 0x8a /* WO */
+#define KHADAS_MCU_VIM4_WDT_EN_REG 0x8b /* WO */
+#define KHADAS_MCU_VIM4_SYS_RST_REG 0x91 /* WO */
+
enum {
KHADAS_BOARD_VIM1 = 0x1,
KHADAS_BOARD_VIM2,
@@ -82,10 +89,38 @@ enum {
* struct khadas_mcu - Khadas MCU structure
* @device: device reference used for logs
* @regmap: register map
+ * @data: pointer to variant-specific config
*/
struct khadas_mcu {
- struct device *dev;
- struct regmap *regmap;
+ struct device *dev;
+ struct regmap *regmap;
+ const struct khadas_mcu_data *data;
+};
+
+/**
+ * struct khadas_mcu_data - per-variant configuration
+ * @regmap_config: regmap configuration
+ * @cells: MFD sub-devices
+ * @ncells: number of sub-devices
+ * @fan_cells: MFD fan sub-devices
+ * @nfan_cells: number of fan sub-devices
+ */
+struct khadas_mcu_data {
+ const struct regmap_config *regmap_config;
+ const struct mfd_cell *cells;
+ int ncells;
+ const struct mfd_cell *fan_cells;
+ int nfan_cells;
+};
+
+/**
+ * struct khadas_mcu_fan_pdata - fan sub-driver configuration
+ * @fan_reg: register address to write the fan level
+ * @max_level: maximum fan level
+ */
+struct khadas_mcu_fan_pdata {
+ unsigned int fan_reg;
+ unsigned int max_level;
};
#endif /* MFD_KHADAS_MCU_H */
--
2.49.0
^ permalink raw reply related
* [PATCH v2 2/8] dt-bindings: i2c: amlogic: Add compatible for T7 SOC
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Add the T7 SOC compatible which fallback to AXG compatible.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../devicetree/bindings/i2c/amlogic,meson6-i2c.yaml | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml b/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
index c4cc8af182807..7b59b60b62e5b 100644
--- a/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
@@ -16,10 +16,15 @@ allOf:
properties:
compatible:
- enum:
- - amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
- - amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
- - amlogic,meson-axg-i2c # AXG and compatible SoCs
+ oneOf:
+ - items:
+ - enum:
+ - amlogic,t7-i2c
+ - const: amlogic,meson-axg-i2c
+ - enum:
+ - amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
+ - amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
+ - amlogic,meson-axg-i2c # AXG and compatible SoCs
reg:
maxItems: 1
--
2.49.0
^ permalink raw reply related
* [PATCH v2 0/8] Add VIM4 MCU/FAN support
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
The Khadas VIM4 board features a different MCU variant compared to
previous VIM boards.
While it shares the same I2C-based communication model,
it differs in some ways:
- A distinct register map with its own volatile/writeable register set
- A fan control with 0–100 levels instead of the 0–3 levels previously
- A fan power supply gated through a regulator
This series adds support for this new variant by:
1. Refactoring the khadas-mcu MFD driver to use per-variant data
structures (regmap config, cells, fan platform data),
and adding the khadas,vim4-mcu compatible string.
2. Extending the fan thermal driver to retrieve the fan register
and maximum level from platform_data,
and to optionally manage a power regulator for the fan supply.
3. Adding the corresponding DTS node for the VIM4, wiring the MCU to
the I2C AO_A bus and exposing it as a thermal cooling device.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Changes in v2:
- PATCH 5: Add regulator_disable on suspend thanks to Neil's feedback.
- Link to v1: https://lore.kernel.org/r/20260402-add-mcu-fan-khadas-vim4-v1-0-2b12eb4ac7b0@aliel.fr
---
Ronald Claveau (8):
dt-bindings: mfd: khadas: Add new compatible for Khadas VIM4 MCU
dt-bindings: i2c: amlogic: Add compatible for T7 SOC
mfd: khadas-mcu: Add per-variant configuration infrastructure and VIM4 support
mfd: khadas-mcu: Add support for VIM4 MCU variant
thermal: khadas-mcu-fan: Add fan config from platform data Add regulator support
arm64: dts: amlogic: t7: Add i2c pinctrl node
arm64: dts: amlogic: t7: Add i2c controller node
arm64: dts: amlogic: t7: khadas-vim4: Add i2c MCU fan node
.../bindings/i2c/amlogic,meson6-i2c.yaml | 13 ++-
.../devicetree/bindings/mfd/khadas,mcu.yaml | 5 +
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 13 +++
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 20 ++++
drivers/mfd/khadas-mcu.c | 106 ++++++++++++++++++---
drivers/thermal/khadas_mcu_fan.c | 49 ++++++++--
include/linux/mfd/khadas-mcu.h | 39 +++++++-
7 files changed, 222 insertions(+), 23 deletions(-)
---
base-commit: f7b64ed948718290209074a50bb0df17e5944873
change-id: 20260402-add-mcu-fan-khadas-vim4-ac1cbe553c9b
prerequisite-message-id: <20260326092645.1053261-1-jian.hu@amlogic.com>
prerequisite-patch-id: f03a086b4137158412b2d47b3de793b858de8dde
prerequisite-patch-id: 123970c9b29c2090440f2fd71c85d3c6fd8e36de
prerequisite-patch-id: 3e2e56b0926ba327b520f935df4ced5089bbe503
prerequisite-patch-id: 65a5d76ffdbc9b3aab3385bb65cb027004c30e7e
prerequisite-patch-id: 237269801826dd3ad7fb16eb4d7d6d4eab504278
prerequisite-patch-id: 57e9b08a968aedf543d3d0d56cf1ca4db20b2a16
prerequisite-change-id: 20260326-add-bcm43752-compatible-e264a4f7973a:v2
prerequisite-patch-id: cd98b74fa56af72af2553f391c400981d83cd4f4
prerequisite-patch-id: b730f5e42be1d89d193e63a0265495cdbf2c7d7b
prerequisite-change-id: 20260330-fix-invalid-property-bbe54d933f71:v2
prerequisite-patch-id: 8d675e7a239985c762843515b241f0a2f45f9c92
prerequisite-change-id: 20260331-fix-aml-t7-null-reset-2b608ebf9da4:v1
prerequisite-patch-id: 5b5de77af11747ce964404fb827d2ee2bff47ea5
prerequisite-patch-id: 1e37fc75fed1e533adee0f3e7e6ead1f8ff3c55c
prerequisite-patch-id: 65a5d76ffdbc9b3aab3385bb65cb027004c30e7e
prerequisite-patch-id: 2daf583fb5e7449a02bd217d8aca330171b598aa
prerequisite-patch-id: 237269801826dd3ad7fb16eb4d7d6d4eab504278
prerequisite-patch-id: d1ddf9b7710e91f8062de83bd7ba55afb2c4c112
prerequisite-patch-id: 57e9b08a968aedf543d3d0d56cf1ca4db20b2a16
prerequisite-patch-id: cd98b74fa56af72af2553f391c400981d83cd4f4
prerequisite-patch-id: b730f5e42be1d89d193e63a0265495cdbf2c7d7b
prerequisite-patch-id: 9debd88fa60febed9cd7208f86603b4c2d270520
prerequisite-patch-id: 314ef9ff0c4d1d15dab1dea9d92aa065f1eac3e9
Best regards,
--
Ronald Claveau <linux-kernel-dev@aliel.fr>
^ permalink raw reply
* [PATCH v2 1/8] dt-bindings: mfd: khadas: Add new compatible for Khadas VIM4 MCU
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
The Khadas VIM4 MCU register is slightly different
from previous boards' MCU.
This board also features a switchable power source for its fan.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
index 084960fd5a1fd..67769ef5d58b1 100644
--- a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
+++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
@@ -18,6 +18,7 @@ properties:
compatible:
enum:
- khadas,mcu # MCU revision is discoverable
+ - khadas,vim4-mcu
"#cooling-cells": # Only needed for boards having FAN control feature
const: 2
@@ -25,6 +26,10 @@ properties:
reg:
maxItems: 1
+ fan-supply:
+ description: Phandle to the regulator that powers the fan.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
required:
- compatible
- reg
--
2.49.0
^ permalink raw reply related
* Re: (subset) [PATCH 05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
From: Alexandre Belloni @ 2026-04-03 16:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Ulf Hansson, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Saenz Julienne, Lee Jones, Liam Girdwood, Mark Brown,
Shree Ramamoorthy, Jerome Neanne, Paul Cercueil, Dmitry Osipenko,
Heiko Stuebner, Joseph Chen, Chris Zhong, Zhang Qing,
Sebastian Reichel, Andreas Kemnade, Jonathan Neuschäfer,
Lubomir Rintel, Julien Panis, Matti Vaittinen, Alexander Kurz,
Krzysztof Kozlowski, André Draszik, Peng Fan (OSS)
Cc: devicetree, linux-kernel, linux-rpi-kernel, linux-arm-kernel,
linux-rtc, linux-rockchip, linux-samsung-soc, Peng Fan
In-Reply-To: <20260316-power-controller-v1-5-92c80e5e1744@nxp.com>
On Mon, 16 Mar 2026 22:47:40 +0800, Peng Fan (OSS) wrote:
> Convert the binding to use the generic power-controller schema instead by
> referencing power-controller.yaml and removing the local
> `system-power-controller` property definition.
Applied, thanks!
[05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
https://git.kernel.org/abelloni/c/0452290110cc
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v20 06/10] power: reset: Add psci-reboot-mode driver
From: Lorenzo Pieralisi @ 2026-04-03 15:50 UTC (permalink / raw)
To: Shivendra Pratap
Cc: Arnd Bergmann, Bjorn Andersson, Sebastian Reichel, Rob Herring,
Souvik Chakravarty, Krzysztof Kozlowski, Andy Yan,
Matthias Brugger, Mark Rutland, Conor Dooley, Konrad Dybcio,
John Stultz, Moritz Fischer, Bartosz Golaszewski, Sudeep Holla,
Florian Fainelli, Krzysztof Kozlowski, Dmitry Baryshkov,
Mukesh Ojha, Andre Draszik, Kathiravan Thirumoorthy, linux-pm,
linux-kernel, linux-arm-kernel, linux-arm-msm, devicetree,
Srinivas Kandagatla
In-Reply-To: <da6f4566-a719-409b-80a9-40ca89e3e721@oss.qualcomm.com>
On Fri, Apr 03, 2026 at 12:05:27AM +0530, Shivendra Pratap wrote:
>
>
> On 01-04-2026 20:07, Lorenzo Pieralisi wrote:
> > On Tue, Mar 31, 2026 at 11:30:09PM +0530, Shivendra Pratap wrote:
> > >
> > >
> > > On 27-03-2026 19:25, Lorenzo Pieralisi wrote:
> > > > On Wed, Mar 04, 2026 at 11:33:06PM +0530, Shivendra Pratap wrote:
> > > > > PSCI supports different types of resets like COLD reset, ARCH WARM
>
> [snip..]
>
> > > > > + * Predefined reboot-modes are defined as per the values
> > > > > + * of enum reboot_mode defined in the kernel: reboot.c.
> > > > > + */
> > > > > +static struct mode_info psci_resets[] = {
> > > > > + { .mode = "warm", .magic = REBOOT_WARM},
> > > > > + { .mode = "soft", .magic = REBOOT_SOFT},
> > > > > + { .mode = "cold", .magic = REBOOT_COLD},
> >
> > These strings match the command userspace issue right ? I think that we
> > should make them match the corresponding PSCI reset types, the list above
> > maps command to reboot_mode values and those can belong to any reboot
> > mode driver to be honest they don't make much sense in a PSCI reboot
> > mode driver only.
> >
> > It is a question for everyone here: would it make sense to make these
> > predefined resets a set of strings, eg:
> >
> > psci-system-reset
> > psci-system-reset2-arch-warm-reset
> >
> > and then vendor resets:
> >
> > psci-system-reset2-vendor-reset
>
> Can you share bit more details on this? We are already defining the string
> from userspace in the struct - eg: ".mode = "warm".
"warm","soft","cold" are not strictly speaking PSCI concepts and mean nothing
well defined to user space and even if they did, they would not belong in
the PSCI reboot mode driver but in generic code.
Spelling out what a reset is might help instead, again, this is just my
opinion, I don't know how the semantics of resets have been handled thus
far.
If userspace issues a LINUX_REBOOT_CMD_RESTART2 with arg, say,
"psci-system-reset2-arch-warm-reset" it is pretty clear what it wants
to do in PSCI.
Again, it is a suggestion, comments welcome.
> yes we can move away from enum reboot_mode and use custom psci defines one -
> Ack.
>
> >
>
> [snip ..]
>
> > > > > +
> > > > > +/*
> > > > > + * arg1 is reset_type(Low 32 bit of magic).
> > > > > + * arg2 is cookie(High 32 bit of magic).
> > > > > + * If reset_type is 0, cookie will be used to decide the reset command.
> > > > > + */
> > > > > +static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
> > > > > +{
> > > > > + u32 reset_type = REBOOT_MODE_ARG1(magic);
> > > > > + u32 cookie = REBOOT_MODE_ARG2(magic);
> > > > > +
> > > > > + if (reset_type == 0) {
> > > > > + if (cookie == REBOOT_WARM || cookie == REBOOT_SOFT)
> > > > > + psci_set_reset_cmd(true, 0, 0);
> > > > > + else
> > > > > + psci_set_reset_cmd(false, 0, 0);
> > > > > + } else {
> > > > > + psci_set_reset_cmd(true, reset_type, cookie);
> > > > > + }
> > > >
> > > > I don't think that psci_set_reset_cmd() has the right interface (and this
> > > > nested if is too complicated for my taste). All we need to pass is reset-type
> > > > and cookie (and if the reset is one of the predefined ones, reset-type is 0
> > > > and cookie is the REBOOT_* cookie).
> > > >
> > > > Then the PSCI firmware driver will take the action according to what
> > > > resets are available.
> > > >
> > > > How does it sound ?
> > >
> > > So we mean these checks will move to the psci driver? Sorry for re-iterating
> > > the question.
> >
> > Given what I say above, I believe that something we can do is mapping the magic
> > to an enum like:
> >
> > PSCI_SYSTEM_RESET
> > PSCI_SYSTEM_RESET2_ARCH_SYSTEM_WARM_RESET
> > PSCI_SYSTEM_RESET2_VENDOR_RESET
> >
> > and can add a probe function into PSCI driver similar to psci_has_osi_support() but
> > to probe for SYSTEM_RESET2 and initialize the predefined strings accordingly,
> > depending on its presence.
>
> Not able to get it cleanly.
>
> 1. Will move away from reboot_mode enum for pre-defined modes and define new
> enum defining these modes- fine.
> 2. get SYSTEM_RESET2 is supported from psci exported function -- fine, but
> how we use it here now, as we do not want to send the reset_cmd from
> psci_set_reset_cmd now?
You do keep psci_set_reset_cmd() but all it is used for is setting a struct
shared with the PSCI driver where you initialize the enum above, possibly
with a cookie if it is a vendor reset.
> 3. For pre-defined modes, warm/soft or cold - reset_type and cookie, both
> are zero, sys_reset2 or sys_reset2 decides the ARCH reset vs cold reset.
> 4. For vendor-rest , we use sys_reset2 with reset_type and cookie.
Yes.
> All above is done in reboot_notifier call at psci-reboot-mode.
> --
>
> Now in the final restart_notifier->psci_sys_reset --
>
> If panic is in progress, we do not use any of the cmd based reset params and
> go with the legacy reset. So we need to preserve the values that were set
> from psci-reboot-mode.
>
> Did not understand the proposed suggestion in above usecase. Need more input
> on this.
I explained above. The reboot mode driver sets the command to carry out
depending on the string coming from user space and whether PSCI supports
SYSTEM_RESET2 or not.
> --
>
> One other option is to have a restart_notifier in psci-reboot-mode, with
> lesser priority than psci_sys_rest and then handle all the case including
> panic and sys_reset2.
No.
Thanks,
Lorenzo
^ permalink raw reply
* [PATCH v2 0/3] iio: adc: qcom-pm8xxx-xoadc: add support for reading channel labels from DT
From: Antony Kurniawan Soemardi @ 2026-04-03 9:23 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Cc: linux-arm-msm, devicetree, linux-kernel, linux-iio, phone-devel,
Antony Kurniawan Soemardi, Konrad Dybcio
This series adds support for reading channel labels from the device tree
in the Qualcomm PM8xxx XOADC driver, along with the corresponding DT
updates for the PM8921 PMIC. Redundant error logging in pm8xxx_read_raw
is also removed, as returning -EINVAL is sufficient when the channel is
not found.
Tested on Sony Xperia SP (PM8921):
> cat /sys/bus/iio/devices/iio\:device0/in_voltage7_label
usb_vbus
> cat /sys/bus/iio/devices/iio\:device0/in_temp12_label
ref_muxoff
> sensors
iio_hwmon-isa-0000
Adapter: ISA adapter
vbat: 267.86 V
dcin: 4.82 kV
...
chg_temp: +1071.4°C
Note: the sensor readings above are incorrect due to pending calibration
fixes are not included in this series. This patch only addresses label
visibility. The values are expected to be wrong until the calibration
fixes lands separately.
Signed-off-by: Antony Kurniawan Soemardi <linux@smankusors.com>
---
Changes in v2:
- Remove redundant error logging in pm8xxx_read_raw, since -EINVAL is
sufficient to report failures.
- Reword the uncommon Tested-by commit tag to freeform text
- Link to v1: https://lore.kernel.org/r/20260326-pm8xxx-xoadc-label-v1-0-027805dad4db@smankusors.com
Changes since original patch:
- The label is now read from the platform description (device tree)
instead of the internal datasheet name.
- Link to original patch:
https://lore.kernel.org/all/20251028-pm8xxx-xoadc-fix-v1-1-b000e1036e41@smankusors.com/
---
Antony Kurniawan Soemardi (3):
ARM: dts: qcom: pm8921: add labels for ADC channels
iio: adc: qcom-pm8xxx-xoadc: remove redundant error logging in pm8xxx_read_raw
iio: adc: qcom-pm8xxx-xoadc: add support for reading channel labels
arch/arm/boot/dts/qcom/pm8921.dtsi | 12 ++++++++++++
drivers/iio/adc/qcom-pm8xxx-xoadc.c | 34 +++++++++++++++++++++-------------
2 files changed, 33 insertions(+), 13 deletions(-)
---
base-commit: 5619b098e2fbf3a23bf13d91897056a1fe238c6d
change-id: 20260321-pm8xxx-xoadc-label-47afdf7f06a9
Best regards,
--
Antony Kurniawan Soemardi <linux@smankusors.com>
^ permalink raw reply
* Re: [PATCH v6 09/10] clk: realtek: Add RTD1625-ISO clock controller driver
From: Brian Masney @ 2026-04-03 15:29 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-10-eleanor.lin@realtek.com>
Hi Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:56PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add support for the ISO (Isolation) domain clock controller on the Realtek
> RTD1625 SoC. This controller manages clocks in the always-on power domain,
> ensuring essential services remain functional even when the main system
> power is gated.
>
> Since the reset controller shares the same register space with the ISO
> clock controller, it is instantiated as an auxiliary device by the core
> clock driver. This patch also includes the corresponding auxiliary reset
> driver to handle the ISO domain resets.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move struct rtk_reset_desc arrays from the clock driver to the dedicated reset driver.
> - Implement and register a dedicated reset auxiliary driver.
> ---
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-rtd1625-iso.c | 144 ++++++++++++++++++++++
> drivers/reset/realtek/Makefile | 2 +-
> drivers/reset/realtek/reset-rtd1625-iso.c | 96 +++++++++++++++
> 4 files changed, 242 insertions(+), 1 deletion(-)
> create mode 100644 drivers/clk/realtek/clk-rtd1625-iso.c
> create mode 100644 drivers/reset/realtek/reset-rtd1625-iso.c
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index c992f97dfbc7..1680435e1e0f 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -10,3 +10,4 @@ clk-rtk-y += freq_table.o
>
> clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-crt.o
> +obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-iso.o
> diff --git a/drivers/clk/realtek/clk-rtd1625-iso.c b/drivers/clk/realtek/clk-rtd1625-iso.c
> new file mode 100644
> index 000000000000..027a131363f9
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-rtd1625-iso.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <dt-bindings/clock/realtek,rtd1625-clk.h>
> +#include <linux/array_size.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap-gate.h"
> +
> +#define RTD1625_ISO_CLK_MAX 19
> +#define RTD1625_ISO_RSTN_MAX 29
> +#define RTD1625_ISO_S_CLK_MAX 5
> +#define RTD1625_ISO_S_RSTN_MAX 5
> +
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_p4, 0, 0x4, 0, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_p3, 0, 0x4, 1, 0);
> +static CLK_REGMAP_GATE(clk_en_misc_cec0, "clk_en_misc", 0, 0x4, 2, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbusrx_sys, 0, 0x4, 3, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbustx_sys, 0, 0x4, 4, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbus_sys, 0, 0x4, 5, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbus_osc, 0, 0x4, 6, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_i2c0, 0, 0x4, 9, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_i2c1, 0, 0x4, 10, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_etn_250m, 0, 0x4, 11, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_etn_sys, 0, 0x4, 12, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_drd, 0, 0x4, 13, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_host, 0, 0x4, 14, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_u3_host, 0, 0x4, 15, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb, 0, 0x4, 16, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_vtc, 0, 0x4, 17, 0);
> +static CLK_REGMAP_GATE(clk_en_misc_vfd, "clk_en_misc", 0, 0x4, 18, 0);
> +
> +static struct clk_regmap *rtd1625_clk_regmap_list[] = {
static const? Same for some others below as well.
> + &clk_en_usb_p4.clkr,
> + &clk_en_usb_p3.clkr,
> + &clk_en_misc_cec0.clkr,
> + &clk_en_cbusrx_sys.clkr,
> + &clk_en_cbustx_sys.clkr,
> + &clk_en_cbus_sys.clkr,
> + &clk_en_cbus_osc.clkr,
> + &clk_en_i2c0.clkr,
> + &clk_en_i2c1.clkr,
> + &clk_en_etn_250m.clkr,
> + &clk_en_etn_sys.clkr,
> + &clk_en_usb_drd.clkr,
> + &clk_en_usb_host.clkr,
> + &clk_en_usb_u3_host.clkr,
> + &clk_en_usb.clkr,
> + &clk_en_vtc.clkr,
> + &clk_en_misc_vfd.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_iso_clk_data = {
> + .num = RTD1625_ISO_CLK_MAX,
> + .hws = {
> + [RTD1625_ISO_CLK_EN_USB_P4] = &__clk_regmap_gate_hw(&clk_en_usb_p4),
> + [RTD1625_ISO_CLK_EN_USB_P3] = &__clk_regmap_gate_hw(&clk_en_usb_p3),
> + [RTD1625_ISO_CLK_EN_MISC_CEC0] = &__clk_regmap_gate_hw(&clk_en_misc_cec0),
> + [RTD1625_ISO_CLK_EN_CBUSRX_SYS] = &__clk_regmap_gate_hw(&clk_en_cbusrx_sys),
> + [RTD1625_ISO_CLK_EN_CBUSTX_SYS] = &__clk_regmap_gate_hw(&clk_en_cbustx_sys),
> + [RTD1625_ISO_CLK_EN_CBUS_SYS] = &__clk_regmap_gate_hw(&clk_en_cbus_sys),
> + [RTD1625_ISO_CLK_EN_CBUS_OSC] = &__clk_regmap_gate_hw(&clk_en_cbus_osc),
> + [RTD1625_ISO_CLK_EN_I2C0] = &__clk_regmap_gate_hw(&clk_en_i2c0),
> + [RTD1625_ISO_CLK_EN_I2C1] = &__clk_regmap_gate_hw(&clk_en_i2c1),
> + [RTD1625_ISO_CLK_EN_ETN_250M] = &__clk_regmap_gate_hw(&clk_en_etn_250m),
> + [RTD1625_ISO_CLK_EN_ETN_SYS] = &__clk_regmap_gate_hw(&clk_en_etn_sys),
> + [RTD1625_ISO_CLK_EN_USB_DRD] = &__clk_regmap_gate_hw(&clk_en_usb_drd),
> + [RTD1625_ISO_CLK_EN_USB_HOST] = &__clk_regmap_gate_hw(&clk_en_usb_host),
> + [RTD1625_ISO_CLK_EN_USB_U3_HOST] = &__clk_regmap_gate_hw(&clk_en_usb_u3_host),
> + [RTD1625_ISO_CLK_EN_USB] = &__clk_regmap_gate_hw(&clk_en_usb),
> + [RTD1625_ISO_CLK_EN_VTC] = &__clk_regmap_gate_hw(&clk_en_vtc),
> + [RTD1625_ISO_CLK_EN_MISC_VFD] = &__clk_regmap_gate_hw(&clk_en_misc_vfd),
> + [RTD1625_ISO_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_iso_desc = {
> + .clk_data = &rtd1625_iso_clk_data,
> + .clks = rtd1625_clk_regmap_list,
> + .num_clks = ARRAY_SIZE(rtd1625_clk_regmap_list),
> +};
> +
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_irda, 0, 0x4, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ur10, 0, 0x4, 8, 1);
> +
> +static struct clk_regmap *rtd1625_iso_s_clk_regmap_list[] = {
> + &clk_en_irda.clkr,
> + &clk_en_ur10.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_iso_s_clk_data = {
> + .num = RTD1625_ISO_S_CLK_MAX,
> + .hws = {
> + [RTD1625_ISO_S_CLK_EN_IRDA] = &__clk_regmap_gate_hw(&clk_en_irda),
> + [RTD1625_ISO_S_CLK_EN_UR10] = &__clk_regmap_gate_hw(&clk_en_ur10),
> + [RTD1625_ISO_S_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_iso_s_desc = {
> + .clk_data = &rtd1625_iso_s_clk_data,
> + .clks = rtd1625_iso_s_clk_regmap_list,
> + .num_clks = ARRAY_SIZE(rtd1625_iso_s_clk_regmap_list),
> +};
> +
> +static int rtd1625_iso_probe(struct platform_device *pdev)
> +{
> + const struct rtk_clk_desc *desc;
> +
> + desc = of_device_get_match_data(&pdev->dev);
> + if (!desc)
> + return -EINVAL;
> + return rtk_clk_probe(pdev, desc, "iso_rst");
Add newline before return.
> +}
> +
> +static const struct of_device_id rtd1625_iso_match[] = {
> + {.compatible = "realtek,rtd1625-iso-clk", .data = &rtd1625_iso_desc},
> + {.compatible = "realtek,rtd1625-iso-s-clk", .data = &rtd1625_iso_s_desc},
> + { /* sentinel */ }
> +};
> +
> +static struct platform_driver rtd1625_iso_driver = {
> + .probe = rtd1625_iso_probe,
> + .driver = {
> + .name = "rtk-rtd1625-iso-clk",
> + .of_match_table = rtd1625_iso_match,
> + },
> +};
> +
> +static int __init rtd1625_iso_init(void)
> +{
> + return platform_driver_register(&rtd1625_iso_driver);
> +}
> +subsys_initcall(rtd1625_iso_init);
> +
> +MODULE_DESCRIPTION("Realtek RTD1625 ISO Controller Driver");
> +MODULE_AUTHOR("Cheng-Yu Lee <cylee12@realtek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_CLK");
> diff --git a/drivers/reset/realtek/Makefile b/drivers/reset/realtek/Makefile
> index 8ca1fa939f10..26b3ddc75ada 100644
> --- a/drivers/reset/realtek/Makefile
> +++ b/drivers/reset/realtek/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o
> +obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o reset-rtd1625-iso.o
Some comment as the previous patch. CONFIG_RESET_RTK_COMMON is expected
to be common, right? If so, a SoC-specific driver shouldn't be listed
here.
> diff --git a/drivers/reset/realtek/reset-rtd1625-iso.c b/drivers/reset/realtek/reset-rtd1625-iso.c
> new file mode 100644
> index 000000000000..f2a0478382ae
> --- /dev/null
> +++ b/drivers/reset/realtek/reset-rtd1625-iso.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Realtek Semiconductor Corporation
> + */
> +
> +#include <dt-bindings/reset/realtek,rtd1625.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include "common.h"
> +
> +#define RTD1625_ISO_RSTN_MAX 29
> +#define RTD1625_ISO_S_RSTN_MAX 5
> +
> +static struct rtk_reset_desc rtd1625_iso_reset_descs[] = {
static const?
> + [RTD1625_ISO_RSTN_VFD] = { .ofs = 0x88, .bit = 0 },
> + [RTD1625_ISO_RSTN_CEC0] = { .ofs = 0x88, .bit = 2 },
> + [RTD1625_ISO_RSTN_CEC1] = { .ofs = 0x88, .bit = 3 },
> + [RTD1625_ISO_RSTN_CBUSTX] = { .ofs = 0x88, .bit = 5 },
> + [RTD1625_ISO_RSTN_CBUSRX] = { .ofs = 0x88, .bit = 6 },
> + [RTD1625_ISO_RSTN_USB3_PHY2_XTAL_POW] = { .ofs = 0x88, .bit = 7 },
> + [RTD1625_ISO_RSTN_UR0] = { .ofs = 0x88, .bit = 8 },
> + [RTD1625_ISO_RSTN_GMAC] = { .ofs = 0x88, .bit = 9 },
> + [RTD1625_ISO_RSTN_GPHY] = { .ofs = 0x88, .bit = 10 },
> + [RTD1625_ISO_RSTN_I2C_0] = { .ofs = 0x88, .bit = 11 },
> + [RTD1625_ISO_RSTN_I2C_1] = { .ofs = 0x88, .bit = 12 },
> + [RTD1625_ISO_RSTN_CBUS] = { .ofs = 0x88, .bit = 13 },
> + [RTD1625_ISO_RSTN_USB_DRD] = { .ofs = 0x88, .bit = 14 },
> + [RTD1625_ISO_RSTN_USB_HOST] = { .ofs = 0x88, .bit = 15 },
> + [RTD1625_ISO_RSTN_USB_PHY_0] = { .ofs = 0x88, .bit = 16 },
> + [RTD1625_ISO_RSTN_USB_PHY_1] = { .ofs = 0x88, .bit = 17 },
> + [RTD1625_ISO_RSTN_USB_PHY_2] = { .ofs = 0x88, .bit = 18 },
> + [RTD1625_ISO_RSTN_USB] = { .ofs = 0x88, .bit = 19 },
> + [RTD1625_ISO_RSTN_TYPE_C] = { .ofs = 0x88, .bit = 20 },
> + [RTD1625_ISO_RSTN_USB_U3_HOST] = { .ofs = 0x88, .bit = 21 },
> + [RTD1625_ISO_RSTN_USB3_PHY0_POW] = { .ofs = 0x88, .bit = 22 },
> + [RTD1625_ISO_RSTN_USB3_P0_MDIO] = { .ofs = 0x88, .bit = 23 },
> + [RTD1625_ISO_RSTN_USB3_PHY1_POW] = { .ofs = 0x88, .bit = 24 },
> + [RTD1625_ISO_RSTN_USB3_P1_MDIO] = { .ofs = 0x88, .bit = 25 },
> + [RTD1625_ISO_RSTN_VTC] = { .ofs = 0x88, .bit = 26 },
> + [RTD1625_ISO_RSTN_USB3_PHY2_POW] = { .ofs = 0x88, .bit = 27 },
> + [RTD1625_ISO_RSTN_USB3_P2_MDIO] = { .ofs = 0x88, .bit = 28 },
> + [RTD1625_ISO_RSTN_USB_PHY_3] = { .ofs = 0x88, .bit = 29 },
> + [RTD1625_ISO_RSTN_USB_PHY_4] = { .ofs = 0x88, .bit = 30 },
> +};
> +
> +static struct rtk_reset_desc rtd1625_iso_s_reset_descs[] = {
> + [RTD1625_ISO_S_RSTN_ISOM_MIS] = { .ofs = 0x310, .bit = 0, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_GPIOM] = { .ofs = 0x310, .bit = 2, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_TIMER7] = { .ofs = 0x310, .bit = 4, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_IRDA] = { .ofs = 0x310, .bit = 6, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_UR10] = { .ofs = 0x310, .bit = 8, .write_en = 1 },
> +};
> +
> +static int rtd1625_iso_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct device *parent = dev->parent;
> + struct rtk_reset_data *data;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + if (of_device_is_compatible(parent->of_node, "realtek,rtd1625-iso-s-clk")) {
> + data->descs = rtd1625_iso_s_reset_descs;
> + data->rcdev.nr_resets = RTD1625_ISO_S_RSTN_MAX;
> + } else {
> + data->descs = rtd1625_iso_reset_descs;
> + data->rcdev.nr_resets = RTD1625_ISO_RSTN_MAX;
> + }
> + return rtk_reset_controller_add(dev, data);
Newline before return.
> +}
> +
> +static const struct auxiliary_device_id rtd1625_iso_reset_ids[] = {
> + {
> + .name = "clk_rtk.iso_rst",
> + },
I would combine the { .name } all on one line.
Brian
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(auxiliary, rtd1625_iso_reset_ids);
> +
> +static struct auxiliary_driver rtd1625_iso_driver = {
> + .probe = rtd1625_iso_reset_probe,
> + .id_table = rtd1625_iso_reset_ids,
> + .driver = {
> + .name = "rtd1625-iso-reset",
> + },
> +};
> +module_auxiliary_driver(rtd1625_iso_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_RESET");
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v6 08/10] clk: realtek: Add RTD1625-CRT clock controller driver
From: Brian Masney @ 2026-04-03 15:24 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-9-eleanor.lin@realtek.com>
Hi Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:55PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add support for the CRT (Clock, Reset, and Test) domain clock controller
> on the Realtek RTD1625 SoC. This driver provides essential clock sources
> (including PLLs), gating, and multiplexing functionalities for the
> platform's peripherals.
>
> Since the reset controller shares the same register space with the CRT
> clock controller, it is instantiated as an auxiliary device by the core
> clock driver. This patch also includes the corresponding auxiliary reset
> driver to handle the CRT domain resets.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move struct rtk_reset_desc array from the clock driver to the dedicated reset driver.
> - Implement and register a dedicated reset auxiliary driver.
> ---
> drivers/clk/realtek/Kconfig | 13 +
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-rtd1625-crt.c | 779 ++++++++++++++++++++++
> drivers/reset/realtek/Kconfig | 2 +
> drivers/reset/realtek/Makefile | 2 +-
> drivers/reset/realtek/reset-rtd1625-crt.c | 186 ++++++
> 6 files changed, 982 insertions(+), 1 deletion(-)
> create mode 100644 drivers/clk/realtek/clk-rtd1625-crt.c
> create mode 100644 drivers/reset/realtek/reset-rtd1625-crt.c
>
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> index b31a31e57b3a..6a213cfd66bc 100644
> --- a/drivers/clk/realtek/Kconfig
> +++ b/drivers/clk/realtek/Kconfig
> @@ -28,4 +28,17 @@ config RTK_CLK_COMMON
> config RTK_CLK_PLL_MMC
> bool
>
> +config COMMON_CLK_RTD1625
> + tristate "RTD1625 Clock Controller"
> + select RTK_CLK_COMMON
> + select RTK_CLK_PLL_MMC
> + help
> + Support for the clock controller on Realtek RTD1625 SoCs.
> +
> + This driver provides clock sources, gating, multiplexing, and
> + reset control for peripherals on the RTD1625 platform.
> +
> + Say Y here if your system is based on the RTD1625 and you need
> + its peripheral devices to function.
> +
> endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index fd7d777902c8..c992f97dfbc7 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -9,3 +9,4 @@ clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
>
> clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> +obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-crt.o
> diff --git a/drivers/clk/realtek/clk-rtd1625-crt.c b/drivers/clk/realtek/clk-rtd1625-crt.c
> new file mode 100644
> index 000000000000..fcb8b08722c8
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-rtd1625-crt.c
> @@ -0,0 +1,779 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <dt-bindings/clock/realtek,rtd1625-clk.h>
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +#include "clk-regmap-gate.h"
> +#include "clk-regmap-mux.h"
> +
> +#define RTD1625_CRT_CLK_MAX 172
> +#define RTD1625_CRT_RSTN_MAX 123
> +
> +#define RTD1625_REG_PLL_ACPU1 0x10c
> +#define RTD1625_REG_PLL_ACPU2 0x110
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU0 0x5c0
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU1 0x5c4
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU2 0x5c8
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU_DBG2 0x5dc
> +
> +#define RTD1625_REG_PLL_VE1_1 0x114
> +#define RTD1625_REG_PLL_VE1_2 0x118
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_0 0x580
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_1 0x584
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_2 0x588
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_DBG2 0x59c
> +
> +#define RTD1625_REG_PLL_GPU1 0x1c0
> +#define RTD1625_REG_PLL_GPU2 0x1c4
> +#define RTD1625_REG_PLL_SSC_DIG_GPU0 0x5a0
> +#define RTD1625_REG_PLL_SSC_DIG_GPU1 0x5a4
> +#define RTD1625_REG_PLL_SSC_DIG_GPU2 0x5a8
> +#define RTD1625_REG_PLL_SSC_DIG_GPU_DBG2 0x5bc
> +
> +#define RTD1625_REG_PLL_NPU1 0x1c8
> +#define RTD1625_REG_PLL_NPU2 0x1cc
> +#define RTD1625_REG_PLL_SSC_DIG_NPU0 0x800
> +#define RTD1625_REG_PLL_SSC_DIG_NPU1 0x804
> +#define RTD1625_REG_PLL_SSC_DIG_NPU2 0x808
> +#define RTD1625_REG_PLL_SSC_DIG_NPU_DBG2 0x81c
> +
> +#define RTD1625_REG_PLL_VE2_1 0x1d0
> +#define RTD1625_REG_PLL_VE2_2 0x1d4
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_0 0x5e0
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_1 0x5e4
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_2 0x5e8
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_DBG2 0x5fc
> +
> +#define RTD1625_REG_PLL_HIFI1 0x1d8
> +#define RTD1625_REG_PLL_HIFI2 0x1dc
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI0 0x6e0
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI1 0x6e4
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI2 0x6e8
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI_DBG2 0x6fc
> +
> +#define RTD1625_REG_PLL_BUS1 0x524
> +
> +#define RTD1625_REG_PLL_SSC_DIG_DDSA1 0x564
> +
> +#define RTD1625_REG_PLL_SSC_DIG_DCSB1 0x544
> +
> +static const char * const clk_gpu_parents[] = {"pll_gpu", "clk_sys"};
> +static CLK_REGMAP_MUX(clk_gpu, clk_gpu_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x28, 12, 0x1);
> +static const char * const clk_ve_parents[] = {"pll_vo", "clk_sysh", "pll_ve1", "pll_ve2"};
> +static CLK_REGMAP_MUX(clk_ve1, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 0, 0x3);
> +static CLK_REGMAP_MUX(clk_ve2, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 3, 0x3);
> +static CLK_REGMAP_MUX(clk_ve4, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 6, 0x3);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_misc, CLK_IS_CRITICAL, 0x50, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie0, 0, 0x50, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_gspi, 0, 0x50, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_iso_misc, 0, 0x50, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sds, 0, 0x50, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmi, 0, 0x50, 14, 1);
> +static CLK_REGMAP_GATE(clk_en_gpu, "clk_gpu", CLK_SET_RATE_PARENT, 0x50, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_ve1, "clk_ve1", CLK_SET_RATE_PARENT, 0x50, 20, 1);
> +static CLK_REGMAP_GATE(clk_en_ve2, "clk_ve2", CLK_SET_RATE_PARENT, 0x50, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_se, 0, 0x50, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_md, 0, 0x54, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tp, CLK_IS_CRITICAL, 0x54, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_rcic, 0, 0x54, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_nf, 0, 0x54, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_emmc, 0, 0x54, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sd, 0, 0x54, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sdio_ip, 0, 0x54, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mipi_csi, 0, 0x54, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_emmc_ip, "pll_emmc", CLK_SET_RATE_PARENT, 0x54, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sdio, 0, 0x54, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sd_ip, 0, 0x54, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tpb, 0, 0x54, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_sc1, "clk_en_misc", 0, 0x54, 30, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_3, "clk_en_misc", 0, 0x58, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_jpeg, 0, 0x58, 4, 1);
> +static CLK_REGMAP_GATE(clk_en_acpu, "pll_acpu", CLK_SET_RATE_PARENT,
> + 0x58, 6, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_sc0, "clk_en_misc", 0, 0x58, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmirx, 0, 0x58, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hse, CLK_IS_CRITICAL, 0x58, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_fan, 0, 0x5c, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_wrap_sys, 0, 0x5c, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_wrap_sysh, 0, 0x5c, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_mac_sysh, 0, 0x5c, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_r2rdsc, 0, 0x5c, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie1, 0, 0x5c, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_4, "clk_en_misc", 0, 0x5c, 20, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_5, "clk_en_misc", 0, 0x5c, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tsio, 0, 0x5c, 24, 1);
> +static CLK_REGMAP_GATE(clk_en_ve4, "clk_ve4", CLK_SET_RATE_PARENT,
> + 0x5c, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_edp, 0, 0x5c, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tsio_trx, 0, 0x5c, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie2, 0, 0x8c, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_earc, 0, 0x8c, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lite, 0, 0x8c, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mipi_dsi, 0, 0x8c, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npupp, 0, 0x8c, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npu, 0, 0x8c, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu0, 0, 0x8c, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu1, 0, 0x8c, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_nsram, 0, 0x8c, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmitop, 0, 0x8c, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu_iso_npu, 0, 0x8c, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_keyladder, 0, 0x8c, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ifcp_klm, 0, 0x8c, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ifcp, 0, 0x8c, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_genpw, 0, 0xb0, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_chip, 0, 0xb0, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_ip, 0, 0xb0, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdlm2m, 0, 0xb0, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_xtal, 0, 0xb0, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_test_mux, 0, 0xb0, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_dla, 0, 0xb0, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tpcw, 0, 0xb0, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_gpu_ts_src, 0, 0xb0, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_vi, 0, 0xb0, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lvds1, 0, 0xb0, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lvds2, 0, 0xb0, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu, 0, 0xb0, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_ur1, "clk_en_ur_top", 0, 0x884, 0, 1);
> +static CLK_REGMAP_GATE(clk_en_ur2, "clk_en_ur_top", 0, 0x884, 2, 1);
> +static CLK_REGMAP_GATE(clk_en_ur3, "clk_en_ur_top", 0, 0x884, 4, 1);
> +static CLK_REGMAP_GATE(clk_en_ur4, "clk_en_ur_top", 0, 0x884, 6, 1);
> +static CLK_REGMAP_GATE(clk_en_ur5, "clk_en_ur_top", 0, 0x884, 8, 1);
> +static CLK_REGMAP_GATE(clk_en_ur6, "clk_en_ur_top", 0, 0x884, 10, 1);
> +static CLK_REGMAP_GATE(clk_en_ur7, "clk_en_ur_top", 0, 0x884, 12, 1);
> +static CLK_REGMAP_GATE(clk_en_ur8, "clk_en_ur_top", 0, 0x884, 14, 1);
> +static CLK_REGMAP_GATE(clk_en_ur9, "clk_en_ur_top", 0, 0x884, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ur_top, CLK_IS_CRITICAL, 0x884, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_7, "clk_en_misc", 0, 0x884, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_6, "clk_en_misc", 0, 0x884, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi0, 0, 0x894, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi1, 0, 0x894, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi2, 0, 0x894, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lsadc0, 0, 0x894, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lsadc1, 0, 0x894, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_isomis_dma, 0, 0x894, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_dptx, 0, 0x894, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npu_mipi_csi, 0, 0x894, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_edptx, 0, 0x894, 28, 1);
> +
> +#define FREQ_NF_MASK 0x7ffff
> +#define FREQ_NF(_r, _nf) {.rate = _r, .val = (_nf),}
> +
> +static const struct freq_table acpu_tbl[] = {
> + FREQ_NF(513000000, 0x11000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table ve_tbl[] = {
> + FREQ_NF(553500000, 0x12800),
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(688500000, 0x17800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table bus_tbl[] = {
> + FREQ_NF(513000000, 0x11000),
> + FREQ_NF(540000000, 0x12000),
> + FREQ_NF(553500000, 0x12800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table ddsa_tbl[] = {
> + FREQ_NF(432000000, 0xe000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table gpu_tbl[] = {
> + FREQ_NF(405000000, 0xd000),
> + FREQ_NF(540000000, 0x12000),
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(729000000, 0x19000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_NF(850500000, 0x1d800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table hifi_tbl[] = {
> + FREQ_NF(756000000, 0x1a000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table npu_tbl[] = {
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(729000000, 0x19000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_power_on[] = {
> + {RTD1625_REG_PLL_ACPU2, 0x5},
> + {RTD1625_REG_PLL_ACPU2, 0x7},
> + {RTD1625_REG_PLL_ACPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU2, 0x1e1f8e},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x5, 200},
> + {RTD1625_REG_PLL_ACPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_power_off[] = {
> + {RTD1625_REG_PLL_ACPU2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_acpu = {
static const?
> + .clkr.hw.init = CLK_HW_INIT("pll_acpu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_acpu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_acpu_seq_power_on),
> + .seq_power_off = pll_acpu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_acpu_seq_power_off),
> + .seq_pre_set_freq = pll_acpu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_acpu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_acpu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_acpu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_ACPU1,
> + .freq_tbl = acpu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_ACPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_ACPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_power_on[] = {
> + {RTD1625_REG_PLL_VE1_2, 0x5},
> + {RTD1625_REG_PLL_VE1_2, 0x7},
> + {RTD1625_REG_PLL_VE1_1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x5, 200},
> + {RTD1625_REG_PLL_VE1_2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_power_off[] = {
> + {RTD1625_REG_PLL_VE1_2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x5},
> +};
> +
> +static struct clk_pll pll_ve1 = {
Same here about static const, plus some others below?
> + .clkr.hw.init = CLK_HW_INIT("pll_ve1", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_ve1_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_ve1_seq_power_on),
> + .seq_power_off = pll_ve1_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_ve1_seq_power_off),
> + .seq_pre_set_freq = pll_ve1_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_ve1_seq_pre_set_freq),
> + .seq_post_set_freq = pll_ve1_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_ve1_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_VE1_1,
> + .freq_tbl = ve_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_VE1_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_VE1_2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static struct clk_pll pll_ddsa = {
> + .clkr.hw.init = CLK_HW_INIT("pll_ddsa", "osc27m", &rtk_clk_pll_ro_ops,
> + CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_DDSA1,
> + .freq_tbl = ddsa_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static struct clk_pll pll_bus = {
> + .clkr.hw.init = CLK_HW_INIT("pll_bus", "osc27m", &rtk_clk_pll_ro_ops, CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_BUS1,
> + .freq_tbl = bus_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_sys, "clk_sys", "pll_bus", 2, 1, 0);
> +
> +static struct clk_pll pll_dcsb = {
> + .clkr.hw.init = CLK_HW_INIT("pll_dcsb", "osc27m", &rtk_clk_pll_ro_ops,
> + CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_DCSB1,
> + .freq_tbl = bus_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_sysh, "clk_sysh", "pll_dcsb", 1, 1, 0);
> +
> +static const struct reg_sequence pll_gpu_seq_power_on[] = {
> + {RTD1625_REG_PLL_GPU2, 0x5},
> + {RTD1625_REG_PLL_GPU2, 0x7},
> + {RTD1625_REG_PLL_GPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x5, 200},
> + {RTD1625_REG_PLL_GPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_power_off[] = {
> + {RTD1625_REG_PLL_GPU2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_gpu = {
> + .clkr.hw.init = CLK_HW_INIT("pll_gpu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_gpu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_gpu_seq_power_on),
> + .seq_power_off = pll_gpu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_gpu_seq_power_off),
> + .seq_pre_set_freq = pll_gpu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_gpu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_gpu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_gpu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_GPU1,
> + .freq_tbl = gpu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_GPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_GPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_npu_seq_power_on[] = {
> + {RTD1625_REG_PLL_NPU2, 0x5},
> + {RTD1625_REG_PLL_NPU2, 0x7},
> + {RTD1625_REG_PLL_NPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x5, 200},
> + {RTD1625_REG_PLL_NPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_power_off[] = {
> + {RTD1625_REG_PLL_NPU2, 0x4},
> + {RTD1625_REG_PLL_NPU1, 0x54010},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_npu = {
> + .clkr.hw.init = CLK_HW_INIT("pll_npu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_npu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_npu_seq_power_on),
> + .seq_power_off = pll_npu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_npu_seq_power_off),
> + .seq_pre_set_freq = pll_npu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_npu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_npu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_npu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_NPU1,
> + .freq_tbl = npu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_NPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_NPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_npu, "clk_npu", "pll_npu", 1, 1, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR(clk_npu_mipi_csi, "clk_npu_mipi_csi", "pll_npu", 1, 1,
> + CLK_SET_RATE_PARENT);
> +
> +static const struct reg_sequence pll_ve2_seq_power_on[] = {
> + {RTD1625_REG_PLL_VE2_2, 0x5},
> + {RTD1625_REG_PLL_VE2_2, 0x7},
> + {RTD1625_REG_PLL_VE2_1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x5, 200},
> + {RTD1625_REG_PLL_VE2_2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_power_off[] = {
> + {RTD1625_REG_PLL_VE2_2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x5},
> +};
> +
> +static struct clk_pll pll_ve2 = {
> + .clkr.hw.init = CLK_HW_INIT("pll_ve2", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_ve2_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_ve2_seq_power_on),
> + .seq_power_off = pll_ve2_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_ve2_seq_power_off),
> + .seq_pre_set_freq = pll_ve2_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_ve2_seq_pre_set_freq),
> + .seq_post_set_freq = pll_ve2_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_ve2_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_VE2_1,
> + .freq_tbl = ve_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_VE2_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_VE2_2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_power_on[] = {
> + {RTD1625_REG_PLL_HIFI2, 0x5},
> + {RTD1625_REG_PLL_HIFI2, 0x7},
> + {RTD1625_REG_PLL_HIFI1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x5, 200},
> + {RTD1625_REG_PLL_HIFI2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_power_off[] = {
> + {RTD1625_REG_PLL_HIFI2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x5},
> +};
> +
> +static struct clk_pll pll_hifi = {
> + .clkr.hw.init = CLK_HW_INIT("pll_hifi", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_hifi_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_hifi_seq_power_on),
> + .seq_power_off = pll_hifi_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_hifi_seq_power_off),
> + .seq_pre_set_freq = pll_hifi_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_hifi_seq_pre_set_freq),
> + .seq_post_set_freq = pll_hifi_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_hifi_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_HIFI1,
> + .freq_tbl = hifi_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_HIFI_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_HIFI2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static CLK_FIXED_FACTOR(pll_emmc_ref, "pll_emmc_ref", "osc27m", 1, 1, 0);
> +
> +static struct clk_pll_mmc pll_emmc = {
> + .pll_ofs = 0x1f0,
> + .ssc_dig_ofs = 0x6b0,
> + .clkr.hw.init = CLK_HW_INIT("pll_emmc", "pll_emmc_ref", &rtk_clk_pll_mmc_ops, 0),
> + .phase0_hw.init = CLK_HW_INIT("pll_emmc_vp0", "pll_emmc", &rtk_clk_pll_mmc_phase_ops, 0),
> + .phase1_hw.init = CLK_HW_INIT("pll_emmc_vp1", "pll_emmc", &rtk_clk_pll_mmc_phase_ops, 0),
> +};
> +
> +static struct clk_regmap *rtd1625_crt_regmap_clks[] = {
> + &clk_en_misc.clkr,
> + &clk_en_pcie0.clkr,
> + &clk_en_gspi.clkr,
> + &clk_en_iso_misc.clkr,
> + &clk_en_sds.clkr,
> + &clk_en_hdmi.clkr,
> + &clk_en_gpu.clkr,
> + &clk_en_ve1.clkr,
> + &clk_en_ve2.clkr,
> + &clk_en_se.clkr,
> + &clk_en_md.clkr,
> + &clk_en_tp.clkr,
> + &clk_en_rcic.clkr,
> + &clk_en_nf.clkr,
> + &clk_en_emmc.clkr,
> + &clk_en_sd.clkr,
> + &clk_en_sdio_ip.clkr,
> + &clk_en_mipi_csi.clkr,
> + &clk_en_emmc_ip.clkr,
> + &clk_en_sdio.clkr,
> + &clk_en_sd_ip.clkr,
> + &clk_en_tpb.clkr,
> + &clk_en_misc_sc1.clkr,
> + &clk_en_misc_i2c_3.clkr,
> + &clk_en_jpeg.clkr,
> + &clk_en_acpu.clkr,
> + &clk_en_misc_sc0.clkr,
> + &clk_en_hdmirx.clkr,
> + &clk_en_hse.clkr,
> + &clk_en_fan.clkr,
> + &clk_en_sata_wrap_sys.clkr,
> + &clk_en_sata_wrap_sysh.clkr,
> + &clk_en_sata_mac_sysh.clkr,
> + &clk_en_r2rdsc.clkr,
> + &clk_en_pcie1.clkr,
> + &clk_en_misc_i2c_4.clkr,
> + &clk_en_misc_i2c_5.clkr,
> + &clk_en_tsio.clkr,
> + &clk_en_ve4.clkr,
> + &clk_en_edp.clkr,
> + &clk_en_tsio_trx.clkr,
> + &clk_en_pcie2.clkr,
> + &clk_en_earc.clkr,
> + &clk_en_lite.clkr,
> + &clk_en_mipi_dsi.clkr,
> + &clk_en_npupp.clkr,
> + &clk_en_npu.clkr,
> + &clk_en_aucpu0.clkr,
> + &clk_en_aucpu1.clkr,
> + &clk_en_nsram.clkr,
> + &clk_en_hdmitop.clkr,
> + &clk_en_aucpu_iso_npu.clkr,
> + &clk_en_keyladder.clkr,
> + &clk_en_ifcp_klm.clkr,
> + &clk_en_ifcp.clkr,
> + &clk_en_mdl_genpw.clkr,
> + &clk_en_mdl_chip.clkr,
> + &clk_en_mdl_ip.clkr,
> + &clk_en_mdlm2m.clkr,
> + &clk_en_mdl_xtal.clkr,
> + &clk_en_test_mux.clkr,
> + &clk_en_dla.clkr,
> + &clk_en_tpcw.clkr,
> + &clk_en_gpu_ts_src.clkr,
> + &clk_en_vi.clkr,
> + &clk_en_lvds1.clkr,
> + &clk_en_lvds2.clkr,
> + &clk_en_aucpu.clkr,
> + &clk_en_ur1.clkr,
> + &clk_en_ur2.clkr,
> + &clk_en_ur3.clkr,
> + &clk_en_ur4.clkr,
> + &clk_en_ur5.clkr,
> + &clk_en_ur6.clkr,
> + &clk_en_ur7.clkr,
> + &clk_en_ur8.clkr,
> + &clk_en_ur9.clkr,
> + &clk_en_ur_top.clkr,
> + &clk_en_misc_i2c_7.clkr,
> + &clk_en_misc_i2c_6.clkr,
> + &clk_en_spi0.clkr,
> + &clk_en_spi1.clkr,
> + &clk_en_spi2.clkr,
> + &clk_en_lsadc0.clkr,
> + &clk_en_lsadc1.clkr,
> + &clk_en_isomis_dma.clkr,
> + &clk_en_dptx.clkr,
> + &clk_en_npu_mipi_csi.clkr,
> + &clk_en_edptx.clkr,
> + &clk_gpu.clkr,
> + &clk_ve1.clkr,
> + &clk_ve2.clkr,
> + &clk_ve4.clkr,
> + &pll_ve1.clkr,
> + &pll_ddsa.clkr,
> + &pll_bus.clkr,
> + &pll_dcsb.clkr,
> + &pll_gpu.clkr,
> + &pll_npu.clkr,
> + &pll_ve2.clkr,
> + &pll_hifi.clkr,
> + &pll_emmc.clkr,
> + &pll_acpu.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_crt_hw_data = {
> + .num = RTD1625_CRT_CLK_MAX,
> + .hws = {
> + [RTD1625_CRT_CLK_EN_MISC] = &__clk_regmap_gate_hw(&clk_en_misc),
> + [RTD1625_CRT_CLK_EN_PCIE0] = &__clk_regmap_gate_hw(&clk_en_pcie0),
> + [RTD1625_CRT_CLK_EN_GSPI] = &__clk_regmap_gate_hw(&clk_en_gspi),
> + [RTD1625_CRT_CLK_EN_ISO_MISC] = &__clk_regmap_gate_hw(&clk_en_iso_misc),
> + [RTD1625_CRT_CLK_EN_SDS] = &__clk_regmap_gate_hw(&clk_en_sds),
> + [RTD1625_CRT_CLK_EN_HDMI] = &__clk_regmap_gate_hw(&clk_en_hdmi),
> + [RTD1625_CRT_CLK_EN_GPU] = &__clk_regmap_gate_hw(&clk_en_gpu),
> + [RTD1625_CRT_CLK_EN_VE1] = &__clk_regmap_gate_hw(&clk_en_ve1),
> + [RTD1625_CRT_CLK_EN_VE2] = &__clk_regmap_gate_hw(&clk_en_ve2),
> + [RTD1625_CRT_CLK_EN_MD] = &__clk_regmap_gate_hw(&clk_en_md),
> + [RTD1625_CRT_CLK_EN_TP] = &__clk_regmap_gate_hw(&clk_en_tp),
> + [RTD1625_CRT_CLK_EN_RCIC] = &__clk_regmap_gate_hw(&clk_en_rcic),
> + [RTD1625_CRT_CLK_EN_NF] = &__clk_regmap_gate_hw(&clk_en_nf),
> + [RTD1625_CRT_CLK_EN_EMMC] = &__clk_regmap_gate_hw(&clk_en_emmc),
> + [RTD1625_CRT_CLK_EN_SD] = &__clk_regmap_gate_hw(&clk_en_sd),
> + [RTD1625_CRT_CLK_EN_SDIO_IP] = &__clk_regmap_gate_hw(&clk_en_sdio_ip),
> + [RTD1625_CRT_CLK_EN_MIPI_CSI] = &__clk_regmap_gate_hw(&clk_en_mipi_csi),
> + [RTD1625_CRT_CLK_EN_EMMC_IP] = &__clk_regmap_gate_hw(&clk_en_emmc_ip),
> + [RTD1625_CRT_CLK_EN_SDIO] = &__clk_regmap_gate_hw(&clk_en_sdio),
> + [RTD1625_CRT_CLK_EN_SD_IP] = &__clk_regmap_gate_hw(&clk_en_sd_ip),
> + [RTD1625_CRT_CLK_EN_TPB] = &__clk_regmap_gate_hw(&clk_en_tpb),
> + [RTD1625_CRT_CLK_EN_MISC_SC1] = &__clk_regmap_gate_hw(&clk_en_misc_sc1),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_3] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_3),
> + [RTD1625_CRT_CLK_EN_ACPU] = &__clk_regmap_gate_hw(&clk_en_acpu),
> + [RTD1625_CRT_CLK_EN_JPEG] = &__clk_regmap_gate_hw(&clk_en_jpeg),
> + [RTD1625_CRT_CLK_EN_MISC_SC0] = &__clk_regmap_gate_hw(&clk_en_misc_sc0),
> + [RTD1625_CRT_CLK_EN_HDMIRX] = &__clk_regmap_gate_hw(&clk_en_hdmirx),
> + [RTD1625_CRT_CLK_EN_HSE] = &__clk_regmap_gate_hw(&clk_en_hse),
> + [RTD1625_CRT_CLK_EN_FAN] = &__clk_regmap_gate_hw(&clk_en_fan),
> + [RTD1625_CRT_CLK_EN_SATA_WRAP_SYS] = &__clk_regmap_gate_hw(&clk_en_sata_wrap_sys),
> + [RTD1625_CRT_CLK_EN_SATA_WRAP_SYSH] = &__clk_regmap_gate_hw(&clk_en_sata_wrap_sysh),
> + [RTD1625_CRT_CLK_EN_SATA_MAC_SYSH] = &__clk_regmap_gate_hw(&clk_en_sata_mac_sysh),
> + [RTD1625_CRT_CLK_EN_R2RDSC] = &__clk_regmap_gate_hw(&clk_en_r2rdsc),
> + [RTD1625_CRT_CLK_EN_PCIE1] = &__clk_regmap_gate_hw(&clk_en_pcie1),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_4] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_4),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_5] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_5),
> + [RTD1625_CRT_CLK_EN_TSIO] = &__clk_regmap_gate_hw(&clk_en_tsio),
> + [RTD1625_CRT_CLK_EN_VE4] = &__clk_regmap_gate_hw(&clk_en_ve4),
> + [RTD1625_CRT_CLK_EN_EDP] = &__clk_regmap_gate_hw(&clk_en_edp),
> + [RTD1625_CRT_CLK_EN_TSIO_TRX] = &__clk_regmap_gate_hw(&clk_en_tsio_trx),
> + [RTD1625_CRT_CLK_EN_PCIE2] = &__clk_regmap_gate_hw(&clk_en_pcie2),
> + [RTD1625_CRT_CLK_EN_EARC] = &__clk_regmap_gate_hw(&clk_en_earc),
> + [RTD1625_CRT_CLK_EN_LITE] = &__clk_regmap_gate_hw(&clk_en_lite),
> + [RTD1625_CRT_CLK_EN_MIPI_DSI] = &__clk_regmap_gate_hw(&clk_en_mipi_dsi),
> + [RTD1625_CRT_CLK_EN_NPUPP] = &__clk_regmap_gate_hw(&clk_en_npupp),
> + [RTD1625_CRT_CLK_EN_NPU] = &__clk_regmap_gate_hw(&clk_en_npu),
> + [RTD1625_CRT_CLK_EN_AUCPU0] = &__clk_regmap_gate_hw(&clk_en_aucpu0),
> + [RTD1625_CRT_CLK_EN_AUCPU1] = &__clk_regmap_gate_hw(&clk_en_aucpu1),
> + [RTD1625_CRT_CLK_EN_NSRAM] = &__clk_regmap_gate_hw(&clk_en_nsram),
> + [RTD1625_CRT_CLK_EN_HDMITOP] = &__clk_regmap_gate_hw(&clk_en_hdmitop),
> + [RTD1625_CRT_CLK_EN_AUCPU_ISO_NPU] = &__clk_regmap_gate_hw(&clk_en_aucpu_iso_npu),
> + [RTD1625_CRT_CLK_EN_KEYLADDER] = &__clk_regmap_gate_hw(&clk_en_keyladder),
> + [RTD1625_CRT_CLK_EN_IFCP_KLM] = &__clk_regmap_gate_hw(&clk_en_ifcp_klm),
> + [RTD1625_CRT_CLK_EN_IFCP] = &__clk_regmap_gate_hw(&clk_en_ifcp),
> + [RTD1625_CRT_CLK_EN_MDL_GENPW] = &__clk_regmap_gate_hw(&clk_en_mdl_genpw),
> + [RTD1625_CRT_CLK_EN_MDL_CHIP] = &__clk_regmap_gate_hw(&clk_en_mdl_chip),
> + [RTD1625_CRT_CLK_EN_MDL_IP] = &__clk_regmap_gate_hw(&clk_en_mdl_ip),
> + [RTD1625_CRT_CLK_EN_MDLM2M] = &__clk_regmap_gate_hw(&clk_en_mdlm2m),
> + [RTD1625_CRT_CLK_EN_MDL_XTAL] = &__clk_regmap_gate_hw(&clk_en_mdl_xtal),
> + [RTD1625_CRT_CLK_EN_TEST_MUX] = &__clk_regmap_gate_hw(&clk_en_test_mux),
> + [RTD1625_CRT_CLK_EN_DLA] = &__clk_regmap_gate_hw(&clk_en_dla),
> + [RTD1625_CRT_CLK_EN_TPCW] = &__clk_regmap_gate_hw(&clk_en_tpcw),
> + [RTD1625_CRT_CLK_EN_GPU_TS_SRC] = &__clk_regmap_gate_hw(&clk_en_gpu_ts_src),
> + [RTD1625_CRT_CLK_EN_VI] = &__clk_regmap_gate_hw(&clk_en_vi),
> + [RTD1625_CRT_CLK_EN_LVDS1] = &__clk_regmap_gate_hw(&clk_en_lvds1),
> + [RTD1625_CRT_CLK_EN_LVDS2] = &__clk_regmap_gate_hw(&clk_en_lvds2),
> + [RTD1625_CRT_CLK_EN_AUCPU] = &__clk_regmap_gate_hw(&clk_en_aucpu),
> + [RTD1625_CRT_CLK_EN_UR1] = &__clk_regmap_gate_hw(&clk_en_ur1),
> + [RTD1625_CRT_CLK_EN_UR2] = &__clk_regmap_gate_hw(&clk_en_ur2),
> + [RTD1625_CRT_CLK_EN_UR3] = &__clk_regmap_gate_hw(&clk_en_ur3),
> + [RTD1625_CRT_CLK_EN_UR4] = &__clk_regmap_gate_hw(&clk_en_ur4),
> + [RTD1625_CRT_CLK_EN_UR5] = &__clk_regmap_gate_hw(&clk_en_ur5),
> + [RTD1625_CRT_CLK_EN_UR6] = &__clk_regmap_gate_hw(&clk_en_ur6),
> + [RTD1625_CRT_CLK_EN_UR7] = &__clk_regmap_gate_hw(&clk_en_ur7),
> + [RTD1625_CRT_CLK_EN_UR8] = &__clk_regmap_gate_hw(&clk_en_ur8),
> + [RTD1625_CRT_CLK_EN_UR9] = &__clk_regmap_gate_hw(&clk_en_ur9),
> + [RTD1625_CRT_CLK_EN_UR_TOP] = &__clk_regmap_gate_hw(&clk_en_ur_top),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_7] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_7),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_6] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_6),
> + [RTD1625_CRT_CLK_EN_SPI0] = &__clk_regmap_gate_hw(&clk_en_spi0),
> + [RTD1625_CRT_CLK_EN_SPI1] = &__clk_regmap_gate_hw(&clk_en_spi1),
> + [RTD1625_CRT_CLK_EN_SPI2] = &__clk_regmap_gate_hw(&clk_en_spi2),
> + [RTD1625_CRT_CLK_EN_LSADC0] = &__clk_regmap_gate_hw(&clk_en_lsadc0),
> + [RTD1625_CRT_CLK_EN_LSADC1] = &__clk_regmap_gate_hw(&clk_en_lsadc1),
> + [RTD1625_CRT_CLK_EN_ISOMIS_DMA] = &__clk_regmap_gate_hw(&clk_en_isomis_dma),
> + [RTD1625_CRT_CLK_EN_DPTX] = &__clk_regmap_gate_hw(&clk_en_dptx),
> + [RTD1625_CRT_CLK_EN_NPU_MIPI_CSI] = &__clk_regmap_gate_hw(&clk_en_npu_mipi_csi),
> + [RTD1625_CRT_CLK_EN_EDPTX] = &__clk_regmap_gate_hw(&clk_en_edptx),
> + [RTD1625_CRT_CLK_GPU] = &__clk_regmap_mux_hw(&clk_gpu),
> + [RTD1625_CRT_CLK_VE1] = &__clk_regmap_mux_hw(&clk_ve1),
> + [RTD1625_CRT_CLK_VE2] = &__clk_regmap_mux_hw(&clk_ve2),
> + [RTD1625_CRT_CLK_VE4] = &__clk_regmap_mux_hw(&clk_ve4),
> + [RTD1625_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1),
> + [RTD1625_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa),
> + [RTD1625_CRT_PLL_BUS] = &__clk_pll_hw(&pll_bus),
> + [RTD1625_CRT_CLK_SYS] = &clk_sys.hw,
> + [RTD1625_CRT_PLL_DCSB] = &__clk_pll_hw(&pll_dcsb),
> + [RTD1625_CRT_CLK_SYSH] = &clk_sysh.hw,
> + [RTD1625_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu),
> + [RTD1625_CRT_PLL_NPU] = &__clk_pll_hw(&pll_npu),
> + [RTD1625_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2),
> + [RTD1625_CRT_PLL_HIFI] = &__clk_pll_hw(&pll_hifi),
> + [RTD1625_CRT_PLL_EMMC_REF] = &pll_emmc_ref.hw,
> + [RTD1625_CRT_PLL_EMMC] = &__clk_pll_mmc_hw(&pll_emmc),
> + [RTD1625_CRT_PLL_EMMC_VP0] = &pll_emmc.phase0_hw,
> + [RTD1625_CRT_PLL_EMMC_VP1] = &pll_emmc.phase1_hw,
> + [RTD1625_CRT_PLL_ACPU] = &__clk_pll_hw(&pll_acpu),
> + [RTD1625_CRT_CLK_NPU] = &clk_npu.hw,
> + [RTD1625_CRT_CLK_NPU_MIPI_CSI] = &clk_npu_mipi_csi.hw,
> +
> + [RTD1625_CRT_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_crt_desc = {
> + .clk_data = &rtd1625_crt_hw_data,
> + .clks = rtd1625_crt_regmap_clks,
> + .num_clks = ARRAY_SIZE(rtd1625_crt_regmap_clks),
> +};
> +
> +static int rtd1625_crt_probe(struct platform_device *pdev)
> +{
> + const struct rtk_clk_desc *desc;
> +
> + desc = of_device_get_match_data(&pdev->dev);
> + if (!desc)
> + return -EINVAL;
> +
> + return rtk_clk_probe(pdev, desc, "crt_rst");
> +}
> +
> +static const struct of_device_id rtd1625_crt_match[] = {
> + {.compatible = "realtek,rtd1625-crt-clk", .data = &rtd1625_crt_desc,},
> + {/* sentinel */}
Add a space around the comment like so:
{ /* sentinel */ }
> +};
> +
> +static struct platform_driver rtd1625_crt_driver = {
> + .probe = rtd1625_crt_probe,
> + .driver = {
> + .name = "rtk-rtd1625-crt-clk",
> + .of_match_table = rtd1625_crt_match,
> + },
> +};
> +
> +static int __init rtd1625_crt_init(void)
> +{
> + return platform_driver_register(&rtd1625_crt_driver);
> +}
> +subsys_initcall(rtd1625_crt_init);
> +
> +MODULE_DESCRIPTION("Reatek RTD1625 CRT Controller Driver");
s/Reatek/Realtex/
> +MODULE_AUTHOR("Cheng-Yu Lee <cylee12@realtek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_CLK");
> diff --git a/drivers/reset/realtek/Kconfig b/drivers/reset/realtek/Kconfig
> index 99a14d355803..a44c7834191c 100644
> --- a/drivers/reset/realtek/Kconfig
> +++ b/drivers/reset/realtek/Kconfig
> @@ -1,3 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0-only
> config RESET_RTK_COMMON
> bool
> + select AUXILIARY_BUS
> + default COMMON_CLK_RTD1625
> diff --git a/drivers/reset/realtek/Makefile b/drivers/reset/realtek/Makefile
> index b59a3f7f2453..8ca1fa939f10 100644
> --- a/drivers/reset/realtek/Makefile
> +++ b/drivers/reset/realtek/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_RESET_RTK_COMMON) += common.o
> +obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o
CONFIG_RESET_RTK_COMMON is supposed to be common, right? If so, the
SoC-specific driver shouldn't be included here.
> diff --git a/drivers/reset/realtek/reset-rtd1625-crt.c b/drivers/reset/realtek/reset-rtd1625-crt.c
> new file mode 100644
> index 000000000000..ebb15bb68885
> --- /dev/null
> +++ b/drivers/reset/realtek/reset-rtd1625-crt.c
> @@ -0,0 +1,186 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Realtek Semiconductor Corporation
> + */
> +
> +#include <dt-bindings/reset/realtek,rtd1625.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include "common.h"
> +
> +#define RTD1625_CRT_RSTN_MAX 123
> +
> +static struct rtk_reset_desc rtd1625_crt_reset_descs[] = {
> + /* Bank 0: offset 0x0 */
> + [RTD1625_CRT_RSTN_MISC] = { .ofs = 0x0, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DIP] = { .ofs = 0x0, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GSPI] = { .ofs = 0x0, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS] = { .ofs = 0x0, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS_REG] = { .ofs = 0x0, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS_PHY] = { .ofs = 0x0, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GPU2D] = { .ofs = 0x0, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DC_PHY] = { .ofs = 0x0, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_CRT] = { .ofs = 0x0, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC] = { .ofs = 0x0, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SE] = { .ofs = 0x0, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DLA] = { .ofs = 0x0, .bit = 30, .write_en = 1 },
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Can this cause undefined behavior during reset mask computation?
Several reset array entries set .bit = 30 and .write_en = 1. In
rtk_reset_assert() and rtk_reset_deassert(), if the bitmask is computed as
0x3 << desc->bit, 0x3 is a signed 32-bit integer literal. Left-shifting it by
30 results in 0xC0000000, which exceeds the maximum positive value for a
signed 32-bit integer.
Modifying the sign bit via left-shift on a signed type invokes undefined
behavior in C. Would an unsigned literal (e.g., 0x3U << desc->bit) be needed
to safely construct the mask?
> + /* Bank 1: offset 0x4 */
> + [RTD1625_CRT_RSTN_JPEG] = { .ofs = 0x4, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SD] = { .ofs = 0x4, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDIO] = { .ofs = 0x4, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCR_CNT] = { .ofs = 0x4, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_STITCH] = { .ofs = 0x4, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_PHY] = { .ofs = 0x4, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0] = { .ofs = 0x4, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_CORE] = { .ofs = 0x4, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_POWER] = { .ofs = 0x4, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_NONSTICH] = { .ofs = 0x4, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_PHY_MDIO] = { .ofs = 0x4, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_SGMII_MDIO] = { .ofs = 0x4, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VO2] = { .ofs = 0x4, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MISC_SC0] = { .ofs = 0x4, .bit = 30, .write_en = 1 },
> + /* Bank 2: offset 0x8 */
> + [RTD1625_CRT_RSTN_MD] = { .ofs = 0x8, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LVDS1] = { .ofs = 0x8, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LVDS2] = { .ofs = 0x8, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MISC_SC1] = { .ofs = 0x8, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_3] = { .ofs = 0x8, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_FAN] = { .ofs = 0x8, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TVE] = { .ofs = 0x8, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AIO] = { .ofs = 0x8, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VO] = { .ofs = 0x8, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MIPI_CSI] = { .ofs = 0x8, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMIRX] = { .ofs = 0x8, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMIRX_WRAP] = { .ofs = 0x8, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMI] = { .ofs = 0x8, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DISP] = { .ofs = 0x8, .bit = 30, .write_en = 1 },
> + /* Bank 3: offset 0xc */
> + [RTD1625_CRT_RSTN_SATA_PHY_POW1] = { .ofs = 0xc, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_PHY_POW0] = { .ofs = 0xc, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MDIO1] = { .ofs = 0xc, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MDIO0] = { .ofs = 0xc, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_WRAP] = { .ofs = 0xc, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_P1] = { .ofs = 0xc, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_P0] = { .ofs = 0xc, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_COM] = { .ofs = 0xc, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_STITCH] = { .ofs = 0xc, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_PHY] = { .ofs = 0xc, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1] = { .ofs = 0xc, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_CORE] = { .ofs = 0xc, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_POWER] = { .ofs = 0xc, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_NONSTICH] = { .ofs = 0xc, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_PHY_MDIO] = { .ofs = 0xc, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMITOP] = { .ofs = 0xc, .bit = 30, .write_en = 1 },
> + /* Bank 4: offset 0x68 */
> + [RTD1625_CRT_RSTN_I2C_4] = { .ofs = 0x68, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_5] = { .ofs = 0x68, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TSIO] = { .ofs = 0x68, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VI] = { .ofs = 0x68, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EDP] = { .ofs = 0x68, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_MMU] = { .ofs = 0x68, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_MMU_FUNC] = { .ofs = 0x68, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HSE_MMU] = { .ofs = 0x68, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HSE_MMU_FUNC] = { .ofs = 0x68, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDLM2M] = { .ofs = 0x68, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_ISO_GSPI] = { .ofs = 0x68, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SOFT_NPU] = { .ofs = 0x68, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI2EMMC] = { .ofs = 0x68, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EARC] = { .ofs = 0x68, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1] = { .ofs = 0x68, .bit = 30, .write_en = 1 },
> + /* Bank 5: offset 0x90 */
> + [RTD1625_CRT_RSTN_PCIE2_STITCH] = { .ofs = 0x90, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_PHY] = { .ofs = 0x90, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2] = { .ofs = 0x90, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_CORE] = { .ofs = 0x90, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_POWER] = { .ofs = 0x90, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_NONSTICH] = { .ofs = 0x90, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_PHY_MDIO] = { .ofs = 0x90, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_UMCTL2] = { .ofs = 0x90, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MIPI_DSI] = { .ofs = 0x90, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HIFM] = { .ofs = 0x90, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_NSRAM] = { .ofs = 0x90, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUCPU0_REG] = { .ofs = 0x90, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_GENPW] = { .ofs = 0x90, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_CHIP] = { .ofs = 0x90, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_IP] = { .ofs = 0x90, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TEST_MUX] = { .ofs = 0x90, .bit = 30, .write_en = 1 },
> + /* Bank 6: offset 0xb8 */
> + [RTD1625_CRT_RSTN_ISO_BIST] = { .ofs = 0xb8, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MAIN_BIST] = { .ofs = 0xb8, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MAIN2_BIST] = { .ofs = 0xb8, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_BIST] = { .ofs = 0xb8, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE2_BIST] = { .ofs = 0xb8, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_BIST] = { .ofs = 0xb8, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GPU_BIST] = { .ofs = 0xb8, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DISP_BIST] = { .ofs = 0xb8, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_NPU_BIST] = { .ofs = 0xb8, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_CAS_BIST] = { .ofs = 0xb8, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE4_BIST] = { .ofs = 0xb8, .bit = 20, .write_en = 1 },
> + /* Bank 7: offset 0x454 (DUMMY0, no write_en) */
> + [RTD1625_CRT_RSTN_EMMC] = { .ofs = 0x454, .bit = 0 },
> + /* Bank 8: offset 0x458 (DUMMY1, no write_en) */
> + [RTD1625_CRT_RSTN_GPU] = { .ofs = 0x458, .bit = 0 },
> + /* Bank 9: offset 0x464 (DUMMY4, no write_en) */
> + [RTD1625_CRT_RSTN_VE2] = { .ofs = 0x464, .bit = 0 },
> + /* Bank 10: offset 0x880 */
> + [RTD1625_CRT_RSTN_UR1] = { .ofs = 0x880, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR2] = { .ofs = 0x880, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR3] = { .ofs = 0x880, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR4] = { .ofs = 0x880, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR5] = { .ofs = 0x880, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR6] = { .ofs = 0x880, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR7] = { .ofs = 0x880, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR8] = { .ofs = 0x880, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR9] = { .ofs = 0x880, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR_TOP] = { .ofs = 0x880, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_7] = { .ofs = 0x880, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_6] = { .ofs = 0x880, .bit = 30, .write_en = 1 },
> + /* Bank 11: offset 0x890 */
> + [RTD1625_CRT_RSTN_SPI0] = { .ofs = 0x890, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI1] = { .ofs = 0x890, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI2] = { .ofs = 0x890, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC0] = { .ofs = 0x890, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC1] = { .ofs = 0x890, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_ISOMIS_DMA] = { .ofs = 0x890, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUDIO_ADC] = { .ofs = 0x890, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DPTX] = { .ofs = 0x890, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUCPU1_REG] = { .ofs = 0x890, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EDPTX] = { .ofs = 0x890, .bit = 28, .write_en = 1 },
> +};
> +
> +static int rtd1625_crt_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct rtk_reset_data *data;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->descs = rtd1625_crt_reset_descs;
> + data->rcdev.nr_resets = RTD1625_CRT_RSTN_MAX;
> + return rtk_reset_controller_add(dev, data);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Will the reset controller driver unconditionally fail to probe with -ENODEV
due to an incompatible regmap acquisition method?
The rtk_reset_controller_add() helper attempts to retrieve the shared regmap
from the parent clock device using dev_get_regmap(parent, NULL). However, the
parent clock driver (rtk_clk_probe()) acquires its regmap via
device_node_to_regmap().
This syscon helper creates the regmap but does not associate it with the
parent struct device via devres. Because the regmap is absent from the
parent's devres list, dev_get_regmap() will always return NULL, causing the
reset driver probe to fail unconditionally and leaving dependent peripherals
without reset control.
Brian
> +}
> +
> +static const struct auxiliary_device_id rtd1625_crt_reset_ids[] = {
> + {
> + .name = "clk_rtk.crt_rst",
> + },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(auxiliary, rtd1625_crt_reset_ids);
> +
> +static struct auxiliary_driver rtd1625_crt_driver = {
> + .probe = rtd1625_crt_reset_probe,
> + .id_table = rtd1625_crt_reset_ids,
> + .driver = {
> + .name = "rtd1625-crt-reset",
> + },
> +};
> +module_auxiliary_driver(rtd1625_crt_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_RESET");
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH V4 1/3] net: stmmac: Fix PTP ref clock for Tegra234
From: Simon Horman @ 2026-04-03 15:16 UTC (permalink / raw)
To: Jon Hunter
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Thierry Reding, netdev, devicetree, linux-tegra
In-Reply-To: <20260401102941.17466-2-jonathanh@nvidia.com>
On Wed, Apr 01, 2026 at 11:29:39AM +0100, Jon Hunter wrote:
> Since commit 030ce919e114 ("net: stmmac: make sure that ptp_rate is not
> 0 before configuring timestamping") was added the following error is
> observed on Tegra234:
>
> ERR KERN tegra-mgbe 6800000.ethernet eth0: Invalid PTP clock rate
> WARNING KERN tegra-mgbe 6800000.ethernet eth0: PTP init failed
>
> It turns out that the Tegra234 device-tree binding defines the PTP ref
> clock name as 'ptp-ref' and not 'ptp_ref' and the above commit now
> exposes this and that the PTP clock is not configured correctly.
>
> In order to update device-tree to use the correct 'ptp_ref' name, update
> the Tegra MGBE driver to use 'ptp_ref' by default and fallback to using
> 'ptp-ref' if this clock name is present.
>
> Fixes: d8ca113724e7 ("net: stmmac: tegra: Add MGBE support")
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
The nit below notwithstanding this looks good to me.
Reviewed-by: Simon Horman <horms@kernel.org>
> ---
> .../net/ethernet/stmicro/stmmac/dwmac-tegra.c | 20 +++++++++++++++++--
> 1 file changed, 18 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
> index b4b39e6a169e..3af2f001fada 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
...
> @@ -216,6 +216,7 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
> struct plat_stmmacenet_data *plat;
> struct stmmac_resources res;
> struct tegra_mgbe *mgbe;
> + bool use_legacy_ptp = false;
> int irq, err, i;
> u32 value;
>
nit: As this is Networking code, please retain reverse xmas tree order --
longest line to shortest -- for local variable declarations.
...
^ permalink raw reply
* Re: [PATCH v6 07/10] clk: realtek: Add support for MMC-tuned PLL clocks
From: Brian Masney @ 2026-04-03 15:10 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-8-eleanor.lin@realtek.com>
Hi Yu-Chun,
I should have finished going through Sashiko while manually reviewing
your patches.
On Thu, Apr 02, 2026 at 03:39:54PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add clk_pll_mmc_ops for enable/disable, prepare, rate control, and status
> operations on MMC PLL clocks.
>
> Also add clk_pll_mmc_phase_ops to support phase get/set operations.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Jyan Chou <jyanchou@realtek.com>
> Signed-off-by: Jyan Chou <jyanchou@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> +static int clk_pll_mmc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val = PLL_MMC_SSC_DIV_N_VAL;
> + int ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK, 0x0 << PLL_FLAG_INITAL_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_n(clkm, val);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_ext_f(clkm, 1517);
> + if (ret)
> + return ret;
> +
> + switch (val) {
> + case 31 ... 46:
> + ret |= set_pi_ibselh(clkm, 3);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 2);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Is it intended to use bitwise OR to accumulate these return values? Because
these hardware operations return standard negative error codes on failure,
performing a bitwise OR on multiple negative integers will merge their bit
patterns and create a corrupted error code.
> + break;
> +
> + case 20 ... 30:
> + ret |= set_pi_ibselh(clkm, 2);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 10 ... 19:
> + ret |= set_pi_ibselh(clkm, 1);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 5 ... 9:
> + ret |= set_pi_ibselh(clkm, 0);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 0);
> + break;
> + }
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_NCODE_SSC_EMMC_MASK,
> + 27 << PLL_NCODE_SSC_EMMC_SHIFT);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Are the mask and shift values mismatched here? PLL_FLAG_INITAL_EMMC_MASK is
defined as BIT(1) (0x02), but PLL_FLAG_INITAL_EMMC_SHIFT is 8.
When regmap_update_bits() applies the 0x02 mask to a value shifted by 8,
won't it evaluate to 0 and fail to set the intended initialization flag?
Brian
^ permalink raw reply
* Re: [PATCH v4 0/3] Add CAMSS support for SM6350
From: Bryan O'Donoghue @ 2026-04-03 15:07 UTC (permalink / raw)
To: Luca Weiss, Vladimir Zapolskiy
Cc: Konrad Dybcio, Bryan O'Donoghue, Conor Dooley, Robert Foss,
~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-media, devicetree, linux-kernel, Krzysztof Kozlowski,
Todor Tomov, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Bjorn Andersson
In-Reply-To: <DHJD7P2TXQTH.1TQ4YQQ21A6CS@fairphone.com>
On 03/04/2026 09:09, Luca Weiss wrote:
> Hi Vladimir,
>
> On Tue Mar 31, 2026 at 12:49 AM CEST, Vladimir Zapolskiy wrote:
>> Hi Luca,
>>
>> On 2/16/26 10:54, Luca Weiss wrote:
>>> Add bindings, driver and dts to support the Camera Subsystem on the
>>> SM6350 SoC.
>>>
>>> These patches were tested on a Fairphone 4 smartphone with WIP sensor
>>> drivers (Sony IMX576 and IMX582), the camera pipeline works properly as
>>> far as I can tell.
>>>
>>> Though when stopping the camera stream, the following clock warning
>>> appears in dmesg. But it does not interfere with any functionality,
>>> starting and stopping the stream works and debugcc is showing 426.4 MHz
>>> while the clock is on, and 'off' while it's off.
>>>
>>> Any suggestion how to fix this, is appreciated.
>>
>> I've looked at CAMCC recently, and I do notice that SM6350 CAMCC does not
>> set '.use_rpm = true' flag for whatever reason.
>>
>> If you find a free minute, can you test the change below?..
>
> Unfortunately that change does not resolve the "gcc_camera_axi_clk
> status stuck at 'on'" warning.
>
> fairphone-fp4:~$ cat /sys/bus/platform/drivers/sm6350-camcc/ad00000.clock-controller/power/runtime_status
> active
>
> fairphone-fp4:~$ cat /sys/bus/platform/drivers/sm6350-camcc/ad00000.clock-controller/power/runtime_status
> suspended
>
>>
>> ----8<----
>> diff --git a/drivers/clk/qcom/camcc-sm6350.c b/drivers/clk/qcom/camcc-sm6350.c
>> index 7df12c1311c6..ba880e4edcaf 100644
>> --- a/drivers/clk/qcom/camcc-sm6350.c
>> +++ b/drivers/clk/qcom/camcc-sm6350.c
>> @@ -1880,6 +1880,7 @@ static const struct qcom_cc_desc camcc_sm6350_desc = {
>> .num_clks = ARRAY_SIZE(camcc_sm6350_clocks),
>> .gdscs = camcc_sm6350_gdscs,
>> .num_gdscs = ARRAY_SIZE(camcc_sm6350_gdscs),
>> + .use_rpm = true,
>> };
>>
>> static const struct of_device_id camcc_sm6350_match_table[] = {
>> ----8<----
>>
>> This change could be considered to be included in any case, I believe.
>
> I guess this change is now the way to enable pm_runtime, I had this
> series 3 years ago in February 2023:
> https://lore.kernel.org/linux-arm-msm/20230213-sm6350-camcc-runtime_pm-v3-0-d35e0d833cc4@fairphone.com/
>
> But I never followed up due to me not understanding pm_runtime well and
> no direct need for it.
>
> But I guess reviving that with use_rpm = true, add power-domains &
> required-opps to dt-bindings and sm6350.dtsi should be a good idea?
>
> Regards
> Luca
>
>>
>>> [ 5738.590980] ------------[ cut here ]------------
>>> [ 5738.591009] gcc_camera_axi_clk status stuck at 'on'
>>> [ 5738.591049] WARNING: CPU: 0 PID: 6918 at drivers/clk/qcom/clk-branch.c:87 clk_branch_toggle+0x170/0x190
>>> [ 5738.591081] Modules linked in:
>>> [ 5738.591099] CPU: 0 UID: 10000 PID: 6918 Comm: plasma-camera Tainted: G W 6.17.0-00057-ge6b67db49622 #71 NONE
>>> [ 5738.591118] Tainted: [W]=WARN
>>> [ 5738.591126] Hardware name: Fairphone 4 (DT)
>>> [ 5738.591136] pstate: 604000c5 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
>>> [ 5738.591150] pc : clk_branch_toggle+0x170/0x190
>>> [ 5738.591164] lr : clk_branch_toggle+0x170/0x190
>>> [ 5738.591177] sp : ffff800086ed3980
>>> [ 5738.591184] x29: ffff800086ed3990 x28: 0000000000000001 x27: ffff800086ed3cd8
>>> [ 5738.591208] x26: 0000000000000000 x25: ffffda14fcfbd250 x24: 0000000000000000
>>> [ 5738.591230] x23: 0000000000000000 x22: ffffda14fc38bce0 x21: 0000000000000000
>>> [ 5738.591252] x20: ffffda14fd33e618 x19: 0000000000000000 x18: 00000000000064c8
>>> [ 5738.591274] x17: 0000000000000000 x16: 00001ae003667e9e x15: ffffda14fd2a07b0
>>> [ 5738.591295] x14: 0000000000000000 x13: 6f27207461206b63 x12: 7574732073757461
>>> [ 5738.591317] x11: 0000000000000058 x10: 0000000000000018 x9 : ffffda14fd2a0838
>>> [ 5738.591338] x8 : 0000000000057fa8 x7 : 0000000000000a16 x6 : ffffda14fd2f8838
>>> [ 5738.591360] x5 : ffff0001f6f59788 x4 : 0000000000000a15 x3 : ffff25ecf9d7e000
>>> [ 5738.591381] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0000baf5c100
>>> [ 5738.591403] Call trace:
>>> [ 5738.591412] clk_branch_toggle+0x170/0x190 (P)
>>> [ 5738.591429] clk_branch2_disable+0x1c/0x30
>>> [ 5738.591445] clk_core_disable+0x5c/0xb4
>>> [ 5738.591462] clk_disable+0x38/0x60
>>> [ 5738.591478] camss_disable_clocks+0x44/0x78
>>> [ 5738.591496] vfe_put+0x7c/0xc0
>>> [ 5738.591512] vfe_set_power+0x40/0x50
>>> [ 5738.591528] pipeline_pm_power_one+0x14c/0x150
>>> [ 5738.591546] pipeline_pm_power+0x74/0xf4
>>> [ 5738.591561] v4l2_pipeline_pm_use+0x54/0x9c
>>> [ 5738.591577] v4l2_pipeline_pm_put+0x14/0x40
>>> [ 5738.591592] video_unprepare_streaming+0x18/0x24
>>> [ 5738.591608] __vb2_queue_cancel+0x4c/0x314
>>> [ 5738.591626] vb2_core_streamoff+0x24/0xc8
>>> [ 5738.591643] vb2_ioctl_streamoff+0x58/0x98
>>> [ 5738.591657] v4l_streamoff+0x24/0x30
>>> [ 5738.591672] __video_do_ioctl+0x430/0x4a8
>>> [ 5738.591689] video_usercopy+0x2ac/0x680
>>> [ 5738.591705] video_ioctl2+0x18/0x40
>>> [ 5738.591720] v4l2_ioctl+0x40/0x60
>>> [ 5738.591734] __arm64_sys_ioctl+0x90/0xf0
>>> [ 5738.591750] invoke_syscall.constprop.0+0x40/0xf0
>>> [ 5738.591769] el0_svc_common.constprop.0+0x38/0xd8
>>> [ 5738.591785] do_el0_svc+0x1c/0x28
>>> [ 5738.591801] el0_svc+0x34/0xe8
>>> [ 5738.591820] el0t_64_sync_handler+0xa0/0xe4
>>> [ 5738.591838] el0t_64_sync+0x198/0x19c
>>> [ 5738.591854] ---[ end trace 0000000000000000 ]---
>>>
>>> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
>>> ---
>>> Changes in v4:
>>> - Update power-domain-names order (Krzysztof)
>>> - Make hex numbers lower case in init seq (David)
>>> - Pick up tags
>>> - Link to v3: https://lore.kernel.org/r/20260213-sm6350-camss-v3-0-30a845b0b7cc@fairphone.com
>>
>> Should find some time myself to issue RBs, sorry for the delay.
>>
>>> Changes in v3:
>>> - Update dt-bindings to include everything related to camss
>>> - Update regulator names
>>> - Remove slow_ahb_src
>>> - Link to v2: https://lore.kernel.org/r/20251114-sm6350-camss-v2-0-d1ff67da33b6@fairphone.com
>>>
>>> Changes in v2:
>>> - Remove prefix from interconnect-names
>>> - Move 'top' power-domain to the top of list
>>> - Update regulator supply names
>>> - Link to v1: https://lore.kernel.org/r/20251024-sm6350-camss-v1-0-63d626638add@fairphone.com
>>>
>>> ---
>>> Luca Weiss (3):
>>> dt-bindings: media: camss: Add qcom,sm6350-camss
>>> media: qcom: camss: Add SM6350 support
>>> arm64: dts: qcom: sm6350: Add CAMSS node
>>>
>>> .../bindings/media/qcom,sm6350-camss.yaml | 471 +++++++++++++++++++++
>>> arch/arm64/boot/dts/qcom/sm6350.dtsi | 233 ++++++++++
>>> .../platform/qcom/camss/camss-csiphy-3ph-1-0.c | 125 ++++++
>>> drivers/media/platform/qcom/camss/camss-vfe.c | 2 +
>>> drivers/media/platform/qcom/camss/camss.c | 261 ++++++++++++
>>> drivers/media/platform/qcom/camss/camss.h | 1 +
>>> 6 files changed, 1093 insertions(+)
>>> ---
>>> base-commit: 3daf23347bb5f4a375d0101ed29c97ce1a99721b
>>> change-id: 20251024-sm6350-camss-9c404bf9cfdd
>>>
>>> Best regards,
>
What about taking the clock out of hardware gated mode ?
┌─[deckard@sagittarius-a] - [~/Development/qualcomm/qlt-kernel] - [Fri
Apr 03, 16:05]
└─[$]> git diff
diff --git a/drivers/clk/qcom/gcc-sm6350.c b/drivers/clk/qcom/gcc-sm6350.c
index a4d6dff9d0f7f..f98cb35bcd408 100644
--- a/drivers/clk/qcom/gcc-sm6350.c
+++ b/drivers/clk/qcom/gcc-sm6350.c
@@ -909,8 +909,6 @@ static struct clk_branch gcc_camera_ahb_clk = {
static struct clk_branch gcc_camera_axi_clk = {
.halt_reg = 0x17018,
.halt_check = BRANCH_HALT,
- .hwcg_reg = 0x17018,
- .hwcg_bit = 1,
.clkr = {
.enable_reg = 0x17018,
.enable_mask = BIT(0),
---
bod
^ permalink raw reply related
* Re: [PATCH v6 07/10] clk: realtek: Add support for MMC-tuned PLL clocks
From: Brian Masney @ 2026-04-03 15:07 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-8-eleanor.lin@realtek.com>
Hi Yu-Chun and Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:54PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add clk_pll_mmc_ops for enable/disable, prepare, rate control, and status
> operations on MMC PLL clocks.
>
> Also add clk_pll_mmc_phase_ops to support phase get/set operations.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Jyan Chou <jyanchou@realtek.com>
> Signed-off-by: Jyan Chou <jyanchou@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move to_clk_pll_mmc() from clk-pll.h to clk-pll-mmc.c to limit its scope.
> - Change offset type from int to unsigned int.
> ---
> MAINTAINERS | 8 +
> drivers/clk/realtek/Kconfig | 3 +
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-pll-mmc.c | 410 ++++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-pll.h | 13 +
> 5 files changed, 436 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-pll-mmc.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8318156a02b5..4b28af4b26b5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22245,6 +22245,14 @@ F: drivers/reset/realtek/*
> F: include/dt-bindings/clock/realtek*
> F: include/dt-bindings/reset/realtek*
>
> +REALTEK SOC PLL CLOCK FOR MMC SUPPORT
> +M: Cheng-Yu Lee <cylee12@realtek.com>
> +M: Jyan Chou <jyanchou@realtek.com>
> +M: Yu-Chun Lin <eleanor.lin@realtek.com>
> +L: linux-clk@vger.kernel.org
> +S: Supported
> +F: drivers/clk/realtek/clk-pll-mmc.c
> +
> REALTEK SPI-NAND
> M: Chris Packham <chris.packham@alliedtelesis.co.nz>
> S: Maintained
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> index bc47d3f1c452..b31a31e57b3a 100644
> --- a/drivers/clk/realtek/Kconfig
> +++ b/drivers/clk/realtek/Kconfig
> @@ -25,4 +25,7 @@ config RTK_CLK_COMMON
> multiple Realtek clock implementations, and include integration
> with reset controllers where required.
>
> +config RTK_CLK_PLL_MMC
> + bool
> +
> endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index f90dc57fcfdb..fd7d777902c8 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -7,3 +7,5 @@ clk-rtk-y += clk-pll.o
> clk-rtk-y += clk-regmap-gate.o
> clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
> +
> +clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> diff --git a/drivers/clk/realtek/clk-pll-mmc.c b/drivers/clk/realtek/clk-pll-mmc.c
> new file mode 100644
> index 000000000000..d28c7027d3f0
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll-mmc.c
> @@ -0,0 +1,410 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2021 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +
> +#define PLL_EMMC1_OFFSET 0x0
> +#define PLL_EMMC2_OFFSET 0x4
> +#define PLL_EMMC3_OFFSET 0x8
> +#define PLL_EMMC4_OFFSET 0xc
> +#define PLL_SSC_DIG_EMMC1_OFFSET 0x0
> +#define PLL_SSC_DIG_EMMC3_OFFSET 0xc
> +#define PLL_SSC_DIG_EMMC4_OFFSET 0x10
> +
> +#define PLL_MMC_SSC_DIV_N_VAL 0x1b
> +
> +#define PLL_PHRT0_MASK BIT(1)
> +#define PLL_PHSEL_MASK GENMASK(4, 0)
> +#define PLL_SSCPLL_RS_MASK GENMASK(12, 10)
> +#define PLL_SSCPLL_ICP_MASK GENMASK(9, 5)
> +#define PLL_SSC_DIV_EXT_F_MASK GENMASK(25, 13)
> +#define PLL_PI_IBSELH_MASK GENMASK(28, 27)
> +#define PLL_SSC_DIV_N_MASK GENMASK(23, 16)
> +#define PLL_NCODE_SSC_EMMC_MASK GENMASK(20, 13)
> +#define PLL_FCODE_SSC_EMMC_MASK GENMASK(12, 0)
> +#define PLL_GRAN_EST_EM_MC_MASK GENMASK(20, 0)
> +#define PLL_EN_SSC_EMMC_MASK BIT(0)
> +#define PLL_FLAG_INITAL_EMMC_MASK BIT(1)
> +
> +#define PLL_PHRT0_SHIFT 1
> +#define PLL_SSCPLL_RS_SHIFT 10
> +#define PLL_SSCPLL_ICP_SHIFT 5
> +#define PLL_SSC_DIV_EXT_F_SHIFT 13
> +#define PLL_PI_IBSELH_SHIFT 27
> +#define PLL_SSC_DIV_N_SHIFT 16
> +#define PLL_NCODE_SSC_EMMC_SHIFT 13
> +#define PLL_FLAG_INITAL_EMMC_SHIFT 8
> +
> +#define CYCLE_DEGREES 360
> +#define PHASE_STEPS 32
> +#define PHASE_SCALE_FACTOR 1125
> +
> +static inline struct clk_pll_mmc *to_clk_pll_mmc(struct clk_hw *hw)
> +{
> + struct clk_regmap *clkr = to_clk_regmap(hw);
> +
> + return container_of(clkr, struct clk_pll_mmc, clkr);
> +}
> +
> +static inline int get_phrt0(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + u32 reg;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET, ®);
> + if (ret)
> + return ret;
> +
> + *val = (reg >> PLL_PHRT0_SHIFT) & PLL_PHRT0_MASK;
Sashiko reports the following:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
With PLL_PHRT0_SHIFT defined as 1 and PLL_PHRT0_MASK as BIT(1) (0x02), shifting
right by 1 moves the target bit 1 to position 0, but masking with 0x02 checks
position 1 of the shifted value.
Will this cause clk_pll_mmc_is_enabled() to always evaluate to false since it
expects val == 0x1?
> + return 0;
> +}
> +
> +static inline int set_phrt0(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET,
> + PLL_PHRT0_MASK, val << PLL_PHRT0_SHIFT);
> +}
> +
> +static inline int get_phsel(struct clk_pll_mmc *clkm, int id, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> + u32 sft = id ? 8 : 3;
Put variables in reverse Christmas tree order.
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val >> sft) & PLL_PHSEL_MASK;
> + return 0;
> +}
> +
> +static inline int set_phsel(struct clk_pll_mmc *clkm, int id, u32 val)
> +{
> + u32 sft = id ? 8 : 3;
> +
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET,
> + PLL_PHSEL_MASK << sft, val << sft);
> +}
> +
> +static inline int set_sscpll_rs(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSCPLL_RS_MASK, val << PLL_SSCPLL_RS_SHIFT);
> +}
> +
> +static inline int set_sscpll_icp(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSCPLL_ICP_MASK, val << PLL_SSCPLL_ICP_SHIFT);
> +}
> +
> +static inline int get_ssc_div_ext_f(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + u32 raw_val;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val & PLL_SSC_DIV_EXT_F_MASK) >> PLL_SSC_DIV_EXT_F_SHIFT;
> + return 0;
> +}
> +
> +static inline int set_ssc_div_ext_f(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSC_DIV_EXT_F_MASK,
> + val << PLL_SSC_DIV_EXT_F_SHIFT);
> +}
> +
> +static inline int set_pi_ibselh(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_PI_IBSELH_MASK, val << PLL_PI_IBSELH_SHIFT);
> +}
> +
> +static inline int set_ssc_div_n(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC3_OFFSET,
> + PLL_SSC_DIV_N_MASK, val << PLL_SSC_DIV_N_SHIFT);
> +}
> +
> +static inline int get_ssc_div_n(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC3_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val & PLL_SSC_DIV_N_MASK) >> PLL_SSC_DIV_N_SHIFT;
> + return 0;
> +}
> +
> +static inline int set_pow_ctl(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_write(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC4_OFFSET, val);
> +}
> +
> +static inline int get_pow_ctl(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC4_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = raw_val;
> +
> + return 0;
> +}
> +
> +static int clk_pll_mmc_phase_set_phase(struct clk_hw *hw, int degrees)
> +{
> + struct clk_hw *hwp = clk_hw_get_parent(hw);
> + struct clk_pll_mmc *clkm;
> + int phase_id;
> + int ret;
> + u32 val;
> +
> + if (!hwp)
> + return -ENOENT;
> +
> + clkm = to_clk_pll_mmc(hwp);
> + phase_id = (hw - &clkm->phase0_hw) ? 1 : 0;
Are you checking to see if these two pointers are the same? If so, what
do you think about this instead?
hw == &clkm->phase0_hw
> + val = DIV_ROUND_CLOSEST(degrees * 100, PHASE_SCALE_FACTOR);
> + ret = set_phsel(clkm, phase_id, val);
> + if (ret)
> + return ret;
> +
> + usleep_range(10, 20);
> + return 0;
> +}
> +
> +static int clk_pll_mmc_phase_get_phase(struct clk_hw *hw)
> +{
> + struct clk_hw *hwp;
> + struct clk_pll_mmc *clkm;
> + int phase_id;
> + int ret;
> + u32 val;
> +
> + hwp = clk_hw_get_parent(hw);
> + if (!hwp)
> + return -ENOENT;
> +
> + clkm = to_clk_pll_mmc(hwp);
> + phase_id = (hw - &clkm->phase0_hw) ? 1 : 0;
> + ret = get_phsel(clkm, phase_id, &val);
> + if (ret)
> + return ret;
> +
> + val = DIV_ROUND_CLOSEST(val * CYCLE_DEGREES, PHASE_STEPS);
> +
> + return val;
> +}
> +
> +const struct clk_ops rtk_clk_pll_mmc_phase_ops = {
> + .set_phase = clk_pll_mmc_phase_set_phase,
> + .get_phase = clk_pll_mmc_phase_get_phase,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_mmc_phase_ops, "REALTEK_CLK");
> +
> +static int clk_pll_mmc_prepare(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + return set_pow_ctl(clkm, 7);
> +}
> +
> +static void clk_pll_mmc_unprepare(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + set_pow_ctl(clkm, 0);
> +}
> +
> +static int clk_pll_mmc_is_prepared(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val;
> + int ret;
> +
> + ret = get_pow_ctl(clkm, &val);
> + if (ret)
> + return 1;
> +
> + return val != 0x0;
> +}
> +
> +static int clk_pll_mmc_enable(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + int ret;
> +
> + ret = set_phrt0(clkm, 1);
> + if (ret)
> + return ret;
> +
> + udelay(10);
> + return 0;
> +}
> +
> +static void clk_pll_mmc_disable(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + set_phrt0(clkm, 0);
> + udelay(10);
> +}
> +
> +static int clk_pll_mmc_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val;
> + int ret;
> +
> + ret = get_phrt0(clkm, &val);
> + if (ret)
> + return 1;
> +
> + return val == 0x1;
> +}
> +
> +static unsigned long clk_pll_mmc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val, ext_f;
> + int ret;
> +
> + ret = get_ssc_div_n(clkm, &val);
> + if (ret)
> + return ret;
> +
> + ret = get_ssc_div_ext_f(clkm, &ext_f);
> + if (ret)
> + return ret;
> +
> + return parent_rate / 4 * (val + 2) + (parent_rate / 4 * ext_f) / 8192;
> +}
> +
> +static int clk_pll_mmc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
Should there be a check for a parent rate of zero before the division is
done?
> + u32 val = DIV_ROUND_CLOSEST(req->rate * 4, req->best_parent_rate);
> +
> + req->rate = req->best_parent_rate * val / 4;
> + return 0;
> +}
> +
> +static int clk_pll_mmc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val = PLL_MMC_SSC_DIV_N_VAL;
> + int ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK, 0x0 << PLL_FLAG_INITAL_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_n(clkm, val);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_ext_f(clkm, 1517);
> + if (ret)
> + return ret;
> +
> + switch (val) {
> + case 31 ... 46:
> + ret |= set_pi_ibselh(clkm, 3);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 2);
> + break;
> +
> + case 20 ... 30:
> + ret |= set_pi_ibselh(clkm, 2);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 10 ... 19:
> + ret |= set_pi_ibselh(clkm, 1);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 5 ... 9:
> + ret |= set_pi_ibselh(clkm, 0);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 0);
> + break;
> + }
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_NCODE_SSC_EMMC_MASK,
> + 27 << PLL_NCODE_SSC_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_FCODE_SSC_EMMC_MASK, 321);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC4_OFFSET,
> + PLL_GRAN_EST_EM_MC_MASK, 5985);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_EN_SSC_EMMC_MASK, 0x1);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_EN_SSC_EMMC_MASK, 0x0);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK,
> + 0x1 << PLL_FLAG_INITAL_EMMC_SHIFT);
It looks like the rate and parent rate are not used in this function.
Will this always end up with the same rate when everything is
successful?
Brian
^ permalink raw reply
* [PATCH 2/2] arm64: dts: qcom: milos: Add IMEM node
From: Luca Weiss @ 2026-04-03 15:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm, devicetree,
linux-kernel, Luca Weiss
In-Reply-To: <20260403-milos-imem-v1-0-4244ebb47017@fairphone.com>
Add a node for the IMEM found on Milos, which contains pil-reloc-info
and the modem tables for IPA, among others.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
arch/arm64/boot/dts/qcom/milos.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi
index 4a64a98a434b..1c045743ef77 100644
--- a/arch/arm64/boot/dts/qcom/milos.dtsi
+++ b/arch/arm64/boot/dts/qcom/milos.dtsi
@@ -2289,6 +2289,25 @@ scl-pins {
};
};
+ sram@14680000 {
+ compatible = "qcom,milos-imem", "syscon", "simple-mfd";
+ reg = <0x0 0x14680000 0x0 0x2c000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ranges = <0 0 0x14680000 0x2c000>;
+
+ pil-reloc@94c {
+ compatible = "qcom,pil-reloc-info";
+ reg = <0x94c 0xc8>;
+ };
+
+ ipa_modem_tables: modem-tables@3000 {
+ reg = <0x3000 0x2000>;
+ };
+ };
+
apps_smmu: iommu@15000000 {
compatible = "qcom,milos-smmu-500", "qcom,smmu-500", "arm,mmu-500";
reg = <0x0 0x15000000 0x0 0x100000>;
--
2.53.0
^ permalink raw reply related
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