clk: meson: mpll: add round closest support
authorJerome Brunet <jbrunet@baylibre.com>
Tue, 15 May 2018 16:36:51 +0000 (18:36 +0200)
committerJerome Brunet <jbrunet@baylibre.com>
Mon, 21 May 2018 09:31:29 +0000 (11:31 +0200)
Allow the mpll driver to round the requested rate up if
CLK_MESON_MPLL_ROUND_CLOSEST is set and it provides a rate closer to the
requested rate.

Acked-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Martin Blumenstingl<martin.blumenstingl@googlemail.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
drivers/clk/meson/clk-mpll.c
drivers/clk/meson/clkc.h

index 45c3a2261f2fbccb2fbfff4c49cb7ea9975ec8c9..650f75cc15a93f6a3f41a4a50262c144cffd8320 100644 (file)
@@ -39,10 +39,23 @@ static long rate_from_params(unsigned long parent_rate,
 static void params_from_rate(unsigned long requested_rate,
                             unsigned long parent_rate,
                             unsigned int *sdm,
-                            unsigned int *n2)
+                            unsigned int *n2,
+                            u8 flags)
 {
        uint64_t div = parent_rate;
-       unsigned long rem = do_div(div, requested_rate);
+       uint64_t frac = do_div(div, requested_rate);
+
+       frac *= SDM_DEN;
+
+       if (flags & CLK_MESON_MPLL_ROUND_CLOSEST)
+               *sdm = DIV_ROUND_CLOSEST_ULL(frac, requested_rate);
+       else
+               *sdm = DIV_ROUND_UP_ULL(frac, requested_rate);
+
+       if (*sdm == SDM_DEN) {
+               *sdm = 0;
+               div += 1;
+       }
 
        if (div < N2_MIN) {
                *n2 = N2_MIN;
@@ -52,7 +65,6 @@ static void params_from_rate(unsigned long requested_rate,
                *sdm = SDM_DEN - 1;
        } else {
                *n2 = div;
-               *sdm = DIV_ROUND_UP_ULL((u64)rem * SDM_DEN, requested_rate);
        }
 }
 
@@ -75,9 +87,11 @@ static long mpll_round_rate(struct clk_hw *hw,
                            unsigned long rate,
                            unsigned long *parent_rate)
 {
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
        unsigned int sdm, n2;
 
-       params_from_rate(rate, *parent_rate, &sdm, &n2);
+       params_from_rate(rate, *parent_rate, &sdm, &n2, mpll->flags);
        return rate_from_params(*parent_rate, sdm, n2);
 }
 
@@ -90,7 +104,7 @@ static int mpll_set_rate(struct clk_hw *hw,
        unsigned int sdm, n2;
        unsigned long flags = 0;
 
-       params_from_rate(rate, parent_rate, &sdm, &n2);
+       params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags);
 
        if (mpll->lock)
                spin_lock_irqsave(mpll->lock, flags);
index 7b90c9748c73eb583da5e831765b7040f06bd83c..2fb084330ee9882abe9916d5fdf5e0a9c27ffc13 100644 (file)
@@ -86,8 +86,11 @@ struct meson_clk_mpll_data {
        struct parm ssen;
        struct parm misc;
        spinlock_t *lock;
+       u8 flags;
 };
 
+#define CLK_MESON_MPLL_ROUND_CLOSEST   BIT(0)
+
 struct meson_clk_audio_div_data {
        struct parm div;
        u8 flags;