diff options
-rw-r--r-- | sound/soc/codecs/wm8915.c | 82 |
1 files changed, 53 insertions, 29 deletions
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c index a1d8618f7e2e..423baa9be241 100644 --- a/sound/soc/codecs/wm8915.c +++ b/sound/soc/codecs/wm8915.c | |||
@@ -75,6 +75,7 @@ struct wm8915_priv { | |||
75 | struct wm8915_pdata pdata; | 75 | struct wm8915_pdata pdata; |
76 | 76 | ||
77 | int rx_rate[WM8915_AIFS]; | 77 | int rx_rate[WM8915_AIFS]; |
78 | int bclk_rate[WM8915_AIFS]; | ||
78 | 79 | ||
79 | /* Platform dependant ReTune mobile configuration */ | 80 | /* Platform dependant ReTune mobile configuration */ |
80 | int num_retune_mobile_texts; | 81 | int num_retune_mobile_texts; |
@@ -1562,6 +1563,50 @@ static int wm8915_reset(struct snd_soc_codec *codec) | |||
1562 | return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); | 1563 | return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); |
1563 | } | 1564 | } |
1564 | 1565 | ||
1566 | static const int bclk_divs[] = { | ||
1567 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 | ||
1568 | }; | ||
1569 | |||
1570 | static void wm8915_update_bclk(struct snd_soc_codec *codec) | ||
1571 | { | ||
1572 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | ||
1573 | int aif, best, cur_val, bclk_rate, bclk_reg, i; | ||
1574 | |||
1575 | /* Don't bother if we're in a low frequency idle mode that | ||
1576 | * can't support audio. | ||
1577 | */ | ||
1578 | if (wm8915->sysclk < 64000) | ||
1579 | return; | ||
1580 | |||
1581 | for (aif = 0; aif < WM8915_AIFS; aif++) { | ||
1582 | switch (aif) { | ||
1583 | case 0: | ||
1584 | bclk_reg = WM8915_AIF1_BCLK; | ||
1585 | break; | ||
1586 | case 1: | ||
1587 | bclk_reg = WM8915_AIF2_BCLK; | ||
1588 | break; | ||
1589 | } | ||
1590 | |||
1591 | bclk_rate = wm8915->bclk_rate[aif]; | ||
1592 | |||
1593 | /* Pick a divisor for BCLK as close as we can get to ideal */ | ||
1594 | best = 0; | ||
1595 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
1596 | cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; | ||
1597 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1598 | break; | ||
1599 | best = i; | ||
1600 | } | ||
1601 | bclk_rate = wm8915->sysclk / bclk_divs[best]; | ||
1602 | dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", | ||
1603 | bclk_divs[best], bclk_rate); | ||
1604 | |||
1605 | snd_soc_update_bits(codec, bclk_reg, | ||
1606 | WM8915_AIF1_BCLK_DIV_MASK, best); | ||
1607 | } | ||
1608 | } | ||
1609 | |||
1565 | static int wm8915_set_bias_level(struct snd_soc_codec *codec, | 1610 | static int wm8915_set_bias_level(struct snd_soc_codec *codec, |
1566 | enum snd_soc_bias_level level) | 1611 | enum snd_soc_bias_level level) |
1567 | { | 1612 | { |
@@ -1714,10 +1759,6 @@ static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1714 | return 0; | 1759 | return 0; |
1715 | } | 1760 | } |
1716 | 1761 | ||
1717 | static const int bclk_divs[] = { | ||
1718 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 | ||
1719 | }; | ||
1720 | |||
1721 | static const int dsp_divs[] = { | 1762 | static const int dsp_divs[] = { |
1722 | 48000, 32000, 16000, 8000 | 1763 | 48000, 32000, 16000, 8000 |
1723 | }; | 1764 | }; |
@@ -1728,17 +1769,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1728 | { | 1769 | { |
1729 | struct snd_soc_codec *codec = dai->codec; | 1770 | struct snd_soc_codec *codec = dai->codec; |
1730 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 1771 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
1731 | int bits, i, bclk_rate, best, cur_val; | 1772 | int bits, i, bclk_rate; |
1732 | int aifdata = 0; | 1773 | int aifdata = 0; |
1733 | int bclk = 0; | ||
1734 | int lrclk = 0; | 1774 | int lrclk = 0; |
1735 | int dsp = 0; | 1775 | int dsp = 0; |
1736 | int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift; | 1776 | int aifdata_reg, lrclk_reg, dsp_shift; |
1737 | |||
1738 | if (!wm8915->sysclk) { | ||
1739 | dev_err(codec->dev, "SYSCLK not configured\n"); | ||
1740 | return -EINVAL; | ||
1741 | } | ||
1742 | 1777 | ||
1743 | switch (dai->id) { | 1778 | switch (dai->id) { |
1744 | case 0: | 1779 | case 0: |
@@ -1750,7 +1785,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1750 | aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; | 1785 | aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; |
1751 | lrclk_reg = WM8915_AIF1_TX_LRCLK_1; | 1786 | lrclk_reg = WM8915_AIF1_TX_LRCLK_1; |
1752 | } | 1787 | } |
1753 | bclk_reg = WM8915_AIF1_BCLK; | ||
1754 | dsp_shift = 0; | 1788 | dsp_shift = 0; |
1755 | break; | 1789 | break; |
1756 | case 1: | 1790 | case 1: |
@@ -1762,7 +1796,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1762 | aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; | 1796 | aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; |
1763 | lrclk_reg = WM8915_AIF2_TX_LRCLK_1; | 1797 | lrclk_reg = WM8915_AIF2_TX_LRCLK_1; |
1764 | } | 1798 | } |
1765 | bclk_reg = WM8915_AIF2_BCLK; | ||
1766 | dsp_shift = WM8915_DSP2_DIV_SHIFT; | 1799 | dsp_shift = WM8915_DSP2_DIV_SHIFT; |
1767 | break; | 1800 | break; |
1768 | default: | 1801 | default: |
@@ -1776,6 +1809,9 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1776 | return bclk_rate; | 1809 | return bclk_rate; |
1777 | } | 1810 | } |
1778 | 1811 | ||
1812 | wm8915->bclk_rate[dai->id] = bclk_rate; | ||
1813 | wm8915->rx_rate[dai->id] = params_rate(params); | ||
1814 | |||
1779 | /* Needs looking at for TDM */ | 1815 | /* Needs looking at for TDM */ |
1780 | bits = snd_pcm_format_width(params_format(params)); | 1816 | bits = snd_pcm_format_width(params_format(params)); |
1781 | if (bits < 0) | 1817 | if (bits < 0) |
@@ -1793,18 +1829,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1793 | } | 1829 | } |
1794 | dsp |= i << dsp_shift; | 1830 | dsp |= i << dsp_shift; |
1795 | 1831 | ||
1796 | /* Pick a divisor for BCLK as close as we can get to ideal */ | 1832 | wm8915_update_bclk(codec); |
1797 | best = 0; | ||
1798 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
1799 | cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; | ||
1800 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1801 | break; | ||
1802 | best = i; | ||
1803 | } | ||
1804 | bclk_rate = wm8915->sysclk / bclk_divs[best]; | ||
1805 | dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", | ||
1806 | bclk_divs[best], bclk_rate); | ||
1807 | bclk |= best; | ||
1808 | 1833 | ||
1809 | lrclk = bclk_rate / params_rate(params); | 1834 | lrclk = bclk_rate / params_rate(params); |
1810 | dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", | 1835 | dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", |
@@ -1814,14 +1839,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1814 | WM8915_AIF1TX_WL_MASK | | 1839 | WM8915_AIF1TX_WL_MASK | |
1815 | WM8915_AIF1TX_SLOT_LEN_MASK, | 1840 | WM8915_AIF1TX_SLOT_LEN_MASK, |
1816 | aifdata); | 1841 | aifdata); |
1817 | snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk); | ||
1818 | snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, | 1842 | snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, |
1819 | lrclk); | 1843 | lrclk); |
1820 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, | 1844 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, |
1821 | WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); | 1845 | WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); |
1822 | 1846 | ||
1823 | wm8915->rx_rate[dai->id] = params_rate(params); | ||
1824 | |||
1825 | return 0; | 1847 | return 0; |
1826 | } | 1848 | } |
1827 | 1849 | ||
@@ -1882,6 +1904,8 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, | |||
1882 | return -EINVAL; | 1904 | return -EINVAL; |
1883 | } | 1905 | } |
1884 | 1906 | ||
1907 | wm8915_update_bclk(codec); | ||
1908 | |||
1885 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, | 1909 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, |
1886 | WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, | 1910 | WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, |
1887 | src << WM8915_SYSCLK_SRC_SHIFT | ratediv); | 1911 | src << WM8915_SYSCLK_SRC_SHIFT | ratediv); |