root/drivers/clk/sunxi-ng/ccu_div.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ccu_div_round_rate
  2. ccu_div_disable
  3. ccu_div_enable
  4. ccu_div_is_enabled
  5. ccu_div_recalc_rate
  6. ccu_div_determine_rate
  7. ccu_div_set_rate
  8. ccu_div_get_parent
  9. ccu_div_set_parent

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2016 Maxime Ripard
   4  * Maxime Ripard <maxime.ripard@free-electrons.com>
   5  */
   6 
   7 #include <linux/clk-provider.h>
   8 #include <linux/io.h>
   9 
  10 #include "ccu_gate.h"
  11 #include "ccu_div.h"
  12 
  13 static unsigned long ccu_div_round_rate(struct ccu_mux_internal *mux,
  14                                         struct clk_hw *parent,
  15                                         unsigned long *parent_rate,
  16                                         unsigned long rate,
  17                                         void *data)
  18 {
  19         struct ccu_div *cd = data;
  20 
  21         if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
  22                 rate *= cd->fixed_post_div;
  23 
  24         rate = divider_round_rate_parent(&cd->common.hw, parent,
  25                                          rate, parent_rate,
  26                                          cd->div.table, cd->div.width,
  27                                          cd->div.flags);
  28 
  29         if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
  30                 rate /= cd->fixed_post_div;
  31 
  32         return rate;
  33 }
  34 
  35 static void ccu_div_disable(struct clk_hw *hw)
  36 {
  37         struct ccu_div *cd = hw_to_ccu_div(hw);
  38 
  39         return ccu_gate_helper_disable(&cd->common, cd->enable);
  40 }
  41 
  42 static int ccu_div_enable(struct clk_hw *hw)
  43 {
  44         struct ccu_div *cd = hw_to_ccu_div(hw);
  45 
  46         return ccu_gate_helper_enable(&cd->common, cd->enable);
  47 }
  48 
  49 static int ccu_div_is_enabled(struct clk_hw *hw)
  50 {
  51         struct ccu_div *cd = hw_to_ccu_div(hw);
  52 
  53         return ccu_gate_helper_is_enabled(&cd->common, cd->enable);
  54 }
  55 
  56 static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
  57                                         unsigned long parent_rate)
  58 {
  59         struct ccu_div *cd = hw_to_ccu_div(hw);
  60         unsigned long val;
  61         u32 reg;
  62 
  63         reg = readl(cd->common.base + cd->common.reg);
  64         val = reg >> cd->div.shift;
  65         val &= (1 << cd->div.width) - 1;
  66 
  67         parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
  68                                                   parent_rate);
  69 
  70         val = divider_recalc_rate(hw, parent_rate, val, cd->div.table,
  71                                   cd->div.flags, cd->div.width);
  72 
  73         if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
  74                 val /= cd->fixed_post_div;
  75 
  76         return val;
  77 }
  78 
  79 static int ccu_div_determine_rate(struct clk_hw *hw,
  80                                 struct clk_rate_request *req)
  81 {
  82         struct ccu_div *cd = hw_to_ccu_div(hw);
  83 
  84         return ccu_mux_helper_determine_rate(&cd->common, &cd->mux,
  85                                              req, ccu_div_round_rate, cd);
  86 }
  87 
  88 static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
  89                            unsigned long parent_rate)
  90 {
  91         struct ccu_div *cd = hw_to_ccu_div(hw);
  92         unsigned long flags;
  93         unsigned long val;
  94         u32 reg;
  95 
  96         parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
  97                                                   parent_rate);
  98 
  99         if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
 100                 rate *= cd->fixed_post_div;
 101 
 102         val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
 103                               cd->div.flags);
 104 
 105         spin_lock_irqsave(cd->common.lock, flags);
 106 
 107         reg = readl(cd->common.base + cd->common.reg);
 108         reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
 109 
 110         writel(reg | (val << cd->div.shift),
 111                cd->common.base + cd->common.reg);
 112 
 113         spin_unlock_irqrestore(cd->common.lock, flags);
 114 
 115         return 0;
 116 }
 117 
 118 static u8 ccu_div_get_parent(struct clk_hw *hw)
 119 {
 120         struct ccu_div *cd = hw_to_ccu_div(hw);
 121 
 122         return ccu_mux_helper_get_parent(&cd->common, &cd->mux);
 123 }
 124 
 125 static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
 126 {
 127         struct ccu_div *cd = hw_to_ccu_div(hw);
 128 
 129         return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
 130 }
 131 
 132 const struct clk_ops ccu_div_ops = {
 133         .disable        = ccu_div_disable,
 134         .enable         = ccu_div_enable,
 135         .is_enabled     = ccu_div_is_enabled,
 136 
 137         .get_parent     = ccu_div_get_parent,
 138         .set_parent     = ccu_div_set_parent,
 139 
 140         .determine_rate = ccu_div_determine_rate,
 141         .recalc_rate    = ccu_div_recalc_rate,
 142         .set_rate       = ccu_div_set_rate,
 143 };

/* [<][>][^][v][top][bottom][index][help] */