clk: sunxi-ng: nm: Support finding closest rate
authorFrank Oltmanns <frank@oltmanns.dev>
Mon, 7 Aug 2023 12:43:39 +0000 (14:43 +0200)
committerChen-Yu Tsai <wens@csie.org>
Wed, 9 Aug 2023 15:33:58 +0000 (23:33 +0800)
Use the helper function ccu_is_better_rate() to determine the rate that
is closest to the requested rate, thereby supporting rates that are
higher than the requested rate if the clock uses the
CCU_FEATURE_CLOSEST_RATE.

Add the macro SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST which
sets CCU_FEATURE_CLOSEST_RATE.

To avoid code duplication, add the macros
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT that allows selecting
arbitrary features and use it in the original
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX as well as the newly introduced
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST macros.

Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Frank Oltmanns <frank@oltmanns.dev>
Link: https://lore.kernel.org/r/20230807-pll-mipi_set_rate_parent-v6-6-f173239a4b59@oltmanns.dev
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
drivers/clk/sunxi-ng/ccu_nm.c
drivers/clk/sunxi-ng/ccu_nm.h

index c1fd11542c455038438cdcc20b5f53d41000e3dc..ffac3deb89d6621e992882898eac62cb034da745 100644 (file)
@@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent,
        return rate;
 }
 
-static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
-                                     struct _ccu_nm *nm)
+static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned long parent,
+                                     unsigned long rate, struct _ccu_nm *nm)
 {
        unsigned long best_rate = 0;
        unsigned long best_n = 0, best_m = 0;
@@ -39,10 +39,7 @@ static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
                        unsigned long tmp_rate = ccu_nm_calc_rate(parent,
                                                                  _n, _m);
 
-                       if (tmp_rate > rate)
-                               continue;
-
-                       if ((rate - tmp_rate) < (rate - best_rate)) {
+                       if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
                                best_rate = tmp_rate;
                                best_n = _n;
                                best_m = _m;
@@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
        _nm.min_m = 1;
        _nm.max_m = nm->m.max ?: 1 << nm->m.width;
 
-       rate = ccu_nm_find_best(*parent_rate, rate, &_nm);
+       rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm);
 
        if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
                rate /= nm->fixed_post_div;
@@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
                                           &_nm.m, &_nm.n);
        } else {
                ccu_sdm_helper_disable(&nm->common, &nm->sdm);
-               ccu_nm_find_best(parent_rate, rate, &_nm);
+               ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm);
        }
 
        spin_lock_irqsave(nm->common.lock, flags);
index 2904e67f05a81057870a79a3ef75ed6f8c1d46fc..93c11693574f6d3dd916f76290f36c6565ad82a9 100644 (file)
@@ -108,7 +108,7 @@ struct ccu_nm {
                },                                                      \
        }
 
-#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name,       \
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name,  \
                                                 _parent, _reg,         \
                                                 _min_rate, _max_rate,  \
                                                 _nshift, _nwidth,      \
@@ -116,7 +116,8 @@ struct ccu_nm {
                                                 _frac_en, _frac_sel,   \
                                                 _frac_rate_0,          \
                                                 _frac_rate_1,          \
-                                                _gate, _lock, _flags)  \
+                                                _gate, _lock, _flags,  \
+                                                _features)             \
        struct ccu_nm _struct = {                                       \
                .enable         = _gate,                                \
                .lock           = _lock,                                \
@@ -129,7 +130,7 @@ struct ccu_nm {
                .max_rate       = _max_rate,                            \
                .common         = {                                     \
                        .reg            = _reg,                         \
-                       .features       = CCU_FEATURE_FRACTIONAL,       \
+                       .features       = _features,                    \
                        .hw.init        = CLK_HW_INIT(_name,            \
                                                      _parent,          \
                                                      &ccu_nm_ops,      \
@@ -137,6 +138,47 @@ struct ccu_nm {
                },                                                      \
        }
 
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name,       \
+                                                _parent, _reg,         \
+                                                _min_rate, _max_rate,  \
+                                                _nshift, _nwidth,      \
+                                                _mshift, _mwidth,      \
+                                                _frac_en, _frac_sel,   \
+                                                _frac_rate_0,          \
+                                                _frac_rate_1,          \
+                                                _gate, _lock, _flags)  \
+       SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name,   \
+                                               _parent, _reg,          \
+                                               _min_rate, _max_rate,   \
+                                               _nshift, _nwidth,       \
+                                               _mshift, _mwidth,       \
+                                               _frac_en, _frac_sel,    \
+                                               _frac_rate_0,           \
+                                               _frac_rate_1,           \
+                                               _gate, _lock, _flags,   \
+                                               CCU_FEATURE_FRACTIONAL)
+
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(_struct, _name, \
+                                                _parent, _reg,         \
+                                                _min_rate, _max_rate,  \
+                                                _nshift, _nwidth,      \
+                                                _mshift, _mwidth,      \
+                                                _frac_en, _frac_sel,   \
+                                                _frac_rate_0,          \
+                                                _frac_rate_1,          \
+                                                _gate, _lock, _flags)  \
+       SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name,   \
+                                               _parent, _reg,          \
+                                               _min_rate, _max_rate,   \
+                                               _nshift, _nwidth,       \
+                                               _mshift, _mwidth,       \
+                                               _frac_en, _frac_sel,    \
+                                               _frac_rate_0,           \
+                                               _frac_rate_1,           \
+                                               _gate, _lock, _flags,   \
+                                               CCU_FEATURE_FRACTIONAL |\
+                                               CCU_FEATURE_CLOSEST_RATE)
+
 #define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg,     \
                                    _nshift, _nwidth,                   \
                                    _mshift, _mwidth,                   \