aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2017-12-08 03:35:10 -0500
committerMaxime Ripard <maxime.ripard@free-electrons.com>2017-12-08 04:08:07 -0500
commit7d333ef1cc1b8c8951f3a2c41f6406e2295d8be9 (patch)
treefe53d1a1e2a6ba5b08691018ee13b293825350a6
parent83fe3be4d1974f5f50c5e2039a1609f4960e8579 (diff)
clk: sunxi-ng: Support fixed post-dividers on NM style clocks
On the A83T, the audio PLL should have its div1 set to 0, or /1, and div2 set to 1, or /2. This setting is the default, and is required to match the sigma-delta modulation parameters from the BSP kernel. To do this, we first add fixed post-divider to the NM style clocks, which is the type of clock the audio PLL clock is modeled into. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.c50
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.h2
2 files changed, 39 insertions, 13 deletions
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index 7620aa973a6e..a16de092bf94 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
70 unsigned long parent_rate) 70 unsigned long parent_rate)
71{ 71{
72 struct ccu_nm *nm = hw_to_ccu_nm(hw); 72 struct ccu_nm *nm = hw_to_ccu_nm(hw);
73 unsigned long rate;
73 unsigned long n, m; 74 unsigned long n, m;
74 u32 reg; 75 u32 reg;
75 76
76 if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) 77 if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) {
77 return ccu_frac_helper_read_rate(&nm->common, &nm->frac); 78 rate = ccu_frac_helper_read_rate(&nm->common, &nm->frac);
79
80 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
81 rate /= nm->fixed_post_div;
82
83 return rate;
84 }
78 85
79 reg = readl(nm->common.base + nm->common.reg); 86 reg = readl(nm->common.base + nm->common.reg);
80 87
@@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
90 if (!m) 97 if (!m)
91 m++; 98 m++;
92 99
93 if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { 100 if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm))
94 unsigned long rate = 101 rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n);
95 ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, 102 else
96 m, n); 103 rate = parent_rate * n / m;
97 if (rate) 104
98 return rate; 105 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
99 } 106 rate /= nm->fixed_post_div;
100 107
101 return parent_rate * n / m; 108 return rate;
102} 109}
103 110
104static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, 111static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -107,11 +114,20 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
107 struct ccu_nm *nm = hw_to_ccu_nm(hw); 114 struct ccu_nm *nm = hw_to_ccu_nm(hw);
108 struct _ccu_nm _nm; 115 struct _ccu_nm _nm;
109 116
110 if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) 117 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
118 rate *= nm->fixed_post_div;
119
120 if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
121 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
122 rate /= nm->fixed_post_div;
111 return rate; 123 return rate;
124 }
112 125
113 if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) 126 if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) {
127 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
128 rate /= nm->fixed_post_div;
114 return rate; 129 return rate;
130 }
115 131
116 _nm.min_n = nm->n.min ?: 1; 132 _nm.min_n = nm->n.min ?: 1;
117 _nm.max_n = nm->n.max ?: 1 << nm->n.width; 133 _nm.max_n = nm->n.max ?: 1 << nm->n.width;
@@ -119,8 +135,12 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
119 _nm.max_m = nm->m.max ?: 1 << nm->m.width; 135 _nm.max_m = nm->m.max ?: 1 << nm->m.width;
120 136
121 ccu_nm_find_best(*parent_rate, rate, &_nm); 137 ccu_nm_find_best(*parent_rate, rate, &_nm);
138 rate = *parent_rate * _nm.n / _nm.m;
139
140 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
141 rate /= nm->fixed_post_div;
122 142
123 return *parent_rate * _nm.n / _nm.m; 143 return rate;
124} 144}
125 145
126static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, 146static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -131,6 +151,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
131 unsigned long flags; 151 unsigned long flags;
132 u32 reg; 152 u32 reg;
133 153
154 /* Adjust target rate according to post-dividers */
155 if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
156 rate = rate * nm->fixed_post_div;
157
134 if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { 158 if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
135 spin_lock_irqsave(nm->common.lock, flags); 159 spin_lock_irqsave(nm->common.lock, flags);
136 160
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
index c623b0c7a23c..eba586b4c7d0 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.h
+++ b/drivers/clk/sunxi-ng/ccu_nm.h
@@ -36,6 +36,8 @@ struct ccu_nm {
36 struct ccu_frac_internal frac; 36 struct ccu_frac_internal frac;
37 struct ccu_sdm_internal sdm; 37 struct ccu_sdm_internal sdm;
38 38
39 unsigned int fixed_post_div;
40
39 struct ccu_common common; 41 struct ccu_common common;
40}; 42};
41 43