diff options
Diffstat (limited to 'sound/soc/codecs/wm8915.c')
-rw-r--r-- | sound/soc/codecs/wm8915.c | 156 |
1 files changed, 110 insertions, 46 deletions
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c index e2ab4fac281..423baa9be24 100644 --- a/sound/soc/codecs/wm8915.c +++ b/sound/soc/codecs/wm8915.c | |||
@@ -41,14 +41,12 @@ | |||
41 | #define HPOUT2L 4 | 41 | #define HPOUT2L 4 |
42 | #define HPOUT2R 8 | 42 | #define HPOUT2R 8 |
43 | 43 | ||
44 | #define WM8915_NUM_SUPPLIES 6 | 44 | #define WM8915_NUM_SUPPLIES 4 |
45 | static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { | 45 | static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { |
46 | "DCVDD", | ||
47 | "DBVDD", | 46 | "DBVDD", |
48 | "AVDD1", | 47 | "AVDD1", |
49 | "AVDD2", | 48 | "AVDD2", |
50 | "CPVDD", | 49 | "CPVDD", |
51 | "MICVDD", | ||
52 | }; | 50 | }; |
53 | 51 | ||
54 | struct wm8915_priv { | 52 | struct wm8915_priv { |
@@ -57,6 +55,7 @@ struct wm8915_priv { | |||
57 | int ldo1ena; | 55 | int ldo1ena; |
58 | 56 | ||
59 | int sysclk; | 57 | int sysclk; |
58 | int sysclk_src; | ||
60 | 59 | ||
61 | int fll_src; | 60 | int fll_src; |
62 | int fll_fref; | 61 | int fll_fref; |
@@ -76,6 +75,7 @@ struct wm8915_priv { | |||
76 | struct wm8915_pdata pdata; | 75 | struct wm8915_pdata pdata; |
77 | 76 | ||
78 | int rx_rate[WM8915_AIFS]; | 77 | int rx_rate[WM8915_AIFS]; |
78 | int bclk_rate[WM8915_AIFS]; | ||
79 | 79 | ||
80 | /* Platform dependant ReTune mobile configuration */ | 80 | /* Platform dependant ReTune mobile configuration */ |
81 | int num_retune_mobile_texts; | 81 | int num_retune_mobile_texts; |
@@ -113,8 +113,6 @@ WM8915_REGULATOR_EVENT(0) | |||
113 | WM8915_REGULATOR_EVENT(1) | 113 | WM8915_REGULATOR_EVENT(1) |
114 | WM8915_REGULATOR_EVENT(2) | 114 | WM8915_REGULATOR_EVENT(2) |
115 | WM8915_REGULATOR_EVENT(3) | 115 | WM8915_REGULATOR_EVENT(3) |
116 | WM8915_REGULATOR_EVENT(4) | ||
117 | WM8915_REGULATOR_EVENT(5) | ||
118 | 116 | ||
119 | static const u16 wm8915_reg[WM8915_MAX_REGISTER] = { | 117 | static const u16 wm8915_reg[WM8915_MAX_REGISTER] = { |
120 | [WM8915_SOFTWARE_RESET] = 0x8915, | 118 | [WM8915_SOFTWARE_RESET] = 0x8915, |
@@ -1565,6 +1563,50 @@ static int wm8915_reset(struct snd_soc_codec *codec) | |||
1565 | return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); | 1563 | return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); |
1566 | } | 1564 | } |
1567 | 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 | |||
1568 | static int wm8915_set_bias_level(struct snd_soc_codec *codec, | 1610 | static int wm8915_set_bias_level(struct snd_soc_codec *codec, |
1569 | enum snd_soc_bias_level level) | 1611 | enum snd_soc_bias_level level) |
1570 | { | 1612 | { |
@@ -1717,10 +1759,6 @@ static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1717 | return 0; | 1759 | return 0; |
1718 | } | 1760 | } |
1719 | 1761 | ||
1720 | static const int bclk_divs[] = { | ||
1721 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 | ||
1722 | }; | ||
1723 | |||
1724 | static const int dsp_divs[] = { | 1762 | static const int dsp_divs[] = { |
1725 | 48000, 32000, 16000, 8000 | 1763 | 48000, 32000, 16000, 8000 |
1726 | }; | 1764 | }; |
@@ -1731,17 +1769,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1731 | { | 1769 | { |
1732 | struct snd_soc_codec *codec = dai->codec; | 1770 | struct snd_soc_codec *codec = dai->codec; |
1733 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 1771 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
1734 | int bits, i, bclk_rate, best, cur_val; | 1772 | int bits, i, bclk_rate; |
1735 | int aifdata = 0; | 1773 | int aifdata = 0; |
1736 | int bclk = 0; | ||
1737 | int lrclk = 0; | 1774 | int lrclk = 0; |
1738 | int dsp = 0; | 1775 | int dsp = 0; |
1739 | int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift; | 1776 | int aifdata_reg, lrclk_reg, dsp_shift; |
1740 | |||
1741 | if (!wm8915->sysclk) { | ||
1742 | dev_err(codec->dev, "SYSCLK not configured\n"); | ||
1743 | return -EINVAL; | ||
1744 | } | ||
1745 | 1777 | ||
1746 | switch (dai->id) { | 1778 | switch (dai->id) { |
1747 | case 0: | 1779 | case 0: |
@@ -1753,7 +1785,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1753 | aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; | 1785 | aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; |
1754 | lrclk_reg = WM8915_AIF1_TX_LRCLK_1; | 1786 | lrclk_reg = WM8915_AIF1_TX_LRCLK_1; |
1755 | } | 1787 | } |
1756 | bclk_reg = WM8915_AIF1_BCLK; | ||
1757 | dsp_shift = 0; | 1788 | dsp_shift = 0; |
1758 | break; | 1789 | break; |
1759 | case 1: | 1790 | case 1: |
@@ -1765,7 +1796,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1765 | aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; | 1796 | aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; |
1766 | lrclk_reg = WM8915_AIF2_TX_LRCLK_1; | 1797 | lrclk_reg = WM8915_AIF2_TX_LRCLK_1; |
1767 | } | 1798 | } |
1768 | bclk_reg = WM8915_AIF2_BCLK; | ||
1769 | dsp_shift = WM8915_DSP2_DIV_SHIFT; | 1799 | dsp_shift = WM8915_DSP2_DIV_SHIFT; |
1770 | break; | 1800 | break; |
1771 | default: | 1801 | default: |
@@ -1779,6 +1809,9 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1779 | return bclk_rate; | 1809 | return bclk_rate; |
1780 | } | 1810 | } |
1781 | 1811 | ||
1812 | wm8915->bclk_rate[dai->id] = bclk_rate; | ||
1813 | wm8915->rx_rate[dai->id] = params_rate(params); | ||
1814 | |||
1782 | /* Needs looking at for TDM */ | 1815 | /* Needs looking at for TDM */ |
1783 | bits = snd_pcm_format_width(params_format(params)); | 1816 | bits = snd_pcm_format_width(params_format(params)); |
1784 | if (bits < 0) | 1817 | if (bits < 0) |
@@ -1796,18 +1829,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1796 | } | 1829 | } |
1797 | dsp |= i << dsp_shift; | 1830 | dsp |= i << dsp_shift; |
1798 | 1831 | ||
1799 | /* Pick a divisor for BCLK as close as we can get to ideal */ | 1832 | wm8915_update_bclk(codec); |
1800 | best = 0; | ||
1801 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
1802 | cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; | ||
1803 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1804 | break; | ||
1805 | best = i; | ||
1806 | } | ||
1807 | bclk_rate = wm8915->sysclk / bclk_divs[best]; | ||
1808 | dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", | ||
1809 | bclk_divs[best], bclk_rate); | ||
1810 | bclk |= best; | ||
1811 | 1833 | ||
1812 | lrclk = bclk_rate / params_rate(params); | 1834 | lrclk = bclk_rate / params_rate(params); |
1813 | 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", |
@@ -1817,14 +1839,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1817 | WM8915_AIF1TX_WL_MASK | | 1839 | WM8915_AIF1TX_WL_MASK | |
1818 | WM8915_AIF1TX_SLOT_LEN_MASK, | 1840 | WM8915_AIF1TX_SLOT_LEN_MASK, |
1819 | aifdata); | 1841 | aifdata); |
1820 | snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk); | ||
1821 | snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, | 1842 | snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, |
1822 | lrclk); | 1843 | lrclk); |
1823 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, | 1844 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, |
1824 | WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); | 1845 | WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); |
1825 | 1846 | ||
1826 | wm8915->rx_rate[dai->id] = params_rate(params); | ||
1827 | |||
1828 | return 0; | 1847 | return 0; |
1829 | } | 1848 | } |
1830 | 1849 | ||
@@ -1838,6 +1857,9 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, | |||
1838 | int src; | 1857 | int src; |
1839 | int old; | 1858 | int old; |
1840 | 1859 | ||
1860 | if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src) | ||
1861 | return 0; | ||
1862 | |||
1841 | /* Disable SYSCLK while we reconfigure */ | 1863 | /* Disable SYSCLK while we reconfigure */ |
1842 | old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA; | 1864 | old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA; |
1843 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, | 1865 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, |
@@ -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); |
@@ -1889,6 +1913,8 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, | |||
1889 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, | 1913 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, |
1890 | WM8915_SYSCLK_ENA, old); | 1914 | WM8915_SYSCLK_ENA, old); |
1891 | 1915 | ||
1916 | wm8915->sysclk_src = clk_id; | ||
1917 | |||
1892 | return 0; | 1918 | return 0; |
1893 | } | 1919 | } |
1894 | 1920 | ||
@@ -2007,6 +2033,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
2007 | unsigned int Fref, unsigned int Fout) | 2033 | unsigned int Fref, unsigned int Fout) |
2008 | { | 2034 | { |
2009 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 2035 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
2036 | struct i2c_client *i2c = to_i2c_client(codec->dev); | ||
2010 | struct _fll_div fll_div; | 2037 | struct _fll_div fll_div; |
2011 | unsigned long timeout; | 2038 | unsigned long timeout; |
2012 | int ret, reg; | 2039 | int ret, reg; |
@@ -2093,7 +2120,18 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
2093 | else | 2120 | else |
2094 | timeout = msecs_to_jiffies(2); | 2121 | timeout = msecs_to_jiffies(2); |
2095 | 2122 | ||
2096 | wait_for_completion_timeout(&wm8915->fll_lock, timeout); | 2123 | /* Allow substantially longer if we've actually got the IRQ */ |
2124 | if (i2c->irq) | ||
2125 | timeout *= 1000; | ||
2126 | |||
2127 | ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout); | ||
2128 | |||
2129 | if (ret == 0 && i2c->irq) { | ||
2130 | dev_err(codec->dev, "Timed out waiting for FLL\n"); | ||
2131 | ret = -ETIMEDOUT; | ||
2132 | } else { | ||
2133 | ret = 0; | ||
2134 | } | ||
2097 | 2135 | ||
2098 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); | 2136 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); |
2099 | 2137 | ||
@@ -2101,7 +2139,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
2101 | wm8915->fll_fout = Fout; | 2139 | wm8915->fll_fout = Fout; |
2102 | wm8915->fll_src = source; | 2140 | wm8915->fll_src = source; |
2103 | 2141 | ||
2104 | return 0; | 2142 | return ret; |
2105 | } | 2143 | } |
2106 | 2144 | ||
2107 | #ifdef CONFIG_GPIOLIB | 2145 | #ifdef CONFIG_GPIOLIB |
@@ -2293,6 +2331,12 @@ static void wm8915_micd(struct snd_soc_codec *codec) | |||
2293 | SND_JACK_HEADSET | SND_JACK_BTN_0); | 2331 | SND_JACK_HEADSET | SND_JACK_BTN_0); |
2294 | wm8915->jack_mic = true; | 2332 | wm8915->jack_mic = true; |
2295 | wm8915->detecting = false; | 2333 | wm8915->detecting = false; |
2334 | |||
2335 | /* Increase poll rate to give better responsiveness | ||
2336 | * for buttons */ | ||
2337 | snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, | ||
2338 | WM8915_MICD_RATE_MASK, | ||
2339 | 5 << WM8915_MICD_RATE_SHIFT); | ||
2296 | } | 2340 | } |
2297 | 2341 | ||
2298 | /* If we detected a lower impedence during initial startup | 2342 | /* If we detected a lower impedence during initial startup |
@@ -2333,15 +2377,17 @@ static void wm8915_micd(struct snd_soc_codec *codec) | |||
2333 | SND_JACK_HEADPHONE, | 2377 | SND_JACK_HEADPHONE, |
2334 | SND_JACK_HEADSET | | 2378 | SND_JACK_HEADSET | |
2335 | SND_JACK_BTN_0); | 2379 | SND_JACK_BTN_0); |
2380 | |||
2381 | /* Increase the detection rate a bit for | ||
2382 | * responsiveness. | ||
2383 | */ | ||
2384 | snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, | ||
2385 | WM8915_MICD_RATE_MASK, | ||
2386 | 7 << WM8915_MICD_RATE_SHIFT); | ||
2387 | |||
2336 | wm8915->detecting = false; | 2388 | wm8915->detecting = false; |
2337 | } | 2389 | } |
2338 | } | 2390 | } |
2339 | |||
2340 | /* Increase poll rate to give better responsiveness for buttons */ | ||
2341 | if (!wm8915->detecting) | ||
2342 | snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, | ||
2343 | WM8915_MICD_RATE_MASK, | ||
2344 | 5 << WM8915_MICD_RATE_SHIFT); | ||
2345 | } | 2391 | } |
2346 | 2392 | ||
2347 | static irqreturn_t wm8915_irq(int irq, void *data) | 2393 | static irqreturn_t wm8915_irq(int irq, void *data) |
@@ -2383,6 +2429,20 @@ static irqreturn_t wm8915_irq(int irq, void *data) | |||
2383 | } | 2429 | } |
2384 | } | 2430 | } |
2385 | 2431 | ||
2432 | static irqreturn_t wm8915_edge_irq(int irq, void *data) | ||
2433 | { | ||
2434 | irqreturn_t ret = IRQ_NONE; | ||
2435 | irqreturn_t val; | ||
2436 | |||
2437 | do { | ||
2438 | val = wm8915_irq(irq, data); | ||
2439 | if (val != IRQ_NONE) | ||
2440 | ret = val; | ||
2441 | } while (val != IRQ_NONE); | ||
2442 | |||
2443 | return ret; | ||
2444 | } | ||
2445 | |||
2386 | static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) | 2446 | static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) |
2387 | { | 2447 | { |
2388 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 2448 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
@@ -2482,8 +2542,6 @@ static int wm8915_probe(struct snd_soc_codec *codec) | |||
2482 | wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1; | 2542 | wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1; |
2483 | wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2; | 2543 | wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2; |
2484 | wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3; | 2544 | wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3; |
2485 | wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4; | ||
2486 | wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5; | ||
2487 | 2545 | ||
2488 | /* This should really be moved into the regulator core */ | 2546 | /* This should really be moved into the regulator core */ |
2489 | for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) { | 2547 | for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) { |
@@ -2709,8 +2767,14 @@ static int wm8915_probe(struct snd_soc_codec *codec) | |||
2709 | 2767 | ||
2710 | irq_flags |= IRQF_ONESHOT; | 2768 | irq_flags |= IRQF_ONESHOT; |
2711 | 2769 | ||
2712 | ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, | 2770 | if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) |
2713 | irq_flags, "wm8915", codec); | 2771 | ret = request_threaded_irq(i2c->irq, NULL, |
2772 | wm8915_edge_irq, | ||
2773 | irq_flags, "wm8915", codec); | ||
2774 | else | ||
2775 | ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, | ||
2776 | irq_flags, "wm8915", codec); | ||
2777 | |||
2714 | if (ret == 0) { | 2778 | if (ret == 0) { |
2715 | /* Unmask the interrupt */ | 2779 | /* Unmask the interrupt */ |
2716 | snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, | 2780 | snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, |