root/drivers/clk/qcom/clk-hfpll.c

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

DEFINITIONS

This source file includes following definitions.
  1. __clk_hfpll_init_once
  2. __clk_hfpll_enable
  3. clk_hfpll_enable
  4. __clk_hfpll_disable
  5. clk_hfpll_disable
  6. clk_hfpll_round_rate
  7. clk_hfpll_set_rate
  8. clk_hfpll_recalc_rate
  9. clk_hfpll_init
  10. hfpll_is_enabled

   1 // SPDX-License-Identifier: GPL-2.0
   2 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
   3 
   4 #include <linux/kernel.h>
   5 #include <linux/export.h>
   6 #include <linux/regmap.h>
   7 #include <linux/delay.h>
   8 #include <linux/err.h>
   9 #include <linux/clk-provider.h>
  10 #include <linux/spinlock.h>
  11 
  12 #include "clk-regmap.h"
  13 #include "clk-hfpll.h"
  14 
  15 #define PLL_OUTCTRL     BIT(0)
  16 #define PLL_BYPASSNL    BIT(1)
  17 #define PLL_RESET_N     BIT(2)
  18 
  19 /* Initialize a HFPLL at a given rate and enable it. */
  20 static void __clk_hfpll_init_once(struct clk_hw *hw)
  21 {
  22         struct clk_hfpll *h = to_clk_hfpll(hw);
  23         struct hfpll_data const *hd = h->d;
  24         struct regmap *regmap = h->clkr.regmap;
  25 
  26         if (likely(h->init_done))
  27                 return;
  28 
  29         /* Configure PLL parameters for integer mode. */
  30         if (hd->config_val)
  31                 regmap_write(regmap, hd->config_reg, hd->config_val);
  32         regmap_write(regmap, hd->m_reg, 0);
  33         regmap_write(regmap, hd->n_reg, 1);
  34 
  35         if (hd->user_reg) {
  36                 u32 regval = hd->user_val;
  37                 unsigned long rate;
  38 
  39                 rate = clk_hw_get_rate(hw);
  40 
  41                 /* Pick the right VCO. */
  42                 if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
  43                         regval |= hd->user_vco_mask;
  44                 regmap_write(regmap, hd->user_reg, regval);
  45         }
  46 
  47         if (hd->droop_reg)
  48                 regmap_write(regmap, hd->droop_reg, hd->droop_val);
  49 
  50         h->init_done = true;
  51 }
  52 
  53 static void __clk_hfpll_enable(struct clk_hw *hw)
  54 {
  55         struct clk_hfpll *h = to_clk_hfpll(hw);
  56         struct hfpll_data const *hd = h->d;
  57         struct regmap *regmap = h->clkr.regmap;
  58         u32 val;
  59 
  60         __clk_hfpll_init_once(hw);
  61 
  62         /* Disable PLL bypass mode. */
  63         regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
  64 
  65         /*
  66          * H/W requires a 5us delay between disabling the bypass and
  67          * de-asserting the reset. Delay 10us just to be safe.
  68          */
  69         udelay(10);
  70 
  71         /* De-assert active-low PLL reset. */
  72         regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
  73 
  74         /* Wait for PLL to lock. */
  75         if (hd->status_reg) {
  76                 do {
  77                         regmap_read(regmap, hd->status_reg, &val);
  78                 } while (!(val & BIT(hd->lock_bit)));
  79         } else {
  80                 udelay(60);
  81         }
  82 
  83         /* Enable PLL output. */
  84         regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
  85 }
  86 
  87 /* Enable an already-configured HFPLL. */
  88 static int clk_hfpll_enable(struct clk_hw *hw)
  89 {
  90         unsigned long flags;
  91         struct clk_hfpll *h = to_clk_hfpll(hw);
  92         struct hfpll_data const *hd = h->d;
  93         struct regmap *regmap = h->clkr.regmap;
  94         u32 mode;
  95 
  96         spin_lock_irqsave(&h->lock, flags);
  97         regmap_read(regmap, hd->mode_reg, &mode);
  98         if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
  99                 __clk_hfpll_enable(hw);
 100         spin_unlock_irqrestore(&h->lock, flags);
 101 
 102         return 0;
 103 }
 104 
 105 static void __clk_hfpll_disable(struct clk_hfpll *h)
 106 {
 107         struct hfpll_data const *hd = h->d;
 108         struct regmap *regmap = h->clkr.regmap;
 109 
 110         /*
 111          * Disable the PLL output, disable test mode, enable the bypass mode,
 112          * and assert the reset.
 113          */
 114         regmap_update_bits(regmap, hd->mode_reg,
 115                            PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
 116 }
 117 
 118 static void clk_hfpll_disable(struct clk_hw *hw)
 119 {
 120         struct clk_hfpll *h = to_clk_hfpll(hw);
 121         unsigned long flags;
 122 
 123         spin_lock_irqsave(&h->lock, flags);
 124         __clk_hfpll_disable(h);
 125         spin_unlock_irqrestore(&h->lock, flags);
 126 }
 127 
 128 static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
 129                                  unsigned long *parent_rate)
 130 {
 131         struct clk_hfpll *h = to_clk_hfpll(hw);
 132         struct hfpll_data const *hd = h->d;
 133         unsigned long rrate;
 134 
 135         rate = clamp(rate, hd->min_rate, hd->max_rate);
 136 
 137         rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
 138         if (rrate > hd->max_rate)
 139                 rrate -= *parent_rate;
 140 
 141         return rrate;
 142 }
 143 
 144 /*
 145  * For optimization reasons, assumes no downstream clocks are actively using
 146  * it.
 147  */
 148 static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
 149                               unsigned long parent_rate)
 150 {
 151         struct clk_hfpll *h = to_clk_hfpll(hw);
 152         struct hfpll_data const *hd = h->d;
 153         struct regmap *regmap = h->clkr.regmap;
 154         unsigned long flags;
 155         u32 l_val, val;
 156         bool enabled;
 157 
 158         l_val = rate / parent_rate;
 159 
 160         spin_lock_irqsave(&h->lock, flags);
 161 
 162         enabled = __clk_is_enabled(hw->clk);
 163         if (enabled)
 164                 __clk_hfpll_disable(h);
 165 
 166         /* Pick the right VCO. */
 167         if (hd->user_reg && hd->user_vco_mask) {
 168                 regmap_read(regmap, hd->user_reg, &val);
 169                 if (rate <= hd->low_vco_max_rate)
 170                         val &= ~hd->user_vco_mask;
 171                 else
 172                         val |= hd->user_vco_mask;
 173                 regmap_write(regmap, hd->user_reg, val);
 174         }
 175 
 176         regmap_write(regmap, hd->l_reg, l_val);
 177 
 178         if (enabled)
 179                 __clk_hfpll_enable(hw);
 180 
 181         spin_unlock_irqrestore(&h->lock, flags);
 182 
 183         return 0;
 184 }
 185 
 186 static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
 187                                            unsigned long parent_rate)
 188 {
 189         struct clk_hfpll *h = to_clk_hfpll(hw);
 190         struct hfpll_data const *hd = h->d;
 191         struct regmap *regmap = h->clkr.regmap;
 192         u32 l_val;
 193 
 194         regmap_read(regmap, hd->l_reg, &l_val);
 195 
 196         return l_val * parent_rate;
 197 }
 198 
 199 static void clk_hfpll_init(struct clk_hw *hw)
 200 {
 201         struct clk_hfpll *h = to_clk_hfpll(hw);
 202         struct hfpll_data const *hd = h->d;
 203         struct regmap *regmap = h->clkr.regmap;
 204         u32 mode, status;
 205 
 206         regmap_read(regmap, hd->mode_reg, &mode);
 207         if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
 208                 __clk_hfpll_init_once(hw);
 209                 return;
 210         }
 211 
 212         if (hd->status_reg) {
 213                 regmap_read(regmap, hd->status_reg, &status);
 214                 if (!(status & BIT(hd->lock_bit))) {
 215                         WARN(1, "HFPLL %s is ON, but not locked!\n",
 216                              __clk_get_name(hw->clk));
 217                         clk_hfpll_disable(hw);
 218                         __clk_hfpll_init_once(hw);
 219                 }
 220         }
 221 }
 222 
 223 static int hfpll_is_enabled(struct clk_hw *hw)
 224 {
 225         struct clk_hfpll *h = to_clk_hfpll(hw);
 226         struct hfpll_data const *hd = h->d;
 227         struct regmap *regmap = h->clkr.regmap;
 228         u32 mode;
 229 
 230         regmap_read(regmap, hd->mode_reg, &mode);
 231         mode &= 0x7;
 232         return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
 233 }
 234 
 235 const struct clk_ops clk_ops_hfpll = {
 236         .enable = clk_hfpll_enable,
 237         .disable = clk_hfpll_disable,
 238         .is_enabled = hfpll_is_enabled,
 239         .round_rate = clk_hfpll_round_rate,
 240         .set_rate = clk_hfpll_set_rate,
 241         .recalc_rate = clk_hfpll_recalc_rate,
 242         .init = clk_hfpll_init,
 243 };
 244 EXPORT_SYMBOL_GPL(clk_ops_hfpll);

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