diff options
author | Carlo Caione <carlo@endlessm.com> | 2017-10-20 07:18:55 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-10-26 10:15:02 -0400 |
commit | 80bbe4a30bc6b119df86c280c91cde2034309bf1 (patch) | |
tree | 9ac5b6c85c47f343bbeb7fad269478695d841d9d | |
parent | be96fc54d2ed8eae6683b71d2dc5d1a939a10a1e (diff) |
ASoC: rt5651: Enable jack detection on JD* pins
Enable jack detection for the RT5651 codec on the JD* pins.
Signed-off-by: Carlo Caione <carlo@endlessm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | include/sound/rt5651.h | 8 | ||||
-rw-r--r-- | sound/soc/codecs/rt5651.c | 168 | ||||
-rw-r--r-- | sound/soc/codecs/rt5651.h | 4 |
3 files changed, 178 insertions, 2 deletions
diff --git a/include/sound/rt5651.h b/include/sound/rt5651.h index d35de758dfb5..18b79a761f10 100644 --- a/include/sound/rt5651.h +++ b/include/sound/rt5651.h | |||
@@ -11,11 +11,19 @@ | |||
11 | #ifndef __LINUX_SND_RT5651_H | 11 | #ifndef __LINUX_SND_RT5651_H |
12 | #define __LINUX_SND_RT5651_H | 12 | #define __LINUX_SND_RT5651_H |
13 | 13 | ||
14 | enum rt5651_jd_src { | ||
15 | RT5651_JD_NULL, | ||
16 | RT5651_JD1_1, | ||
17 | RT5651_JD1_2, | ||
18 | RT5651_JD2, | ||
19 | }; | ||
20 | |||
14 | struct rt5651_platform_data { | 21 | struct rt5651_platform_data { |
15 | /* IN2 can optionally be differential */ | 22 | /* IN2 can optionally be differential */ |
16 | bool in2_diff; | 23 | bool in2_diff; |
17 | 24 | ||
18 | bool dmic_en; | 25 | bool dmic_en; |
26 | enum rt5651_jd_src jd_src; | ||
19 | }; | 27 | }; |
20 | 28 | ||
21 | #endif | 29 | #endif |
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 28f7210cec91..91f254391452 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <sound/soc-dapm.h> | 26 | #include <sound/soc-dapm.h> |
27 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
28 | #include <sound/tlv.h> | 28 | #include <sound/tlv.h> |
29 | #include <sound/jack.h> | ||
29 | 30 | ||
30 | #include "rl6231.h" | 31 | #include "rl6231.h" |
31 | #include "rt5651.h" | 32 | #include "rt5651.h" |
@@ -880,6 +881,9 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { | |||
880 | SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2, | 881 | SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2, |
881 | RT5651_PWR_PLL_BIT, 0, NULL, 0), | 882 | RT5651_PWR_PLL_BIT, 0, NULL, 0), |
882 | /* Input Side */ | 883 | /* Input Side */ |
884 | SND_SOC_DAPM_SUPPLY("JD Power", RT5651_PWR_ANLG2, | ||
885 | RT5651_PWM_JD_M_BIT, 0, NULL, 0), | ||
886 | |||
883 | /* micbias */ | 887 | /* micbias */ |
884 | SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1, | 888 | SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1, |
885 | RT5651_PWR_LDO_BIT, 0, NULL, 0), | 889 | RT5651_PWR_LDO_BIT, 0, NULL, 0), |
@@ -1528,6 +1532,8 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, | |||
1528 | static int rt5651_set_bias_level(struct snd_soc_codec *codec, | 1532 | static int rt5651_set_bias_level(struct snd_soc_codec *codec, |
1529 | enum snd_soc_bias_level level) | 1533 | enum snd_soc_bias_level level) |
1530 | { | 1534 | { |
1535 | struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); | ||
1536 | |||
1531 | switch (level) { | 1537 | switch (level) { |
1532 | case SND_SOC_BIAS_PREPARE: | 1538 | case SND_SOC_BIAS_PREPARE: |
1533 | if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { | 1539 | if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { |
@@ -1556,8 +1562,13 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec, | |||
1556 | snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000); | 1562 | snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000); |
1557 | snd_soc_write(codec, RT5651_PWR_VOL, 0x0000); | 1563 | snd_soc_write(codec, RT5651_PWR_VOL, 0x0000); |
1558 | snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000); | 1564 | snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000); |
1559 | snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000); | 1565 | if (rt5651->pdata.jd_src) { |
1560 | snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000); | 1566 | snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0204); |
1567 | snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0002); | ||
1568 | } else { | ||
1569 | snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000); | ||
1570 | snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000); | ||
1571 | } | ||
1561 | break; | 1572 | break; |
1562 | 1573 | ||
1563 | default: | 1574 | default: |
@@ -1570,6 +1581,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec, | |||
1570 | static int rt5651_probe(struct snd_soc_codec *codec) | 1581 | static int rt5651_probe(struct snd_soc_codec *codec) |
1571 | { | 1582 | { |
1572 | struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); | 1583 | struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); |
1584 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1573 | 1585 | ||
1574 | rt5651->codec = codec; | 1586 | rt5651->codec = codec; |
1575 | 1587 | ||
@@ -1585,6 +1597,15 @@ static int rt5651_probe(struct snd_soc_codec *codec) | |||
1585 | 1597 | ||
1586 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); | 1598 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
1587 | 1599 | ||
1600 | if (rt5651->pdata.jd_src) { | ||
1601 | snd_soc_dapm_force_enable_pin(dapm, "JD Power"); | ||
1602 | snd_soc_dapm_force_enable_pin(dapm, "LDO"); | ||
1603 | snd_soc_dapm_sync(dapm); | ||
1604 | |||
1605 | regmap_update_bits(rt5651->regmap, RT5651_MICBIAS, | ||
1606 | 0x38, 0x38); | ||
1607 | } | ||
1608 | |||
1588 | return 0; | 1609 | return 0; |
1589 | } | 1610 | } |
1590 | 1611 | ||
@@ -1728,6 +1749,93 @@ static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np) | |||
1728 | return 0; | 1749 | return 0; |
1729 | } | 1750 | } |
1730 | 1751 | ||
1752 | static irqreturn_t rt5651_irq(int irq, void *data) | ||
1753 | { | ||
1754 | struct rt5651_priv *rt5651 = data; | ||
1755 | |||
1756 | queue_delayed_work(system_power_efficient_wq, | ||
1757 | &rt5651->jack_detect_work, msecs_to_jiffies(250)); | ||
1758 | |||
1759 | return IRQ_HANDLED; | ||
1760 | } | ||
1761 | |||
1762 | static int rt5651_jack_detect(struct snd_soc_codec *codec, int jack_insert) | ||
1763 | { | ||
1764 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1765 | int jack_type; | ||
1766 | |||
1767 | if (jack_insert) { | ||
1768 | snd_soc_dapm_force_enable_pin(dapm, "LDO"); | ||
1769 | snd_soc_dapm_sync(dapm); | ||
1770 | |||
1771 | snd_soc_update_bits(codec, RT5651_MICBIAS, | ||
1772 | RT5651_MIC1_OVCD_MASK | | ||
1773 | RT5651_MIC1_OVTH_MASK | | ||
1774 | RT5651_PWR_CLK12M_MASK | | ||
1775 | RT5651_PWR_MB_MASK, | ||
1776 | RT5651_MIC1_OVCD_EN | | ||
1777 | RT5651_MIC1_OVTH_600UA | | ||
1778 | RT5651_PWR_MB_PU | | ||
1779 | RT5651_PWR_CLK12M_PU); | ||
1780 | msleep(100); | ||
1781 | if (snd_soc_read(codec, RT5651_IRQ_CTRL2) & RT5651_MB1_OC_CLR) | ||
1782 | jack_type = SND_JACK_HEADPHONE; | ||
1783 | else | ||
1784 | jack_type = SND_JACK_HEADSET; | ||
1785 | snd_soc_update_bits(codec, RT5651_IRQ_CTRL2, | ||
1786 | RT5651_MB1_OC_CLR, 0); | ||
1787 | } else { /* jack out */ | ||
1788 | jack_type = 0; | ||
1789 | |||
1790 | snd_soc_update_bits(codec, RT5651_MICBIAS, | ||
1791 | RT5651_MIC1_OVCD_MASK, | ||
1792 | RT5651_MIC1_OVCD_DIS); | ||
1793 | } | ||
1794 | |||
1795 | return jack_type; | ||
1796 | } | ||
1797 | |||
1798 | static void rt5651_jack_detect_work(struct work_struct *work) | ||
1799 | { | ||
1800 | struct rt5651_priv *rt5651 = | ||
1801 | container_of(work, struct rt5651_priv, jack_detect_work.work); | ||
1802 | |||
1803 | int report, val = 0; | ||
1804 | |||
1805 | if (!rt5651->codec) | ||
1806 | return; | ||
1807 | |||
1808 | switch (rt5651->pdata.jd_src) { | ||
1809 | case RT5651_JD1_1: | ||
1810 | val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x1000; | ||
1811 | break; | ||
1812 | case RT5651_JD1_2: | ||
1813 | val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x2000; | ||
1814 | break; | ||
1815 | case RT5651_JD2: | ||
1816 | val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x4000; | ||
1817 | break; | ||
1818 | default: | ||
1819 | break; | ||
1820 | } | ||
1821 | |||
1822 | report = rt5651_jack_detect(rt5651->codec, !val); | ||
1823 | |||
1824 | snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); | ||
1825 | } | ||
1826 | |||
1827 | int rt5651_set_jack_detect(struct snd_soc_codec *codec, | ||
1828 | struct snd_soc_jack *hp_jack) | ||
1829 | { | ||
1830 | struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); | ||
1831 | |||
1832 | rt5651->hp_jack = hp_jack; | ||
1833 | rt5651_irq(0, rt5651); | ||
1834 | |||
1835 | return 0; | ||
1836 | } | ||
1837 | EXPORT_SYMBOL_GPL(rt5651_set_jack_detect); | ||
1838 | |||
1731 | static int rt5651_i2c_probe(struct i2c_client *i2c, | 1839 | static int rt5651_i2c_probe(struct i2c_client *i2c, |
1732 | const struct i2c_device_id *id) | 1840 | const struct i2c_device_id *id) |
1733 | { | 1841 | { |
@@ -1779,6 +1887,59 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, | |||
1779 | 1887 | ||
1780 | rt5651->hp_mute = 1; | 1888 | rt5651->hp_mute = 1; |
1781 | 1889 | ||
1890 | if (rt5651->pdata.jd_src) { | ||
1891 | |||
1892 | /* IRQ output on GPIO1 */ | ||
1893 | regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1, | ||
1894 | RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); | ||
1895 | |||
1896 | switch (rt5651->pdata.jd_src) { | ||
1897 | case RT5651_JD1_1: | ||
1898 | regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2, | ||
1899 | RT5651_JD_TRG_SEL_MASK, | ||
1900 | RT5651_JD_TRG_SEL_JD1_1); | ||
1901 | regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1, | ||
1902 | RT5651_JD1_1_IRQ_EN, | ||
1903 | RT5651_JD1_1_IRQ_EN); | ||
1904 | break; | ||
1905 | case RT5651_JD1_2: | ||
1906 | regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2, | ||
1907 | RT5651_JD_TRG_SEL_MASK, | ||
1908 | RT5651_JD_TRG_SEL_JD1_2); | ||
1909 | regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1, | ||
1910 | RT5651_JD1_2_IRQ_EN, | ||
1911 | RT5651_JD1_2_IRQ_EN); | ||
1912 | break; | ||
1913 | case RT5651_JD2: | ||
1914 | regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2, | ||
1915 | RT5651_JD_TRG_SEL_MASK, | ||
1916 | RT5651_JD_TRG_SEL_JD2); | ||
1917 | regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1, | ||
1918 | RT5651_JD2_IRQ_EN, | ||
1919 | RT5651_JD2_IRQ_EN); | ||
1920 | break; | ||
1921 | case RT5651_JD_NULL: | ||
1922 | break; | ||
1923 | default: | ||
1924 | dev_warn(&i2c->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); | ||
1925 | break; | ||
1926 | } | ||
1927 | } | ||
1928 | |||
1929 | INIT_DELAYED_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); | ||
1930 | |||
1931 | if (i2c->irq) { | ||
1932 | ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, | ||
1933 | rt5651_irq, | ||
1934 | IRQF_TRIGGER_RISING | | ||
1935 | IRQF_TRIGGER_FALLING | | ||
1936 | IRQF_ONESHOT, "rt5651", rt5651); | ||
1937 | if (ret) { | ||
1938 | dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); | ||
1939 | return ret; | ||
1940 | } | ||
1941 | } | ||
1942 | |||
1782 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651, | 1943 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651, |
1783 | rt5651_dai, ARRAY_SIZE(rt5651_dai)); | 1944 | rt5651_dai, ARRAY_SIZE(rt5651_dai)); |
1784 | 1945 | ||
@@ -1787,6 +1948,9 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, | |||
1787 | 1948 | ||
1788 | static int rt5651_i2c_remove(struct i2c_client *i2c) | 1949 | static int rt5651_i2c_remove(struct i2c_client *i2c) |
1789 | { | 1950 | { |
1951 | struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c); | ||
1952 | |||
1953 | cancel_delayed_work_sync(&rt5651->jack_detect_work); | ||
1790 | snd_soc_unregister_codec(&i2c->dev); | 1954 | snd_soc_unregister_codec(&i2c->dev); |
1791 | 1955 | ||
1792 | return 0; | 1956 | return 0; |
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index 1bd33cfa6411..4f8b202121d7 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h | |||
@@ -2062,6 +2062,8 @@ struct rt5651_priv { | |||
2062 | struct snd_soc_codec *codec; | 2062 | struct snd_soc_codec *codec; |
2063 | struct rt5651_platform_data pdata; | 2063 | struct rt5651_platform_data pdata; |
2064 | struct regmap *regmap; | 2064 | struct regmap *regmap; |
2065 | struct snd_soc_jack *hp_jack; | ||
2066 | struct delayed_work jack_detect_work; | ||
2065 | 2067 | ||
2066 | int sysclk; | 2068 | int sysclk; |
2067 | int sysclk_src; | 2069 | int sysclk_src; |
@@ -2077,4 +2079,6 @@ struct rt5651_priv { | |||
2077 | bool hp_mute; | 2079 | bool hp_mute; |
2078 | }; | 2080 | }; |
2079 | 2081 | ||
2082 | int rt5651_set_jack_detect(struct snd_soc_codec *codec, | ||
2083 | struct snd_soc_jack *hp_jack); | ||
2080 | #endif /* __RT5651_H__ */ | 2084 | #endif /* __RT5651_H__ */ |