[PATCH v4 9/9] clk: sunxi-ng: sun6i-rtc: add a733 support

Chen-Yu Tsai wens at kernel.org
Mon Jul 6 09:47:30 PDT 2026


On Mon, Jul 6, 2026 at 5:32 PM Jerome Brunet <jbrunet at baylibre.com> wrote:
>
> Add support for the sun60i a733 CCU RTC.
>
> Compared to the a523, this SoC has a different input oscillator divider
> which auto-detects the oscillator rate and select a divider to provide
> a fixed 32768Hz clock. It also provides several phy reference clocks
> with dedicated clock gates.
>
> Signed-off-by: Jerome Brunet <jbrunet at baylibre.com>
> ---
>  drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 73 ++++++++++++++++++++++++++++++++++--
>  drivers/clk/sunxi-ng/ccu-sun6i-rtc.h |  2 +-
>  2 files changed, 71 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
> index 25dd87e78eb7..6b71bbd80255 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
> @@ -44,9 +44,13 @@
>  #define DCXO_CTRL_REG                  0x160
>  #define DCXO_CTRL_CLK16M_RC_EN         BIT(0)
>
> +#define DCXO_GATING_REG                        0x16c
> +
>  struct sun6i_rtc_match_data {
>         bool                            have_ext_osc32k         : 1;
>         bool                            have_iosc_calibration   : 1;
> +       bool                            have_dcxo_status        : 1;
> +       bool                            have_phy_ref_gates      : 1;
>         bool                            rtc_32k_single_parent   : 1;
>         const struct clk_parent_data    *osc32k_fanout_parents;
>         u8                              osc32k_fanout_nparents;
> @@ -213,7 +217,12 @@ static struct ccu_mux osc32k_clk = {
>         },
>  };
>
> -/* This falls back to the global name for fwnodes without a named reference. */
> +/*
> + * This falls back to the global name for fwnodes without a named reference.
> + * NOTE: osc24M name might be misleading the oscillator could also be a 26MHz
> + * or a 19.2MHz one starting with the a733. The original name is kept anyway
> + * in case anything is relying on it.
> + */
>  static const struct clk_parent_data osc24M[] = {
>         { .fw_name = "hosc", .name = "osc24M" }
>  };
> @@ -227,8 +236,28 @@ static struct clk_fixed_factor osc24M_32k_div_clk = {
>                                             0),
>  };
>
> -static SUNXI_CCU_GATE_HW(osc24M_32k_clk, "osc24M-32k", &osc24M_32k_div_clk.hw,
> -                        LOSC_OUT_GATING_REG, BIT(16), 0);
> +static struct clk_div_table osc24M_32k_div_a733_table[] = {
> +       { .val = 0, .div = 732 },
> +       { .val = 1, .div = 586 },
> +       { .val = 2, .div = 793 },
> +       { .val = 3, .div = 732 },
> +       { /* Sentinel */ },
> +};
> +
> +static struct ccu_div osc24M_32k_div_a733_clk = {
> +       .enable = BIT(1),
> +       .div    = _SUNXI_CCU_DIV_TABLE(14, 2, osc24M_32k_div_a733_table),
> +       .common = {
> +               .reg            = DCXO_CTRL_REG,
> +               .hw.init        = CLK_HW_INIT_PARENTS_DATA("osc24M-32k-div",
> +                                                          osc24M,
> +                                                          &ccu_rodiv_ops,
> +                                                          0),
> +       },
> +};
> +
> +static SUNXI_CCU_GATE(osc24M_32k_clk, "osc24M-32k", "osc24M-32k-div",

I'm not a big fan of using global clock parent names, especially when we
can have proper struct clk_hw pointer references. However in this case
it seems unavoidable without making a huge mess.

> +                     LOSC_OUT_GATING_REG, BIT(16), 0);
>
>  static const struct clk_hw *rtc_32k_parents[] = {
>         &osc32k_clk.common.hw,
> @@ -267,6 +296,15 @@ static struct ccu_mux osc32k_fanout_clk = {
>         },
>  };
>
> +static SUNXI_CCU_GATE_FW(hosc_serdes1_clk, "hosc-serdes1", "hosc",
> +                     DCXO_GATING_REG, BIT(5), 0);
> +static SUNXI_CCU_GATE_FW(hosc_serdes0_clk, "hosc-serdes0", "hosc",
> +                     DCXO_GATING_REG, BIT(4), 0);
> +static SUNXI_CCU_GATE_FW(hosc_hdmi_clk, "hosc-hdmi", "hosc",
> +                     DCXO_GATING_REG, BIT(1), 0);
> +static SUNXI_CCU_GATE_FW(hosc_ufs_clk, "hosc-ufs", "hosc",
> +                     DCXO_GATING_REG, BIT(0), 0);
> +
>  static struct ccu_common *sun6i_rtc_ccu_clks[] = {
>         &iosc_clk,
>         &iosc_32k_clk,
> @@ -275,6 +313,11 @@ static struct ccu_common *sun6i_rtc_ccu_clks[] = {
>         &osc24M_32k_clk.common,
>         &rtc_32k_clk.common,
>         &osc32k_fanout_clk.common,
> +       &osc24M_32k_div_a733_clk.common,
> +       &hosc_serdes1_clk.common,
> +       &hosc_serdes0_clk.common,
> +       &hosc_hdmi_clk.common,
> +       &hosc_ufs_clk.common,
>  };
>
>  static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
> @@ -288,6 +331,10 @@ static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
>                 [CLK_OSC24M_32K]        = &osc24M_32k_clk.common.hw,
>                 [CLK_RTC_32K]           = &rtc_32k_clk.common.hw,
>                 [CLK_OSC24M_32K_DIV]    = &osc24M_32k_div_clk.hw,
> +               [CLK_HOSC_UFS]          = &hosc_ufs_clk.common.hw,
> +               [CLK_HOSC_HDMI]         = &hosc_hdmi_clk.common.hw,
> +               [CLK_HOSC_SERDES0]      = &hosc_serdes0_clk.common.hw,
> +               [CLK_HOSC_SERDES1]      = &hosc_serdes1_clk.common.hw,
>         },
>  };
>
> @@ -330,6 +377,15 @@ static const struct sun6i_rtc_match_data sun55i_a523_rtc_ccu_data = {
>         .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents),
>  };
>
> +static const struct sun6i_rtc_match_data sun60i_a733_rtc_ccu_data = {
> +       .have_ext_osc32k        = true,
> +       .have_iosc_calibration  = true,
> +       .have_dcxo_status       = true,
> +       .have_phy_ref_gates     = true,
> +       .osc32k_fanout_parents  = sun50i_r329_osc32k_fanout_parents,
> +       .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents),
> +};
> +
>  static const struct of_device_id sun6i_rtc_ccu_match[] = {
>         {
>                 .compatible     = "allwinner,sun50i-h616-rtc",
> @@ -343,6 +399,10 @@ static const struct of_device_id sun6i_rtc_ccu_match[] = {
>                 .compatible     = "allwinner,sun55i-a523-rtc",
>                 .data           = &sun55i_a523_rtc_ccu_data,
>         },
> +       {
> +               .compatible     = "allwinner,sun60i-a733-rtc",
> +               .data           = &sun60i_a733_rtc_ccu_data,
> +       },
>         {},
>  };
>  MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match);
> @@ -375,6 +435,13 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
>         osc32k_fanout_init_data.parent_data = data->osc32k_fanout_parents;
>         osc32k_fanout_init_data.num_parents = data->osc32k_fanout_nparents;
>
> +       if (data->have_dcxo_status)
> +               sun6i_rtc_ccu_hw_clks.hws[CLK_OSC24M_32K_DIV] =
> +                       &osc24M_32k_div_a733_clk.common.hw;
> +
> +       if (!data->have_phy_ref_gates)
> +               sun6i_rtc_ccu_hw_clks.num = CLK_OSC24M_32K_DIV + 1;

Maybe keep the old CLK_NUMBER macro and call the new one CLK_NUMBER_A733?
The point is to not directly use a random macro + 1 here.

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens at kernel.org>

> +
>         return devm_sunxi_ccu_probe(dev, reg, &sun6i_rtc_ccu_desc);
>  }
>
> diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
> index ab7b92b47f59..4f4f4cb00f1d 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
> +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
> @@ -11,6 +11,6 @@
>  #define CLK_RTC_32K            6
>  #define CLK_OSC24M_32K_DIV     7
>
> -#define CLK_NUMBER             (CLK_OSC24M_32K_DIV + 1)
> +#define CLK_NUMBER             (CLK_HOSC_SERDES1 + 1)
>
>  #endif /* _CCU_SUN6I_RTC_H */
>
> --
> 2.47.3
>



More information about the linux-arm-kernel mailing list