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

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

DEFINITIONS

This source file includes following definitions.
  1. ccu_sdm_helper_is_enabled
  2. ccu_sdm_helper_enable
  3. ccu_sdm_helper_disable
  4. ccu_sdm_helper_has_rate
  5. ccu_sdm_helper_read_rate
  6. ccu_sdm_helper_get_factors

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
   4  */
   5 
   6 #include <linux/clk-provider.h>
   7 #include <linux/io.h>
   8 #include <linux/spinlock.h>
   9 
  10 #include "ccu_sdm.h"
  11 
  12 bool ccu_sdm_helper_is_enabled(struct ccu_common *common,
  13                                struct ccu_sdm_internal *sdm)
  14 {
  15         if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
  16                 return false;
  17 
  18         if (sdm->enable && !(readl(common->base + common->reg) & sdm->enable))
  19                 return false;
  20 
  21         return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable);
  22 }
  23 
  24 void ccu_sdm_helper_enable(struct ccu_common *common,
  25                            struct ccu_sdm_internal *sdm,
  26                            unsigned long rate)
  27 {
  28         unsigned long flags;
  29         unsigned int i;
  30         u32 reg;
  31 
  32         if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
  33                 return;
  34 
  35         /* Set the pattern */
  36         for (i = 0; i < sdm->table_size; i++)
  37                 if (sdm->table[i].rate == rate)
  38                         writel(sdm->table[i].pattern,
  39                                common->base + sdm->tuning_reg);
  40 
  41         /* Make sure SDM is enabled */
  42         spin_lock_irqsave(common->lock, flags);
  43         reg = readl(common->base + sdm->tuning_reg);
  44         writel(reg | sdm->tuning_enable, common->base + sdm->tuning_reg);
  45         spin_unlock_irqrestore(common->lock, flags);
  46 
  47         spin_lock_irqsave(common->lock, flags);
  48         reg = readl(common->base + common->reg);
  49         writel(reg | sdm->enable, common->base + common->reg);
  50         spin_unlock_irqrestore(common->lock, flags);
  51 }
  52 
  53 void ccu_sdm_helper_disable(struct ccu_common *common,
  54                             struct ccu_sdm_internal *sdm)
  55 {
  56         unsigned long flags;
  57         u32 reg;
  58 
  59         if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
  60                 return;
  61 
  62         spin_lock_irqsave(common->lock, flags);
  63         reg = readl(common->base + common->reg);
  64         writel(reg & ~sdm->enable, common->base + common->reg);
  65         spin_unlock_irqrestore(common->lock, flags);
  66 
  67         spin_lock_irqsave(common->lock, flags);
  68         reg = readl(common->base + sdm->tuning_reg);
  69         writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg);
  70         spin_unlock_irqrestore(common->lock, flags);
  71 }
  72 
  73 /*
  74  * Sigma delta modulation provides a way to do fractional-N frequency
  75  * synthesis, in essence allowing the PLL to output any frequency
  76  * within its operational range. On earlier SoCs such as the A10/A20,
  77  * some PLLs support this. On later SoCs, all PLLs support this.
  78  *
  79  * The datasheets do not explain what the "wave top" and "wave bottom"
  80  * parameters mean or do, nor how to calculate the effective output
  81  * frequency. The only examples (and real world usage) are for the audio
  82  * PLL to generate 24.576 and 22.5792 MHz clock rates used by the audio
  83  * peripherals. The author lacks the underlying domain knowledge to
  84  * pursue this.
  85  *
  86  * The goal and function of the following code is to support the two
  87  * clock rates used by the audio subsystem, allowing for proper audio
  88  * playback and capture without any pitch or speed changes.
  89  */
  90 bool ccu_sdm_helper_has_rate(struct ccu_common *common,
  91                              struct ccu_sdm_internal *sdm,
  92                              unsigned long rate)
  93 {
  94         unsigned int i;
  95 
  96         if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
  97                 return false;
  98 
  99         for (i = 0; i < sdm->table_size; i++)
 100                 if (sdm->table[i].rate == rate)
 101                         return true;
 102 
 103         return false;
 104 }
 105 
 106 unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
 107                                        struct ccu_sdm_internal *sdm,
 108                                        u32 m, u32 n)
 109 {
 110         unsigned int i;
 111         u32 reg;
 112 
 113         pr_debug("%s: Read sigma-delta modulation setting\n",
 114                  clk_hw_get_name(&common->hw));
 115 
 116         if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
 117                 return 0;
 118 
 119         pr_debug("%s: clock is sigma-delta modulated\n",
 120                  clk_hw_get_name(&common->hw));
 121 
 122         reg = readl(common->base + sdm->tuning_reg);
 123 
 124         pr_debug("%s: pattern reg is 0x%x",
 125                  clk_hw_get_name(&common->hw), reg);
 126 
 127         for (i = 0; i < sdm->table_size; i++)
 128                 if (sdm->table[i].pattern == reg &&
 129                     sdm->table[i].m == m && sdm->table[i].n == n)
 130                         return sdm->table[i].rate;
 131 
 132         /* We can't calculate the effective clock rate, so just fail. */
 133         return 0;
 134 }
 135 
 136 int ccu_sdm_helper_get_factors(struct ccu_common *common,
 137                                struct ccu_sdm_internal *sdm,
 138                                unsigned long rate,
 139                                unsigned long *m, unsigned long *n)
 140 {
 141         unsigned int i;
 142 
 143         if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
 144                 return -EINVAL;
 145 
 146         for (i = 0; i < sdm->table_size; i++)
 147                 if (sdm->table[i].rate == rate) {
 148                         *m = sdm->table[i].m;
 149                         *n = sdm->table[i].n;
 150                         return 0;
 151                 }
 152 
 153         /* nothing found */
 154         return -EINVAL;
 155 }

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