diff options
author | Rhyland Klein <rklein@nvidia.com> | 2012-03-15 18:07:47 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-04-01 06:28:24 -0400 |
commit | 9dd90c5db0401061009183e6407feff3724ebc8b (patch) | |
tree | 462b883850965aba52919f438474e5888f7de6a5 /sound | |
parent | 5f1cba63a3a65b01a70ac09914176bb3719725d6 (diff) |
ASoC: max98095: add jack detection
This change adds the logic to support using the jack detect mechanism built
in to the codec to detect both when a jack was inserted and what type of
jack is present.
This change also supports the use of an external mechanism for headphone
detection. If this mechanism exists, when the max98095_jack_detect function
is called, the hp_jack is simply passed NULL.
This change supports both simple headphones, powered headphones, microphones
and headsets with both headphones and a mic.
Signed-off-by: Rhyland Klein <rklein@nvidia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/max98095.c | 158 | ||||
-rw-r--r-- | sound/soc/codecs/max98095.h | 22 |
2 files changed, 179 insertions, 1 deletions
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 0bb511a0388d..0752840e01c2 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <asm/div64.h> | 25 | #include <asm/div64.h> |
26 | #include <sound/max98095.h> | 26 | #include <sound/max98095.h> |
27 | #include <sound/jack.h> | ||
27 | #include "max98095.h" | 28 | #include "max98095.h" |
28 | 29 | ||
29 | enum max98095_type { | 30 | enum max98095_type { |
@@ -51,6 +52,8 @@ struct max98095_priv { | |||
51 | u8 lin_state; | 52 | u8 lin_state; |
52 | unsigned int mic1pre; | 53 | unsigned int mic1pre; |
53 | unsigned int mic2pre; | 54 | unsigned int mic2pre; |
55 | struct snd_soc_jack *headphone_jack; | ||
56 | struct snd_soc_jack *mic_jack; | ||
54 | }; | 57 | }; |
55 | 58 | ||
56 | static const u8 max98095_reg_def[M98095_REG_CNT] = { | 59 | static const u8 max98095_reg_def[M98095_REG_CNT] = { |
@@ -2173,9 +2176,125 @@ static void max98095_handle_pdata(struct snd_soc_codec *codec) | |||
2173 | max98095_handle_bq_pdata(codec); | 2176 | max98095_handle_bq_pdata(codec); |
2174 | } | 2177 | } |
2175 | 2178 | ||
2179 | static irqreturn_t max98095_report_jack(int irq, void *data) | ||
2180 | { | ||
2181 | struct snd_soc_codec *codec = data; | ||
2182 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | ||
2183 | unsigned int value; | ||
2184 | int hp_report = 0; | ||
2185 | int mic_report = 0; | ||
2186 | |||
2187 | /* Read the Jack Status Register */ | ||
2188 | value = snd_soc_read(codec, M98095_007_JACK_AUTO_STS); | ||
2189 | |||
2190 | /* If ddone is not set, then detection isn't finished yet */ | ||
2191 | if ((value & M98095_DDONE) == 0) | ||
2192 | return IRQ_NONE; | ||
2193 | |||
2194 | /* if hp, check its bit, and if set, clear it */ | ||
2195 | if ((value & M98095_HP_IN || value & M98095_LO_IN) && | ||
2196 | max98095->headphone_jack) | ||
2197 | hp_report |= SND_JACK_HEADPHONE; | ||
2198 | |||
2199 | /* if mic, check its bit, and if set, clear it */ | ||
2200 | if ((value & M98095_MIC_IN) && max98095->mic_jack) | ||
2201 | mic_report |= SND_JACK_MICROPHONE; | ||
2202 | |||
2203 | if (max98095->headphone_jack == max98095->mic_jack) { | ||
2204 | snd_soc_jack_report(max98095->headphone_jack, | ||
2205 | hp_report | mic_report, | ||
2206 | SND_JACK_HEADSET); | ||
2207 | } else { | ||
2208 | if (max98095->headphone_jack) | ||
2209 | snd_soc_jack_report(max98095->headphone_jack, | ||
2210 | hp_report, SND_JACK_HEADPHONE); | ||
2211 | if (max98095->mic_jack) | ||
2212 | snd_soc_jack_report(max98095->mic_jack, | ||
2213 | mic_report, SND_JACK_MICROPHONE); | ||
2214 | } | ||
2215 | |||
2216 | return IRQ_HANDLED; | ||
2217 | } | ||
2218 | |||
2219 | int max98095_jack_detect_enable(struct snd_soc_codec *codec) | ||
2220 | { | ||
2221 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | ||
2222 | int ret = 0; | ||
2223 | int detect_enable = M98095_JDEN; | ||
2224 | unsigned int slew = M98095_DEFAULT_SLEW_DELAY; | ||
2225 | |||
2226 | if (max98095->pdata->jack_detect_pin5en) | ||
2227 | detect_enable |= M98095_PIN5EN; | ||
2228 | |||
2229 | if (max98095->jack_detect_delay) | ||
2230 | slew = max98095->jack_detect_delay; | ||
2231 | |||
2232 | ret = snd_soc_write(codec, M98095_08E_JACK_DC_SLEW, slew); | ||
2233 | if (ret < 0) { | ||
2234 | dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret); | ||
2235 | return ret; | ||
2236 | } | ||
2237 | |||
2238 | /* configure auto detection to be enabled */ | ||
2239 | ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, detect_enable); | ||
2240 | if (ret < 0) { | ||
2241 | dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret); | ||
2242 | return ret; | ||
2243 | } | ||
2244 | |||
2245 | return ret; | ||
2246 | } | ||
2247 | |||
2248 | int max98095_jack_detect_disable(struct snd_soc_codec *codec) | ||
2249 | { | ||
2250 | int ret = 0; | ||
2251 | |||
2252 | /* configure auto detection to be disabled */ | ||
2253 | ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, 0x0); | ||
2254 | if (ret < 0) { | ||
2255 | dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret); | ||
2256 | return ret; | ||
2257 | } | ||
2258 | |||
2259 | return ret; | ||
2260 | } | ||
2261 | |||
2262 | int max98095_jack_detect(struct snd_soc_codec *codec, | ||
2263 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack) | ||
2264 | { | ||
2265 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | ||
2266 | struct i2c_client *client = to_i2c_client(codec->dev); | ||
2267 | int ret = 0; | ||
2268 | |||
2269 | max98095->headphone_jack = hp_jack; | ||
2270 | max98095->mic_jack = mic_jack; | ||
2271 | |||
2272 | /* only progress if we have at least 1 jack pointer */ | ||
2273 | if (!hp_jack && !mic_jack) | ||
2274 | return -EINVAL; | ||
2275 | |||
2276 | max98095_jack_detect_enable(codec); | ||
2277 | |||
2278 | /* enable interrupts for headphone jack detection */ | ||
2279 | ret = snd_soc_update_bits(codec, M98095_013_JACK_INT_EN, | ||
2280 | M98095_IDDONE, M98095_IDDONE); | ||
2281 | if (ret < 0) { | ||
2282 | dev_err(codec->dev, "Failed to cfg jack irqs %d\n", ret); | ||
2283 | return ret; | ||
2284 | } | ||
2285 | |||
2286 | max98095_report_jack(client->irq, codec); | ||
2287 | return 0; | ||
2288 | } | ||
2289 | |||
2176 | #ifdef CONFIG_PM | 2290 | #ifdef CONFIG_PM |
2177 | static int max98095_suspend(struct snd_soc_codec *codec) | 2291 | static int max98095_suspend(struct snd_soc_codec *codec) |
2178 | { | 2292 | { |
2293 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | ||
2294 | |||
2295 | if (max98095->headphone_jack || max98095->mic_jack) | ||
2296 | max98095_jack_detect_disable(codec); | ||
2297 | |||
2179 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2298 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2180 | 2299 | ||
2181 | return 0; | 2300 | return 0; |
@@ -2183,8 +2302,16 @@ static int max98095_suspend(struct snd_soc_codec *codec) | |||
2183 | 2302 | ||
2184 | static int max98095_resume(struct snd_soc_codec *codec) | 2303 | static int max98095_resume(struct snd_soc_codec *codec) |
2185 | { | 2304 | { |
2305 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | ||
2306 | struct i2c_client *client = to_i2c_client(codec->dev); | ||
2307 | |||
2186 | max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 2308 | max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
2187 | 2309 | ||
2310 | if (max98095->headphone_jack || max98095->mic_jack) { | ||
2311 | max98095_jack_detect_enable(codec); | ||
2312 | max98095_report_jack(client->irq, codec); | ||
2313 | } | ||
2314 | |||
2188 | return 0; | 2315 | return 0; |
2189 | } | 2316 | } |
2190 | #else | 2317 | #else |
@@ -2227,6 +2354,7 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2227 | { | 2354 | { |
2228 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 2355 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
2229 | struct max98095_cdata *cdata; | 2356 | struct max98095_cdata *cdata; |
2357 | struct i2c_client *client; | ||
2230 | int ret = 0; | 2358 | int ret = 0; |
2231 | 2359 | ||
2232 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | 2360 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); |
@@ -2238,6 +2366,8 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2238 | /* reset the codec, the DSP core, and disable all interrupts */ | 2366 | /* reset the codec, the DSP core, and disable all interrupts */ |
2239 | max98095_reset(codec); | 2367 | max98095_reset(codec); |
2240 | 2368 | ||
2369 | client = to_i2c_client(codec->dev); | ||
2370 | |||
2241 | /* initialize private data */ | 2371 | /* initialize private data */ |
2242 | 2372 | ||
2243 | max98095->sysclk = (unsigned)-1; | 2373 | max98095->sysclk = (unsigned)-1; |
@@ -2266,11 +2396,23 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2266 | max98095->mic1pre = 0; | 2396 | max98095->mic1pre = 0; |
2267 | max98095->mic2pre = 0; | 2397 | max98095->mic2pre = 0; |
2268 | 2398 | ||
2399 | if (client->irq) { | ||
2400 | /* register an audio interrupt */ | ||
2401 | ret = request_threaded_irq(client->irq, NULL, | ||
2402 | max98095_report_jack, | ||
2403 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
2404 | "max98095", codec); | ||
2405 | if (ret) { | ||
2406 | dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); | ||
2407 | goto err_access; | ||
2408 | } | ||
2409 | } | ||
2410 | |||
2269 | ret = snd_soc_read(codec, M98095_0FF_REV_ID); | 2411 | ret = snd_soc_read(codec, M98095_0FF_REV_ID); |
2270 | if (ret < 0) { | 2412 | if (ret < 0) { |
2271 | dev_err(codec->dev, "Failure reading hardware revision: %d\n", | 2413 | dev_err(codec->dev, "Failure reading hardware revision: %d\n", |
2272 | ret); | 2414 | ret); |
2273 | goto err_access; | 2415 | goto err_irq; |
2274 | } | 2416 | } |
2275 | dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A'); | 2417 | dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A'); |
2276 | 2418 | ||
@@ -2306,14 +2448,28 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2306 | 2448 | ||
2307 | max98095_add_widgets(codec); | 2449 | max98095_add_widgets(codec); |
2308 | 2450 | ||
2451 | return 0; | ||
2452 | |||
2453 | err_irq: | ||
2454 | if (client->irq) | ||
2455 | free_irq(client->irq, codec); | ||
2309 | err_access: | 2456 | err_access: |
2310 | return ret; | 2457 | return ret; |
2311 | } | 2458 | } |
2312 | 2459 | ||
2313 | static int max98095_remove(struct snd_soc_codec *codec) | 2460 | static int max98095_remove(struct snd_soc_codec *codec) |
2314 | { | 2461 | { |
2462 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | ||
2463 | struct i2c_client *client = to_i2c_client(codec->dev); | ||
2464 | |||
2315 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2465 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2316 | 2466 | ||
2467 | if (max98095->headphone_jack || max98095->mic_jack) | ||
2468 | max98095_jack_detect_disable(codec); | ||
2469 | |||
2470 | if (client->irq) | ||
2471 | free_irq(client->irq, codec); | ||
2472 | |||
2317 | return 0; | 2473 | return 0; |
2318 | } | 2474 | } |
2319 | 2475 | ||
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h index 891584a0eb03..2ebbe4e894bf 100644 --- a/sound/soc/codecs/max98095.h +++ b/sound/soc/codecs/max98095.h | |||
@@ -175,11 +175,23 @@ | |||
175 | 175 | ||
176 | /* MAX98095 Registers Bit Fields */ | 176 | /* MAX98095 Registers Bit Fields */ |
177 | 177 | ||
178 | /* M98095_007_JACK_AUTO_STS */ | ||
179 | #define M98095_MIC_IN (1<<3) | ||
180 | #define M98095_LO_IN (1<<5) | ||
181 | #define M98095_HP_IN (1<<6) | ||
182 | #define M98095_DDONE (1<<7) | ||
183 | |||
178 | /* M98095_00F_HOST_CFG */ | 184 | /* M98095_00F_HOST_CFG */ |
179 | #define M98095_SEG (1<<0) | 185 | #define M98095_SEG (1<<0) |
180 | #define M98095_XTEN (1<<1) | 186 | #define M98095_XTEN (1<<1) |
181 | #define M98095_MDLLEN (1<<2) | 187 | #define M98095_MDLLEN (1<<2) |
182 | 188 | ||
189 | /* M98095_013_JACK_INT_EN */ | ||
190 | #define M98095_IMIC_IN (1<<3) | ||
191 | #define M98095_ILO_IN (1<<5) | ||
192 | #define M98095_IHP_IN (1<<6) | ||
193 | #define M98095_IDDONE (1<<7) | ||
194 | |||
183 | /* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */ | 195 | /* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */ |
184 | #define M98095_CLKMODE_MASK 0xFF | 196 | #define M98095_CLKMODE_MASK 0xFF |
185 | 197 | ||
@@ -255,6 +267,10 @@ | |||
255 | #define M98095_EQ2EN (1<<1) | 267 | #define M98095_EQ2EN (1<<1) |
256 | #define M98095_EQ1EN (1<<0) | 268 | #define M98095_EQ1EN (1<<0) |
257 | 269 | ||
270 | /* M98095_089_JACK_DET_AUTO */ | ||
271 | #define M98095_PIN5EN (1<<2) | ||
272 | #define M98095_JDEN (1<<7) | ||
273 | |||
258 | /* M98095_090_PWR_EN_IN */ | 274 | /* M98095_090_PWR_EN_IN */ |
259 | #define M98095_INEN (1<<7) | 275 | #define M98095_INEN (1<<7) |
260 | #define M98095_MB2EN (1<<3) | 276 | #define M98095_MB2EN (1<<3) |
@@ -296,4 +312,10 @@ | |||
296 | #define M98095_174_DAI1_BQ_BASE 0x74 | 312 | #define M98095_174_DAI1_BQ_BASE 0x74 |
297 | #define M98095_17E_DAI2_BQ_BASE 0x7E | 313 | #define M98095_17E_DAI2_BQ_BASE 0x7E |
298 | 314 | ||
315 | /* Default Delay used in Slew Rate Calculation for Jack detection */ | ||
316 | #define M98095_DEFAULT_SLEW_DELAY 0x18 | ||
317 | |||
318 | extern int max98095_jack_detect(struct snd_soc_codec *codec, | ||
319 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack); | ||
320 | |||
299 | #endif | 321 | #endif |