Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: rt5640: Add the function of the PLL clock calculation to RL6231 shared support

The patch adds the function of the PLL clock calculation to RL6231 shared
support.

Signed-off-by: Oder Chiou <oder_chiou@realtek.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Oder Chiou and committed by
Mark Brown
71c7a2d6 49ef7925

+102 -206
+69
sound/soc/codecs/rl6231.c
··· 62 62 } 63 63 EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk); 64 64 65 + /** 66 + * rl6231_pll_calc - Calcualte PLL M/N/K code. 67 + * @freq_in: external clock provided to codec. 68 + * @freq_out: target clock which codec works on. 69 + * @pll_code: Pointer to structure with M, N, K and bypass flag. 70 + * 71 + * Calcualte M/N/K code to configure PLL for codec. 72 + * 73 + * Returns 0 for success or negative error code. 74 + */ 75 + int rl6231_pll_calc(const unsigned int freq_in, 76 + const unsigned int freq_out, struct rl6231_pll_code *pll_code) 77 + { 78 + int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX; 79 + int k, red, n_t, pll_out, in_t, out_t; 80 + int n = 0, m = 0, m_t = 0; 81 + int red_t = abs(freq_out - freq_in); 82 + bool bypass = false; 83 + 84 + if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in) 85 + return -EINVAL; 86 + 87 + k = 100000000 / freq_out - 2; 88 + if (k > RL6231_PLL_K_MAX) 89 + k = RL6231_PLL_K_MAX; 90 + for (n_t = 0; n_t <= max_n; n_t++) { 91 + in_t = freq_in / (k + 2); 92 + pll_out = freq_out / (n_t + 2); 93 + if (in_t < 0) 94 + continue; 95 + if (in_t == pll_out) { 96 + bypass = true; 97 + n = n_t; 98 + goto code_find; 99 + } 100 + red = abs(in_t - pll_out); 101 + if (red < red_t) { 102 + bypass = true; 103 + n = n_t; 104 + m = m_t; 105 + if (red == 0) 106 + goto code_find; 107 + red_t = red; 108 + } 109 + for (m_t = 0; m_t <= max_m; m_t++) { 110 + out_t = in_t / (m_t + 2); 111 + red = abs(out_t - pll_out); 112 + if (red < red_t) { 113 + bypass = false; 114 + n = n_t; 115 + m = m_t; 116 + if (red == 0) 117 + goto code_find; 118 + red_t = red; 119 + } 120 + } 121 + } 122 + pr_debug("Only get approximation about PLL\n"); 123 + 124 + code_find: 125 + 126 + pll_code->m_bp = bypass; 127 + pll_code->m_code = m; 128 + pll_code->n_code = n; 129 + pll_code->k_code = k; 130 + return 0; 131 + } 132 + EXPORT_SYMBOL_GPL(rl6231_pll_calc); 133 + 65 134 MODULE_DESCRIPTION("RL6231 class device shared support"); 66 135 MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); 67 136 MODULE_LICENSE("GPL v2");
+15
sound/soc/codecs/rl6231.h
··· 13 13 #ifndef __RL6231_H__ 14 14 #define __RL6231_H__ 15 15 16 + #define RL6231_PLL_INP_MAX 40000000 17 + #define RL6231_PLL_INP_MIN 256000 18 + #define RL6231_PLL_N_MAX 0x1ff 19 + #define RL6231_PLL_K_MAX 0x1f 20 + #define RL6231_PLL_M_MAX 0xf 21 + 22 + struct rl6231_pll_code { 23 + bool m_bp; /* Indicates bypass m code or not. */ 24 + int m_code; 25 + int n_code; 26 + int k_code; 27 + }; 28 + 16 29 int rl6231_calc_dmic_clk(int rate); 30 + int rl6231_pll_calc(const unsigned int freq_in, 31 + const unsigned int freq_out, struct rl6231_pll_code *pll_code); 17 32 18 33 #endif /* __RL6231_H__ */
+8 -60
sound/soc/codecs/rt5640.c
··· 1806 1806 return 0; 1807 1807 } 1808 1808 1809 - /** 1810 - * rt5640_pll_calc - Calculate PLL M/N/K code. 1811 - * @freq_in: external clock provided to codec. 1812 - * @freq_out: target clock which codec works on. 1813 - * @pll_code: Pointer to structure with M, N, K and bypass flag. 1814 - * 1815 - * Calculate M/N/K code to configure PLL for codec. And K is assigned to 2 1816 - * which make calculation more efficiently. 1817 - * 1818 - * Returns 0 for success or negative error code. 1819 - */ 1820 - static int rt5640_pll_calc(const unsigned int freq_in, 1821 - const unsigned int freq_out, struct rt5640_pll_code *pll_code) 1822 - { 1823 - int max_n = RT5640_PLL_N_MAX, max_m = RT5640_PLL_M_MAX; 1824 - int n = 0, m = 0, red, n_t, m_t, in_t, out_t; 1825 - int red_t = abs(freq_out - freq_in); 1826 - bool bypass = false; 1827 - 1828 - if (RT5640_PLL_INP_MAX < freq_in || RT5640_PLL_INP_MIN > freq_in) 1829 - return -EINVAL; 1830 - 1831 - for (n_t = 0; n_t <= max_n; n_t++) { 1832 - in_t = (freq_in >> 1) + (freq_in >> 2) * n_t; 1833 - if (in_t < 0) 1834 - continue; 1835 - if (in_t == freq_out) { 1836 - bypass = true; 1837 - n = n_t; 1838 - goto code_find; 1839 - } 1840 - for (m_t = 0; m_t <= max_m; m_t++) { 1841 - out_t = in_t / (m_t + 2); 1842 - red = abs(out_t - freq_out); 1843 - if (red < red_t) { 1844 - n = n_t; 1845 - m = m_t; 1846 - if (red == 0) 1847 - goto code_find; 1848 - red_t = red; 1849 - } 1850 - } 1851 - } 1852 - pr_debug("Only get approximation about PLL\n"); 1853 - 1854 - code_find: 1855 - pll_code->m_bp = bypass; 1856 - pll_code->m_code = m; 1857 - pll_code->n_code = n; 1858 - pll_code->k_code = 2; 1859 - return 0; 1860 - } 1861 - 1862 1809 static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, 1863 1810 unsigned int freq_in, unsigned int freq_out) 1864 1811 { 1865 1812 struct snd_soc_codec *codec = dai->codec; 1866 1813 struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); 1867 - struct rt5640_pll_code *pll_code = &rt5640->pll_code; 1814 + struct rl6231_pll_code pll_code; 1868 1815 int ret, dai_sel; 1869 1816 1870 1817 if (source == rt5640->pll_src && freq_in == rt5640->pll_in && ··· 1855 1908 return -EINVAL; 1856 1909 } 1857 1910 1858 - ret = rt5640_pll_calc(freq_in, freq_out, pll_code); 1911 + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); 1859 1912 if (ret < 0) { 1860 1913 dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); 1861 1914 return ret; 1862 1915 } 1863 1916 1864 - dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp, 1865 - (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code); 1917 + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", 1918 + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), 1919 + pll_code.n_code, pll_code.k_code); 1866 1920 1867 1921 snd_soc_write(codec, RT5640_PLL_CTRL1, 1868 - pll_code->n_code << RT5640_PLL_N_SFT | pll_code->k_code); 1922 + pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code); 1869 1923 snd_soc_write(codec, RT5640_PLL_CTRL2, 1870 - (pll_code->m_bp ? 0 : pll_code->m_code) << RT5640_PLL_M_SFT | 1871 - pll_code->m_bp << RT5640_PLL_M_BP_SFT); 1924 + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT | 1925 + pll_code.m_bp << RT5640_PLL_M_BP_SFT); 1872 1926 1873 1927 rt5640->pll_in = freq_in; 1874 1928 rt5640->pll_out = freq_out;
-8
sound/soc/codecs/rt5640.h
··· 2079 2079 RT5640_DMIC2, 2080 2080 }; 2081 2081 2082 - struct rt5640_pll_code { 2083 - bool m_bp; /* Indicates bypass m code or not. */ 2084 - int m_code; 2085 - int n_code; 2086 - int k_code; 2087 - }; 2088 - 2089 2082 struct rt5640_priv { 2090 2083 struct snd_soc_codec *codec; 2091 2084 struct rt5640_platform_data pdata; ··· 2090 2097 int bclk[RT5640_AIFS]; 2091 2098 int master[RT5640_AIFS]; 2092 2099 2093 - struct rt5640_pll_code pll_code; 2094 2100 int pll_src; 2095 2101 int pll_in; 2096 2102 int pll_out;
+2 -70
sound/soc/codecs/rt5645.c
··· 1964 1964 return 0; 1965 1965 } 1966 1966 1967 - /** 1968 - * rt5645_pll_calc - Calcualte PLL M/N/K code. 1969 - * @freq_in: external clock provided to codec. 1970 - * @freq_out: target clock which codec works on. 1971 - * @pll_code: Pointer to structure with M, N, K and bypass flag. 1972 - * 1973 - * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2 1974 - * which make calculation more efficiently. 1975 - * 1976 - * Returns 0 for success or negative error code. 1977 - */ 1978 - static int rt5645_pll_calc(const unsigned int freq_in, 1979 - const unsigned int freq_out, struct rt5645_pll_code *pll_code) 1980 - { 1981 - int max_n = RT5645_PLL_N_MAX, max_m = RT5645_PLL_M_MAX; 1982 - int k, n = 0, m = 0, red, n_t, m_t, pll_out, in_t, out_t; 1983 - int red_t = abs(freq_out - freq_in); 1984 - bool bypass = false; 1985 - 1986 - if (RT5645_PLL_INP_MAX < freq_in || RT5645_PLL_INP_MIN > freq_in) 1987 - return -EINVAL; 1988 - 1989 - k = 100000000 / freq_out - 2; 1990 - if (k > RT5645_PLL_K_MAX) 1991 - k = RT5645_PLL_K_MAX; 1992 - for (n_t = 0; n_t <= max_n; n_t++) { 1993 - in_t = freq_in / (k + 2); 1994 - pll_out = freq_out / (n_t + 2); 1995 - if (in_t < 0) 1996 - continue; 1997 - if (in_t == pll_out) { 1998 - bypass = true; 1999 - n = n_t; 2000 - goto code_find; 2001 - } 2002 - red = abs(in_t - pll_out); 2003 - if (red < red_t) { 2004 - bypass = true; 2005 - n = n_t; 2006 - m = m_t; 2007 - if (red == 0) 2008 - goto code_find; 2009 - red_t = red; 2010 - } 2011 - for (m_t = 0; m_t <= max_m; m_t++) { 2012 - out_t = in_t / (m_t + 2); 2013 - red = abs(out_t - pll_out); 2014 - if (red < red_t) { 2015 - bypass = false; 2016 - n = n_t; 2017 - m = m_t; 2018 - if (red == 0) 2019 - goto code_find; 2020 - red_t = red; 2021 - } 2022 - } 2023 - } 2024 - pr_debug("Only get approximation about PLL\n"); 2025 - 2026 - code_find: 2027 - 2028 - pll_code->m_bp = bypass; 2029 - pll_code->m_code = m; 2030 - pll_code->n_code = n; 2031 - pll_code->k_code = k; 2032 - return 0; 2033 - } 2034 - 2035 1967 static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, 2036 1968 unsigned int freq_in, unsigned int freq_out) 2037 1969 { 2038 1970 struct snd_soc_codec *codec = dai->codec; 2039 1971 struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); 2040 - struct rt5645_pll_code pll_code; 1972 + struct rl6231_pll_code pll_code; 2041 1973 int ret; 2042 1974 2043 1975 if (source == rt5645->pll_src && freq_in == rt5645->pll_in && ··· 2012 2080 return -EINVAL; 2013 2081 } 2014 2082 2015 - ret = rt5645_pll_calc(freq_in, freq_out, &pll_code); 2083 + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); 2016 2084 if (ret < 0) { 2017 2085 dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); 2018 2086 return ret;
-7
sound/soc/codecs/rt5645.h
··· 2162 2162 RT5645_DMIC_DATA_GPIO11, 2163 2163 }; 2164 2164 2165 - struct rt5645_pll_code { 2166 - bool m_bp; /* Indicates bypass m code or not. */ 2167 - int m_code; 2168 - int n_code; 2169 - int k_code; 2170 - }; 2171 - 2172 2165 struct rt5645_priv { 2173 2166 struct snd_soc_codec *codec; 2174 2167 struct rt5645_platform_data pdata;
+8 -60
sound/soc/codecs/rt5651.c
··· 1516 1516 return 0; 1517 1517 } 1518 1518 1519 - /** 1520 - * rt5651_pll_calc - Calcualte PLL M/N/K code. 1521 - * @freq_in: external clock provided to codec. 1522 - * @freq_out: target clock which codec works on. 1523 - * @pll_code: Pointer to structure with M, N, K and bypass flag. 1524 - * 1525 - * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2 1526 - * which make calculation more efficiently. 1527 - * 1528 - * Returns 0 for success or negative error code. 1529 - */ 1530 - static int rt5651_pll_calc(const unsigned int freq_in, 1531 - const unsigned int freq_out, struct rt5651_pll_code *pll_code) 1532 - { 1533 - int max_n = RT5651_PLL_N_MAX, max_m = RT5651_PLL_M_MAX; 1534 - int n = 0, m = 0, red, n_t, m_t, in_t, out_t; 1535 - int red_t = abs(freq_out - freq_in); 1536 - bool bypass = false; 1537 - 1538 - if (RT5651_PLL_INP_MAX < freq_in || RT5651_PLL_INP_MIN > freq_in) 1539 - return -EINVAL; 1540 - 1541 - for (n_t = 0; n_t <= max_n; n_t++) { 1542 - in_t = (freq_in >> 1) + (freq_in >> 2) * n_t; 1543 - if (in_t < 0) 1544 - continue; 1545 - if (in_t == freq_out) { 1546 - bypass = true; 1547 - n = n_t; 1548 - goto code_find; 1549 - } 1550 - for (m_t = 0; m_t <= max_m; m_t++) { 1551 - out_t = in_t / (m_t + 2); 1552 - red = abs(out_t - freq_out); 1553 - if (red < red_t) { 1554 - n = n_t; 1555 - m = m_t; 1556 - if (red == 0) 1557 - goto code_find; 1558 - red_t = red; 1559 - } 1560 - } 1561 - } 1562 - pr_debug("Only get approximation about PLL\n"); 1563 - 1564 - code_find: 1565 - pll_code->m_bp = bypass; 1566 - pll_code->m_code = m; 1567 - pll_code->n_code = n; 1568 - pll_code->k_code = 2; 1569 - return 0; 1570 - } 1571 - 1572 1519 static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, 1573 1520 unsigned int freq_in, unsigned int freq_out) 1574 1521 { 1575 1522 struct snd_soc_codec *codec = dai->codec; 1576 1523 struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); 1577 - struct rt5651_pll_code *pll_code = &rt5651->pll_code; 1524 + struct rl6231_pll_code pll_code; 1578 1525 int ret; 1579 1526 1580 1527 if (source == rt5651->pll_src && freq_in == rt5651->pll_in && ··· 1556 1609 return -EINVAL; 1557 1610 } 1558 1611 1559 - ret = rt5651_pll_calc(freq_in, freq_out, pll_code); 1612 + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); 1560 1613 if (ret < 0) { 1561 1614 dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); 1562 1615 return ret; 1563 1616 } 1564 1617 1565 - dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp, 1566 - (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code); 1618 + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", 1619 + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), 1620 + pll_code.n_code, pll_code.k_code); 1567 1621 1568 1622 snd_soc_write(codec, RT5651_PLL_CTRL1, 1569 - pll_code->n_code << RT5651_PLL_N_SFT | pll_code->k_code); 1623 + pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code); 1570 1624 snd_soc_write(codec, RT5651_PLL_CTRL2, 1571 - (pll_code->m_bp ? 0 : pll_code->m_code) << RT5651_PLL_M_SFT | 1572 - pll_code->m_bp << RT5651_PLL_M_BP_SFT); 1625 + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT | 1626 + pll_code.m_bp << RT5651_PLL_M_BP_SFT); 1573 1627 1574 1628 rt5651->pll_in = freq_in; 1575 1629 rt5651->pll_out = freq_out;
-1
sound/soc/codecs/rt5651.h
··· 2069 2069 int bclk[RT5651_AIFS]; 2070 2070 int master[RT5651_AIFS]; 2071 2071 2072 - struct rt5651_pll_code pll_code; 2073 2072 int pll_src; 2074 2073 int pll_in; 2075 2074 int pll_out;