diff options
Diffstat (limited to 'sound/soc/codecs/rt5645.c')
-rw-r--r-- | sound/soc/codecs/rt5645.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a7762d0a623e..3fb83bf09768 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/gpio.h> | ||
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
@@ -2103,6 +2104,77 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2103 | return 0; | 2104 | return 0; |
2104 | } | 2105 | } |
2105 | 2106 | ||
2107 | static int rt5645_jack_detect(struct snd_soc_codec *codec, | ||
2108 | struct snd_soc_jack *jack) | ||
2109 | { | ||
2110 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2111 | int gpio_state, jack_type = 0; | ||
2112 | unsigned int val; | ||
2113 | |||
2114 | gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio); | ||
2115 | |||
2116 | dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio, | ||
2117 | gpio_state); | ||
2118 | |||
2119 | if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) || | ||
2120 | (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) { | ||
2121 | snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1"); | ||
2122 | snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2"); | ||
2123 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | ||
2124 | snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power"); | ||
2125 | snd_soc_dapm_sync(&codec->dapm); | ||
2126 | |||
2127 | snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006); | ||
2128 | snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0); | ||
2129 | |||
2130 | snd_soc_update_bits(codec, RT5645_IN1_CTRL2, | ||
2131 | RT5645_CBJ_MN_JD, 0); | ||
2132 | snd_soc_update_bits(codec, RT5645_IN1_CTRL2, | ||
2133 | RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); | ||
2134 | |||
2135 | msleep(400); | ||
2136 | val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7; | ||
2137 | dev_dbg(codec->dev, "val = %d\n", val); | ||
2138 | |||
2139 | if (val == 1 || val == 2) | ||
2140 | jack_type = SND_JACK_HEADSET; | ||
2141 | else | ||
2142 | jack_type = SND_JACK_HEADPHONE; | ||
2143 | |||
2144 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); | ||
2145 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); | ||
2146 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | ||
2147 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | ||
2148 | snd_soc_dapm_sync(&codec->dapm); | ||
2149 | } | ||
2150 | |||
2151 | snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET); | ||
2152 | |||
2153 | return 0; | ||
2154 | } | ||
2155 | |||
2156 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | ||
2157 | struct snd_soc_jack *jack) | ||
2158 | { | ||
2159 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2160 | |||
2161 | rt5645->jack = jack; | ||
2162 | |||
2163 | rt5645_jack_detect(codec, rt5645->jack); | ||
2164 | |||
2165 | return 0; | ||
2166 | } | ||
2167 | EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); | ||
2168 | |||
2169 | static irqreturn_t rt5645_irq(int irq, void *data) | ||
2170 | { | ||
2171 | struct rt5645_priv *rt5645 = data; | ||
2172 | |||
2173 | rt5645_jack_detect(rt5645->codec, rt5645->jack); | ||
2174 | |||
2175 | return IRQ_HANDLED; | ||
2176 | } | ||
2177 | |||
2106 | static int rt5645_probe(struct snd_soc_codec *codec) | 2178 | static int rt5645_probe(struct snd_soc_codec *codec) |
2107 | { | 2179 | { |
2108 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2180 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
@@ -2250,6 +2322,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2250 | if (rt5645 == NULL) | 2322 | if (rt5645 == NULL) |
2251 | return -ENOMEM; | 2323 | return -ENOMEM; |
2252 | 2324 | ||
2325 | rt5645->i2c = i2c; | ||
2253 | i2c_set_clientdata(i2c, rt5645); | 2326 | i2c_set_clientdata(i2c, rt5645); |
2254 | 2327 | ||
2255 | if (pdata) | 2328 | if (pdata) |
@@ -2345,12 +2418,38 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2345 | 2418 | ||
2346 | } | 2419 | } |
2347 | 2420 | ||
2421 | if (rt5645->i2c->irq) { | ||
2422 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, | ||
2423 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | ||
2424 | | IRQF_ONESHOT, "rt5645", rt5645); | ||
2425 | if (ret) | ||
2426 | dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); | ||
2427 | } | ||
2428 | |||
2429 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) { | ||
2430 | ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645"); | ||
2431 | if (ret) | ||
2432 | dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n"); | ||
2433 | |||
2434 | ret = gpio_direction_input(rt5645->pdata.hp_det_gpio); | ||
2435 | if (ret) | ||
2436 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); | ||
2437 | } | ||
2438 | |||
2348 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, | 2439 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, |
2349 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); | 2440 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); |
2350 | } | 2441 | } |
2351 | 2442 | ||
2352 | static int rt5645_i2c_remove(struct i2c_client *i2c) | 2443 | static int rt5645_i2c_remove(struct i2c_client *i2c) |
2353 | { | 2444 | { |
2445 | struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c); | ||
2446 | |||
2447 | if (i2c->irq) | ||
2448 | free_irq(i2c->irq, rt5645); | ||
2449 | |||
2450 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) | ||
2451 | gpio_free(rt5645->pdata.hp_det_gpio); | ||
2452 | |||
2354 | snd_soc_unregister_codec(&i2c->dev); | 2453 | snd_soc_unregister_codec(&i2c->dev); |
2355 | 2454 | ||
2356 | return 0; | 2455 | return 0; |