0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/regmap.h>
0012
0013 #include <linux/gcd.h>
0014 #include "rl6231.h"
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft)
0027 {
0028 int pd, val;
0029
0030 regmap_read(map, reg, &val);
0031
0032 val = (val >> sft) & 0x7;
0033
0034 switch (val) {
0035 case 0:
0036 case 1:
0037 case 2:
0038 case 3:
0039 pd = val + 1;
0040 break;
0041 case 4:
0042 pd = 6;
0043 break;
0044 case 5:
0045 pd = 8;
0046 break;
0047 case 6:
0048 pd = 12;
0049 break;
0050 case 7:
0051 pd = 16;
0052 break;
0053 default:
0054 pd = -EINVAL;
0055 break;
0056 }
0057
0058 return pd;
0059 }
0060 EXPORT_SYMBOL_GPL(rl6231_get_pre_div);
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 int rl6231_calc_dmic_clk(int rate)
0071 {
0072 static const int div[] = {2, 3, 4, 6, 8, 12};
0073 int i;
0074
0075 if (rate < 1000000 * div[0]) {
0076 pr_warn("Base clock rate %d is too low\n", rate);
0077 return -EINVAL;
0078 }
0079
0080 for (i = 0; i < ARRAY_SIZE(div); i++) {
0081 if ((div[i] % 3) == 0)
0082 continue;
0083
0084 if (1536000 * div[i] >= rate)
0085 return i;
0086 }
0087
0088 pr_warn("Base clock rate %d is too high\n", rate);
0089 return -EINVAL;
0090 }
0091 EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk);
0092
0093 struct pll_calc_map {
0094 unsigned int pll_in;
0095 unsigned int pll_out;
0096 int k;
0097 int n;
0098 int m;
0099 bool m_bp;
0100 bool k_bp;
0101 };
0102
0103 static const struct pll_calc_map pll_preset_table[] = {
0104 {19200000, 4096000, 23, 14, 1, false, false},
0105 {19200000, 24576000, 3, 30, 3, false, false},
0106 {48000000, 3840000, 23, 2, 0, false, false},
0107 {3840000, 24576000, 3, 30, 0, true, false},
0108 {3840000, 22579200, 3, 5, 0, true, false},
0109 };
0110
0111 static unsigned int find_best_div(unsigned int in,
0112 unsigned int max, unsigned int div)
0113 {
0114 unsigned int d;
0115
0116 if (in <= max)
0117 return 1;
0118
0119 d = in / max;
0120 if (in % max)
0121 d++;
0122
0123 while (div % d != 0)
0124 d++;
0125
0126
0127 return d;
0128 }
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 int rl6231_pll_calc(const unsigned int freq_in,
0141 const unsigned int freq_out, struct rl6231_pll_code *pll_code)
0142 {
0143 int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
0144 int i, k, n_t;
0145 int k_t, min_k, max_k, n = 0, m = 0, m_t = 0;
0146 unsigned int red, pll_out, in_t, out_t, div, div_t;
0147 unsigned int red_t = abs(freq_out - freq_in);
0148 unsigned int f_in, f_out, f_max;
0149 bool m_bypass = false, k_bypass = false;
0150
0151 if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
0152 return -EINVAL;
0153
0154 for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
0155 if (freq_in == pll_preset_table[i].pll_in &&
0156 freq_out == pll_preset_table[i].pll_out) {
0157 k = pll_preset_table[i].k;
0158 m = pll_preset_table[i].m;
0159 n = pll_preset_table[i].n;
0160 m_bypass = pll_preset_table[i].m_bp;
0161 k_bypass = pll_preset_table[i].k_bp;
0162 pr_debug("Use preset PLL parameter table\n");
0163 goto code_find;
0164 }
0165 }
0166
0167 min_k = 80000000 / freq_out - 2;
0168 max_k = 150000000 / freq_out - 2;
0169 if (max_k > RL6231_PLL_K_MAX)
0170 max_k = RL6231_PLL_K_MAX;
0171 if (min_k > RL6231_PLL_K_MAX)
0172 min_k = max_k = RL6231_PLL_K_MAX;
0173 div_t = gcd(freq_in, freq_out);
0174 f_max = 0xffffffff / RL6231_PLL_N_MAX;
0175 div = find_best_div(freq_in, f_max, div_t);
0176 f_in = freq_in / div;
0177 f_out = freq_out / div;
0178 k = min_k;
0179 if (min_k < -1)
0180 min_k = -1;
0181 for (k_t = min_k; k_t <= max_k; k_t++) {
0182 for (n_t = 0; n_t <= max_n; n_t++) {
0183 in_t = f_in * (n_t + 2);
0184 pll_out = f_out * (k_t + 2);
0185 if (in_t == pll_out) {
0186 m_bypass = true;
0187 n = n_t;
0188 k = k_t;
0189 goto code_find;
0190 }
0191 out_t = in_t / (k_t + 2);
0192 red = abs(f_out - out_t);
0193 if (red < red_t) {
0194 m_bypass = true;
0195 n = n_t;
0196 m = 0;
0197 k = k_t;
0198 if (red == 0)
0199 goto code_find;
0200 red_t = red;
0201 }
0202 for (m_t = 0; m_t <= max_m; m_t++) {
0203 out_t = in_t / ((m_t + 2) * (k_t + 2));
0204 red = abs(f_out - out_t);
0205 if (red < red_t) {
0206 m_bypass = false;
0207 n = n_t;
0208 m = m_t;
0209 k = k_t;
0210 if (red == 0)
0211 goto code_find;
0212 red_t = red;
0213 }
0214 }
0215 }
0216 }
0217 pr_debug("Only get approximation about PLL\n");
0218
0219 code_find:
0220 if (k == -1) {
0221 k_bypass = true;
0222 k = 0;
0223 }
0224
0225 pll_code->m_bp = m_bypass;
0226 pll_code->k_bp = k_bypass;
0227 pll_code->m_code = m;
0228 pll_code->n_code = n;
0229 pll_code->k_code = k;
0230 return 0;
0231 }
0232 EXPORT_SYMBOL_GPL(rl6231_pll_calc);
0233
0234 int rl6231_get_clk_info(int sclk, int rate)
0235 {
0236 int i;
0237 static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
0238
0239 if (sclk <= 0 || rate <= 0)
0240 return -EINVAL;
0241
0242 rate = rate << 8;
0243 for (i = 0; i < ARRAY_SIZE(pd); i++)
0244 if (sclk == rate * pd[i])
0245 return i;
0246
0247 return -EINVAL;
0248 }
0249 EXPORT_SYMBOL_GPL(rl6231_get_clk_info);
0250
0251 MODULE_DESCRIPTION("RL6231 class device shared support");
0252 MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
0253 MODULE_LICENSE("GPL v2");