summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@kernel.org>2026-08-11 23:08:57 -0700
committerStephen Boyd <sboyd@kernel.org>2026-08-11 23:08:57 -0700
commitd8a8d206a7ea9ebc0cefeb74263a1096d3858f27 (patch)
treec1a89d647c10acfc771903984841f53071d26f45
parent8cdeaa50eae8dad34885515f62559ee83e7e8dda (diff)
parent0a136efc0fc2d53b1b1389b3c3fb0f76edca38bf (diff)
downloadlinux-stable-d8a8d206a7ea9ebc0cefeb74263a1096d3858f27.tar.gz
linux-stable-d8a8d206a7ea9ebc0cefeb74263a1096d3858f27.zip
Merge tag 'sunxi-clk-for-7.3' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into clk-allwinner
Pull Allwinner clk driver updates from Chen-Yu Tsai: Some cleanups to the Allwinner clock driver library and support for the Allwinner A733 RTC clocks added. * tag 'sunxi-clk-for-7.3' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux: clk: sunxi-ng: sun6i-rtc: add a733 support clk: sunxi-ng: sun6i-rtc: split main oscillator div and gate clk: sunxi-ng: div: add read-only operation support clk: sunxi-ng: mux: fix determine helper rate propagation clk: sunxi-ng: mux: remove unneeded export clk: sunxi-ng: sun6i-rtc: Add feature bit for IOSC calibration clk: sunxi-ng: sun6i-rtc: clean up DT usage clk: sunxi-ng: fix ccu probe clock unregister on error dt-bindings: rtc: sun6i: add sun60i-a733 support dt-bindings: rtc: sun6i: no clock-output-names on h616/r329
-rw-r--r--Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml13
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun6i-rtc.c127
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun6i-rtc.h3
-rw-r--r--drivers/clk/sunxi-ng/ccu_common.c12
-rw-r--r--drivers/clk/sunxi-ng/ccu_common.h1
-rw-r--r--drivers/clk/sunxi-ng/ccu_div.c31
-rw-r--r--drivers/clk/sunxi-ng/ccu_div.h1
-rw-r--r--drivers/clk/sunxi-ng/ccu_mux.c58
-rw-r--r--include/dt-bindings/clock/sun6i-rtc.h4
9 files changed, 176 insertions, 74 deletions
diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
index 9df5cdb6f63f..f2b91186ed37 100644
--- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
@@ -33,6 +33,7 @@ properties:
- enum:
- allwinner,sun20i-d1-rtc
- allwinner,sun55i-a523-rtc
+ - allwinner,sun60i-a733-rtc
- const: allwinner,sun50i-r329-rtc
reg:
@@ -175,6 +176,18 @@ allOf:
interrupts:
minItems: 2
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - allwinner,sun50i-h616-rtc
+ - allwinner,sun50i-r329-rtc
+
+ then:
+ properties:
+ clock-output-names: false
+
required:
- "#clock-cells"
- compatible
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
index f6bfeba009e8..98ae10307f43 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
@@ -44,16 +44,20 @@
#define DCXO_CTRL_REG 0x160
#define DCXO_CTRL_CLK16M_RC_EN BIT(0)
+#define DCXO_GATING_REG 0x16c
+
+#define CLK_NUMBER_NO_GATES (CLK_OSC24M_32K_DIV + 1)
+
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;
};
-static bool have_iosc_calibration;
-
static int ccu_iosc_enable(struct clk_hw *hw)
{
struct ccu_common *cm = hw_to_ccu_common(hw);
@@ -80,7 +84,7 @@ static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
{
struct ccu_common *cm = hw_to_ccu_common(hw);
- if (have_iosc_calibration) {
+ if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
/*
@@ -119,7 +123,7 @@ static int ccu_iosc_32k_prepare(struct clk_hw *hw)
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val;
- if (!have_iosc_calibration)
+ if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
return 0;
val = readl(cm->base + IOSC_CLK_CALI_REG);
@@ -134,7 +138,7 @@ static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val;
- if (!have_iosc_calibration)
+ if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
return;
val = readl(cm->base + IOSC_CLK_CALI_REG);
@@ -148,7 +152,7 @@ static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val;
- if (have_iosc_calibration) {
+ if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
val = readl(cm->base + IOSC_CLK_CALI_REG);
/* Assume the calibrated 32k clock is accurate. */
@@ -167,7 +171,7 @@ static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val;
- if (have_iosc_calibration) {
+ if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
val = readl(cm->base + IOSC_CLK_CALI_REG);
/* Assume the calibrated 32k clock is accurate. */
@@ -191,10 +195,8 @@ static struct ccu_common iosc_32k_clk = {
CLK_GET_RATE_NOCACHE),
};
-static const struct clk_hw *ext_osc32k[] = { NULL }; /* updated during probe */
-
-static SUNXI_CCU_GATE_HWS(ext_osc32k_gate_clk, "ext-osc32k-gate",
- ext_osc32k, 0x0, BIT(4), 0);
+static SUNXI_CCU_GATE_FW(ext_osc32k_gate_clk, "ext-osc32k-gate",
+ "ext-osc32k", 0x0, BIT(4), 0);
static const struct clk_hw *osc32k_parents[] = {
&iosc_32k_clk.hw,
@@ -217,22 +219,50 @@ 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" }
};
-static struct ccu_gate osc24M_32k_clk = {
- .enable = BIT(16),
+static struct clk_fixed_factor osc24M_32k_div_clk = {
+ .mult = 1,
+ .div = 750,
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("osc24M-32k-div",
+ osc24M,
+ &clk_fixed_factor_ops,
+ 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_FLAGS(14, 2,
+ osc24M_32k_div_a733_table,
+ CLK_DIVIDER_READ_ONLY),
.common = {
- .reg = LOSC_OUT_GATING_REG,
- .prediv = 750,
- .features = CCU_FEATURE_ALL_PREDIV,
- .hw.init = CLK_HW_INIT_PARENTS_DATA("osc24M-32k", osc24M,
- &ccu_gate_ops, 0),
+ .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",
+ LOSC_OUT_GATING_REG, BIT(16), 0);
+
static const struct clk_hw *rtc_32k_parents[] = {
&osc32k_clk.common.hw,
&osc24M_32k_clk.common.hw
@@ -270,6 +300,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,
@@ -278,6 +317,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 = {
@@ -290,6 +334,11 @@ static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
[CLK_EXT_OSC32K_GATE] = &ext_osc32k_gate_clk.common.hw,
[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,
},
};
@@ -332,6 +381,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",
@@ -345,6 +403,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);
@@ -352,7 +414,6 @@ MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match);
int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
{
const struct sun6i_rtc_match_data *data;
- struct clk *ext_osc32k_clk = NULL;
const struct of_device_id *match;
/* This driver is only used for newer variants of the hardware. */
@@ -361,23 +422,12 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
return 0;
data = match->data;
- have_iosc_calibration = data->have_iosc_calibration;
-
- if (data->have_ext_osc32k) {
- const char *fw_name;
-
- /* ext-osc32k was the only input clock in the old binding. */
- fw_name = of_property_present(dev->of_node, "clock-names")
- ? "ext-osc32k" : NULL;
- ext_osc32k_clk = devm_clk_get_optional(dev, fw_name);
- if (IS_ERR(ext_osc32k_clk))
- return PTR_ERR(ext_osc32k_clk);
+ if (data->have_iosc_calibration) {
+ iosc_clk.features |= CCU_FEATURE_IOSC_CALIBRATION;
+ iosc_32k_clk.features |= CCU_FEATURE_IOSC_CALIBRATION;
}
- if (ext_osc32k_clk) {
- /* Link ext-osc32k-gate to its parent. */
- *ext_osc32k = __clk_get_hw(ext_osc32k_clk);
- } else {
+ if (!data->have_ext_osc32k) {
/* ext-osc32k-gate is an orphan, so do not register it. */
sun6i_rtc_ccu_hw_clks.hws[CLK_EXT_OSC32K_GATE] = NULL;
osc32k_init_data.num_parents = 1;
@@ -389,6 +439,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_NUMBER_NO_GATES;
+
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 9ae821fc2599..4f4f4cb00f1d 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.h
@@ -9,7 +9,8 @@
#define CLK_EXT_OSC32K_GATE 4
#define CLK_OSC24M_32K 5
#define CLK_RTC_32K 6
+#define CLK_OSC24M_32K_DIV 7
-#define CLK_NUMBER (CLK_RTC_32K + 1)
+#define CLK_NUMBER (CLK_HOSC_SERDES1 + 1)
#endif /* _CCU_SUN6I_RTC_H */
diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
index 1c083b4d0b7e..43d8eca6abee 100644
--- a/drivers/clk/sunxi-ng/ccu_common.c
+++ b/drivers/clk/sunxi-ng/ccu_common.c
@@ -114,7 +114,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
const struct sunxi_ccu_desc *desc)
{
struct ccu_reset *reset;
- int i, ret;
+ int i, j, ret;
ccu->desc = desc;
@@ -130,8 +130,8 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
cclk->lock = &ccu->lock;
}
- for (i = 0; i < desc->hw_clks->num ; i++) {
- struct clk_hw *hw = desc->hw_clks->hws[i];
+ for (j = 0; j < desc->hw_clks->num ; j++) {
+ struct clk_hw *hw = desc->hw_clks->hws[j];
const char *name;
if (!hw)
@@ -143,7 +143,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
else
ret = of_clk_hw_register(node, hw);
if (ret) {
- pr_err("Couldn't register clock %d - %s\n", i, name);
+ pr_err("Couldn't register clock %d - %s\n", j, name);
goto err_clk_unreg;
}
}
@@ -186,8 +186,8 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
err_del_provider:
of_clk_del_provider(node);
err_clk_unreg:
- while (--i >= 0) {
- struct clk_hw *hw = desc->hw_clks->hws[i];
+ while (--j >= 0) {
+ struct clk_hw *hw = desc->hw_clks->hws[j];
if (!hw)
continue;
diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
index bbec283b9d99..d9dc24ad5503 100644
--- a/drivers/clk/sunxi-ng/ccu_common.h
+++ b/drivers/clk/sunxi-ng/ccu_common.h
@@ -21,6 +21,7 @@
#define CCU_FEATURE_CLOSEST_RATE BIT(9)
#define CCU_FEATURE_DUAL_DIV BIT(10)
#define CCU_FEATURE_UPDATE_BIT BIT(11)
+#define CCU_FEATURE_IOSC_CALIBRATION BIT(12)
/* MMC timing mode switch bit */
#define CCU_MMC_NEW_TIMING_MODE BIT(30)
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
index 62d680ccb524..c385e0160f13 100644
--- a/drivers/clk/sunxi-ng/ccu_div.c
+++ b/drivers/clk/sunxi-ng/ccu_div.c
@@ -20,8 +20,22 @@ static int ccu_div_determine_rate_helper(struct ccu_mux_internal *mux,
if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
req->rate *= cd->fixed_post_div;
- ret = divider_determine_rate(&cd->common.hw, req, cd->div.table,
- cd->div.width, cd->div.flags);
+ if (cd->div.flags & CLK_DIVIDER_READ_ONLY) {
+ unsigned long val;
+ u32 reg;
+
+ reg = readl(cd->common.base + cd->common.reg);
+ val = reg >> cd->div.shift;
+ val &= (1 << cd->div.width) - 1;
+
+ ret = divider_ro_determine_rate(&cd->common.hw, req, cd->div.table,
+ cd->div.width, cd->div.flags, val);
+
+ } else {
+ ret = divider_determine_rate(&cd->common.hw, req, cd->div.table,
+ cd->div.width, cd->div.flags);
+ }
+
if (ret)
return ret;
@@ -143,3 +157,16 @@ const struct clk_ops ccu_div_ops = {
.set_rate = ccu_div_set_rate,
};
EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");
+
+const struct clk_ops ccu_rodiv_ops = {
+ .disable = ccu_div_disable,
+ .enable = ccu_div_enable,
+ .is_enabled = ccu_div_is_enabled,
+
+ .get_parent = ccu_div_get_parent,
+ .set_parent = ccu_div_set_parent,
+
+ .determine_rate = ccu_div_determine_rate,
+ .recalc_rate = ccu_div_recalc_rate,
+};
+EXPORT_SYMBOL_NS_GPL(ccu_rodiv_ops, "SUNXI_CCU");
diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h
index be00b3277e97..a30a92780a05 100644
--- a/drivers/clk/sunxi-ng/ccu_div.h
+++ b/drivers/clk/sunxi-ng/ccu_div.h
@@ -300,5 +300,6 @@ static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
}
extern const struct clk_ops ccu_div_ops;
+extern const struct clk_ops ccu_rodiv_ops;
#endif /* _CCU_DIV_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
index 766f27cff748..4503c9780c39 100644
--- a/drivers/clk/sunxi-ng/ccu_mux.c
+++ b/drivers/clk/sunxi-ng/ccu_mux.c
@@ -66,7 +66,6 @@ unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
{
return parent_rate / ccu_mux_get_prediv(common, cm, parent_index);
}
-EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, "SUNXI_CCU");
static unsigned long ccu_mux_helper_unapply_prediv(struct ccu_common *common,
struct ccu_mux_internal *cm,
@@ -93,66 +92,65 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common,
struct clk_rate_request adj_req = *req;
best_parent = clk_hw_get_parent(hw);
- best_parent_rate = clk_hw_get_rate(best_parent);
-
+ adj_req.best_parent_rate = clk_hw_get_rate(best_parent);
adj_req.best_parent_hw = best_parent;
- adj_req.best_parent_rate = ccu_mux_helper_apply_prediv(common, cm, -1,
- best_parent_rate);
+
+ /*
+ * This effectively treats the predivider as a postdivider.
+ * It stays mathematically correct and ensures whatever
+ * round() will do stays correct while walking the tree.
+ * It may query the parent rate too while handling rate
+ * propagation.
+ */
+ adj_req.rate = ccu_mux_helper_unapply_prediv(common, cm, -1,
+ req->rate);
ret = round(cm, &adj_req, data);
if (ret)
return ret;
- best_rate = adj_req.rate;
-
/*
- * best_parent_rate might have been modified by our clock.
- * Unapply the pre-divider if there's one, and give
- * the actual frequency the parent needs to run at.
+ * parent_rate might have been modified by our clock as part
+ * of the rate propagation mechanism. Same goes below.
*/
- best_parent_rate = ccu_mux_helper_unapply_prediv(common, cm, -1,
- adj_req.best_parent_rate);
+ best_parent_rate = adj_req.best_parent_rate;
+ best_rate = ccu_mux_helper_apply_prediv(common, cm, -1,
+ adj_req.rate);
goto out;
}
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
struct clk_rate_request tmp_req = *req;
- unsigned long parent_rate;
+ unsigned long rate;
struct clk_hw *parent;
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
- parent_rate = ccu_mux_helper_apply_prediv(common, cm, i,
- clk_hw_get_rate(parent));
-
tmp_req.best_parent_hw = parent;
- tmp_req.best_parent_rate = parent_rate;
+ tmp_req.best_parent_rate = clk_hw_get_rate(parent);
+ tmp_req.rate = ccu_mux_helper_unapply_prediv(common, cm, i,
+ req->rate);
ret = round(cm, &tmp_req, data);
if (ret)
continue;
- /*
- * parent_rate might have been modified by our clock.
- * Unapply the pre-divider if there's one, and give
- * the actual frequency the parent needs to run at.
- */
- parent_rate = ccu_mux_helper_unapply_prediv(common, cm, i,
- tmp_req.best_parent_rate);
+ rate = ccu_mux_helper_apply_prediv(common, cm, i,
+ tmp_req.rate);
- if (tmp_req.rate == req->rate) {
+ if (rate == req->rate) {
best_parent = parent;
- best_parent_rate = parent_rate;
- best_rate = tmp_req.rate;
+ best_parent_rate = tmp_req.best_parent_rate;
+ best_rate = rate;
goto out;
}
- if (ccu_is_better_rate(common, req->rate, tmp_req.rate, best_rate)) {
- best_rate = tmp_req.rate;
- best_parent_rate = parent_rate;
+ if (ccu_is_better_rate(common, req->rate, rate, best_rate)) {
+ best_rate = rate;
+ best_parent_rate = tmp_req.best_parent_rate;
best_parent = parent;
}
}
diff --git a/include/dt-bindings/clock/sun6i-rtc.h b/include/dt-bindings/clock/sun6i-rtc.h
index 3bd3aa3d57ce..5132a393ca4b 100644
--- a/include/dt-bindings/clock/sun6i-rtc.h
+++ b/include/dt-bindings/clock/sun6i-rtc.h
@@ -6,5 +6,9 @@
#define CLK_OSC32K 0
#define CLK_OSC32K_FANOUT 1
#define CLK_IOSC 2
+#define CLK_HOSC_UFS 8
+#define CLK_HOSC_HDMI 9
+#define CLK_HOSC_SERDES0 10
+#define CLK_HOSC_SERDES1 11
#endif /* _DT_BINDINGS_CLK_SUN6I_RTC_H_ */