These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / sound / soc / codecs / rl6231.c
index 56650d6..1dc68ab 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/regmap.h>
 
 #include "rl6231.h"
 
 /**
- * rl6231_calc_dmic_clk - Calculate the parameter of dmic.
+ * rl6231_get_pre_div - Return the value of pre divider.
+ *
+ * @map: map for setting.
+ * @reg: register.
+ * @sft: shift.
+ *
+ * Return the value of pre divider from given register value.
+ * Return negative error code for unexpected register value.
+ */
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft)
+{
+       int pd, val;
+
+       regmap_read(map, reg, &val);
+
+       val = (val >> sft) & 0x7;
+
+       switch (val) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+               pd = val + 1;
+               break;
+       case 4:
+               pd = 6;
+               break;
+       case 5:
+               pd = 8;
+               break;
+       case 6:
+               pd = 12;
+               break;
+       case 7:
+               pd = 16;
+               break;
+       default:
+               pd = -EINVAL;
+               break;
+       }
+
+       return pd;
+}
+EXPORT_SYMBOL_GPL(rl6231_get_pre_div);
+
+/**
+ * rl6231_calc_dmic_clk - Calculate the frequency divider parameter of dmic.
  *
  * @rate: base clock rate.
  *
- * Choose dmic clock between 1MHz and 3MHz.
- * It is better for clock to approximate 3MHz.
+ * Choose divider parameter that gives the highest possible DMIC frequency in
+ * 1MHz - 3MHz range.
  */
 int rl6231_calc_dmic_clk(int rate)
 {
-       int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
-       int i, red, bound, temp;
+       int div[] = {2, 3, 4, 6, 8, 12};
+       int i;
+
+       if (rate < 1000000 * div[0]) {
+               pr_warn("Base clock rate %d is too low\n", rate);
+               return -EINVAL;
+       }
 
-       red = 3000000 * 12;
        for (i = 0; i < ARRAY_SIZE(div); i++) {
-               bound = div[i] * 3000000;
-               if (rate > bound)
+               if ((div[i] % 3) == 0)
                        continue;
-               temp = bound - rate;
-               if (temp < red) {
-                       red = temp;
-                       idx = i;
-               }
+               /* find divider that gives DMIC frequency below 3.072MHz */
+               if (3072000 * div[i] >= rate)
+                       return i;
        }
 
-       return idx;
+       pr_warn("Base clock rate %d is too high\n", rate);
+       return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk);
 
+struct pll_calc_map {
+       unsigned int pll_in;
+       unsigned int pll_out;
+       int k;
+       int n;
+       int m;
+       bool m_bp;
+};
+
+static const struct pll_calc_map pll_preset_table[] = {
+       {19200000,  24576000,  3, 30, 3, false},
+};
+
 /**
  * rl6231_pll_calc - Calcualte PLL M/N/K code.
  * @freq_in: external clock provided to codec.
@@ -57,7 +119,7 @@ int rl6231_pll_calc(const unsigned int freq_in,
        const unsigned int freq_out, struct rl6231_pll_code *pll_code)
 {
        int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
-       int k, red, n_t, pll_out, in_t, out_t;
+       int i, k, red, n_t, pll_out, in_t, out_t;
        int n = 0, m = 0, m_t = 0;
        int red_t = abs(freq_out - freq_in);
        bool bypass = false;
@@ -65,6 +127,18 @@ int rl6231_pll_calc(const unsigned int freq_in,
        if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
                return -EINVAL;
 
+       for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+               if (freq_in == pll_preset_table[i].pll_in &&
+                       freq_out == pll_preset_table[i].pll_out) {
+                       k = pll_preset_table[i].k;
+                       m = pll_preset_table[i].m;
+                       n = pll_preset_table[i].n;
+                       bypass = pll_preset_table[i].m_bp;
+                       pr_debug("Use preset PLL parameter table\n");
+                       goto code_find;
+               }
+       }
+
        k = 100000000 / freq_out - 2;
        if (k > RL6231_PLL_K_MAX)
                k = RL6231_PLL_K_MAX;