LCOV - code coverage report
Current view: top level - drivers/clk - clk-multiplier.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 0 46 0.0 %
Date: 2020-09-30 20:25:01 Functions: 0 4 0.0 %
Branches: 0 32 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <linux/bitops.h>
       7                 :            : #include <linux/clk-provider.h>
       8                 :            : #include <linux/err.h>
       9                 :            : #include <linux/export.h>
      10                 :            : #include <linux/io.h>
      11                 :            : #include <linux/kernel.h>
      12                 :            : #include <linux/of.h>
      13                 :            : #include <linux/slab.h>
      14                 :            : 
      15                 :            : static inline u32 clk_mult_readl(struct clk_multiplier *mult)
      16                 :            : {
      17   [ #  #  #  # ]:          0 :         if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
      18                 :          0 :                 return ioread32be(mult->reg);
      19                 :            : 
      20                 :          0 :         return readl(mult->reg);
      21                 :            : }
      22                 :            : 
      23                 :            : static inline void clk_mult_writel(struct clk_multiplier *mult, u32 val)
      24                 :            : {
      25         [ #  # ]:          0 :         if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
      26                 :          0 :                 iowrite32be(val, mult->reg);
      27                 :            :         else
      28                 :          0 :                 writel(val, mult->reg);
      29                 :            : }
      30                 :            : 
      31                 :            : static unsigned long __get_mult(struct clk_multiplier *mult,
      32                 :            :                                 unsigned long rate,
      33                 :            :                                 unsigned long parent_rate)
      34                 :            : {
      35         [ #  # ]:          0 :         if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST)
      36                 :          0 :                 return DIV_ROUND_CLOSEST(rate, parent_rate);
      37                 :            : 
      38                 :          0 :         return rate / parent_rate;
      39                 :            : }
      40                 :            : 
      41                 :          0 : static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
      42                 :            :                                                 unsigned long parent_rate)
      43                 :            : {
      44                 :            :         struct clk_multiplier *mult = to_clk_multiplier(hw);
      45                 :            :         unsigned long val;
      46                 :            : 
      47                 :          0 :         val = clk_mult_readl(mult) >> mult->shift;
      48                 :          0 :         val &= GENMASK(mult->width - 1, 0);
      49                 :            : 
      50   [ #  #  #  # ]:          0 :         if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
      51                 :            :                 val = 1;
      52                 :            : 
      53                 :          0 :         return parent_rate * val;
      54                 :            : }
      55                 :            : 
      56                 :            : static bool __is_best_rate(unsigned long rate, unsigned long new,
      57                 :            :                            unsigned long best, unsigned long flags)
      58                 :            : {
      59         [ #  # ]:          0 :         if (flags & CLK_MULTIPLIER_ROUND_CLOSEST)
      60                 :          0 :                 return abs(rate - new) < abs(rate - best);
      61                 :            : 
      62                 :          0 :         return new >= rate && new < best;
      63                 :            : }
      64                 :            : 
      65                 :          0 : static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
      66                 :            :                                 unsigned long *best_parent_rate,
      67                 :            :                                 u8 width, unsigned long flags)
      68                 :            : {
      69                 :            :         struct clk_multiplier *mult = to_clk_multiplier(hw);
      70                 :          0 :         unsigned long orig_parent_rate = *best_parent_rate;
      71                 :            :         unsigned long parent_rate, current_rate, best_rate = ~0;
      72                 :            :         unsigned int i, bestmult = 0;
      73                 :          0 :         unsigned int maxmult = (1 << width) - 1;
      74                 :            : 
      75         [ #  # ]:          0 :         if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
      76                 :          0 :                 bestmult = rate / orig_parent_rate;
      77                 :            : 
      78                 :            :                 /* Make sure we don't end up with a 0 multiplier */
      79   [ #  #  #  # ]:          0 :                 if ((bestmult == 0) &&
      80                 :          0 :                     !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
      81                 :            :                         bestmult = 1;
      82                 :            : 
      83                 :            :                 /* Make sure we don't overflow the multiplier */
      84         [ #  # ]:          0 :                 if (bestmult > maxmult)
      85                 :            :                         bestmult = maxmult;
      86                 :            : 
      87                 :          0 :                 return bestmult;
      88                 :            :         }
      89                 :            : 
      90         [ #  # ]:          0 :         for (i = 1; i < maxmult; i++) {
      91         [ #  # ]:          0 :                 if (rate == orig_parent_rate * i) {
      92                 :            :                         /*
      93                 :            :                          * This is the best case for us if we have a
      94                 :            :                          * perfect match without changing the parent
      95                 :            :                          * rate.
      96                 :            :                          */
      97                 :          0 :                         *best_parent_rate = orig_parent_rate;
      98                 :          0 :                         return i;
      99                 :            :                 }
     100                 :            : 
     101                 :          0 :                 parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
     102                 :            :                                                 rate / i);
     103                 :          0 :                 current_rate = parent_rate * i;
     104                 :            : 
     105         [ #  # ]:          0 :                 if (__is_best_rate(rate, current_rate, best_rate, flags)) {
     106                 :            :                         bestmult = i;
     107                 :            :                         best_rate = current_rate;
     108                 :          0 :                         *best_parent_rate = parent_rate;
     109                 :            :                 }
     110                 :            :         }
     111                 :            : 
     112                 :          0 :         return bestmult;
     113                 :            : }
     114                 :            : 
     115                 :          0 : static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
     116                 :            :                                   unsigned long *parent_rate)
     117                 :            : {
     118                 :            :         struct clk_multiplier *mult = to_clk_multiplier(hw);
     119                 :          0 :         unsigned long factor = __bestmult(hw, rate, parent_rate,
     120                 :          0 :                                           mult->width, mult->flags);
     121                 :            : 
     122                 :          0 :         return *parent_rate * factor;
     123                 :            : }
     124                 :            : 
     125                 :          0 : static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
     126                 :            :                                unsigned long parent_rate)
     127                 :            : {
     128                 :            :         struct clk_multiplier *mult = to_clk_multiplier(hw);
     129                 :            :         unsigned long factor = __get_mult(mult, rate, parent_rate);
     130                 :            :         unsigned long flags = 0;
     131                 :            :         unsigned long val;
     132                 :            : 
     133         [ #  # ]:          0 :         if (mult->lock)
     134                 :          0 :                 spin_lock_irqsave(mult->lock, flags);
     135                 :            :         else
     136                 :            :                 __acquire(mult->lock);
     137                 :            : 
     138                 :            :         val = clk_mult_readl(mult);
     139                 :          0 :         val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
     140                 :          0 :         val |= factor << mult->shift;
     141                 :            :         clk_mult_writel(mult, val);
     142                 :            : 
     143         [ #  # ]:          0 :         if (mult->lock)
     144                 :            :                 spin_unlock_irqrestore(mult->lock, flags);
     145                 :            :         else
     146                 :            :                 __release(mult->lock);
     147                 :            : 
     148                 :          0 :         return 0;
     149                 :            : }
     150                 :            : 
     151                 :            : const struct clk_ops clk_multiplier_ops = {
     152                 :            :         .recalc_rate    = clk_multiplier_recalc_rate,
     153                 :            :         .round_rate     = clk_multiplier_round_rate,
     154                 :            :         .set_rate       = clk_multiplier_set_rate,
     155                 :            : };
     156                 :            : EXPORT_SYMBOL_GPL(clk_multiplier_ops);

Generated by: LCOV version 1.14