@ -2350,12 +2350,94 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
/* Enable interrupts and we're off */
snd_soc_update_bits ( codec , WM8996_INTERRUPT_STATUS_2_MASK ,
WM8996_IM_MICD_EINT , 0 ) ;
WM8996_IM_MICD_EINT | WM8996_HP_DONE_EINT , 0 ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( wm8996_detect ) ;
static void wm8996_hpdet_irq ( struct snd_soc_codec * codec )
{
struct wm8996_priv * wm8996 = snd_soc_codec_get_drvdata ( codec ) ;
int val , reg , report ;
/* Assume headphone in error conditions; we need to report
* something or we stall our state machine .
*/
report = SND_JACK_HEADPHONE ;
reg = snd_soc_read ( codec , WM8996_HEADPHONE_DETECT_2 ) ;
if ( reg < 0 ) {
dev_err ( codec - > dev , " Failed to read HPDET status \n " ) ;
goto out ;
}
if ( ! ( reg & WM8996_HP_DONE ) ) {
dev_err ( codec - > dev , " Got HPDET IRQ but HPDET is busy \n " ) ;
goto out ;
}
val = reg & WM8996_HP_LVL_MASK ;
dev_dbg ( codec - > dev , " HPDET measured %d ohms \n " , val ) ;
/* If we've got high enough impedence then report as line,
* otherwise assume headphone .
*/
if ( val > = 126 )
report = SND_JACK_LINEOUT ;
else
report = SND_JACK_HEADPHONE ;
out :
if ( wm8996 - > jack_mic )
report | = SND_JACK_MICROPHONE ;
snd_soc_jack_report ( wm8996 - > jack , report ,
SND_JACK_LINEOUT | SND_JACK_HEADSET ) ;
wm8996 - > detecting = false ;
/* If the output isn't running re-clamp it */
if ( ! ( snd_soc_read ( codec , WM8996_POWER_MANAGEMENT_1 ) &
( WM8996_HPOUT1L_ENA | WM8996_HPOUT1R_RMV_SHORT ) ) )
snd_soc_update_bits ( codec , WM8996_ANALOGUE_HP_1 ,
WM8996_HPOUT1L_RMV_SHORT |
WM8996_HPOUT1R_RMV_SHORT , 0 ) ;
/* Go back to looking at the microphone */
snd_soc_update_bits ( codec , WM8996_ACCESSORY_DETECT_MODE_1 ,
WM8996_JD_MODE_MASK , 0 ) ;
snd_soc_update_bits ( codec , WM8996_MIC_DETECT_1 , WM8996_MICD_ENA ,
WM8996_MICD_ENA ) ;
snd_soc_dapm_disable_pin ( & codec - > dapm , " Bandgap " ) ;
snd_soc_dapm_sync ( & codec - > dapm ) ;
}
static void wm8996_hpdet_start ( struct snd_soc_codec * codec )
{
/* Unclamp the output, we can't measure while we're shorting it */
snd_soc_update_bits ( codec , WM8996_ANALOGUE_HP_1 ,
WM8996_HPOUT1L_RMV_SHORT |
WM8996_HPOUT1R_RMV_SHORT ,
WM8996_HPOUT1L_RMV_SHORT |
WM8996_HPOUT1R_RMV_SHORT ) ;
/* We need bandgap for HPDET */
snd_soc_dapm_force_enable_pin ( & codec - > dapm , " Bandgap " ) ;
snd_soc_dapm_sync ( & codec - > dapm ) ;
/* Go into headphone detect left mode */
snd_soc_update_bits ( codec , WM8996_MIC_DETECT_1 , WM8996_MICD_ENA , 0 ) ;
snd_soc_update_bits ( codec , WM8996_ACCESSORY_DETECT_MODE_1 ,
WM8996_JD_MODE_MASK , 1 ) ;
/* Trigger a measurement */
snd_soc_update_bits ( codec , WM8996_HEADPHONE_DETECT_1 ,
WM8996_HP_POLL , WM8996_HP_POLL ) ;
}
static void wm8996_micd ( struct snd_soc_codec * codec )
{
struct wm8996_priv * wm8996 = snd_soc_codec_get_drvdata ( codec ) ;
@ -2376,28 +2458,36 @@ static void wm8996_micd(struct snd_soc_codec *codec)
wm8996 - > jack_mic = false ;
wm8996 - > detecting = true ;
snd_soc_jack_report ( wm8996 - > jack , 0 ,
SND_JACK_HEADSET | SND_JACK_BTN_0 ) ;
SND_JACK_LINEOUT | SND_JACK_HEADSET |
SND_JACK_BTN_0 ) ;
snd_soc_update_bits ( codec , WM8996_MIC_DETECT_1 ,
WM8996_MICD_RATE_MASK ,
WM8996_MICD_RATE_MASK ) ;
return ;
}
/* If the measurement is very high we've got a microphone but
* do a little debounce to account for mechanical issues .
/* If the measurement is very high we've got a microphone,
* either we just detected one or if we already reported then
* we ' ve got a button release event .
*/
if ( val & 0x400 ) {
dev_dbg ( codec - > dev , " Microphone detected \n " ) ;
snd_soc_jack_report ( wm8996 - > jack , SND_JACK_HEADSET ,
SND_JACK_HEADSET | SND_JACK_BTN_0 ) ;
wm8996 - > jack_mic = true ;
wm8996 - > detecting = false ;
/* Increase poll rate to give better responsiveness
* for buttons */
snd_soc_update_bits ( codec , WM8996_MIC_DETECT_1 ,
WM8996_MICD_RATE_MASK ,
5 < < WM8996_MICD_RATE_SHIFT ) ;
if ( wm8996 - > detecting ) {
dev_dbg ( codec - > dev , " Microphone detected \n " ) ;
wm8996 - > jack_mic = true ;
wm8996_hpdet_start ( codec ) ;
/* Increase poll rate to give better responsiveness
* for buttons */
snd_soc_update_bits ( codec , WM8996_MIC_DETECT_1 ,
WM8996_MICD_RATE_MASK ,
5 < < WM8996_MICD_RATE_SHIFT ) ;
} else {
dev_dbg ( codec - > dev , " Mic button up \n " ) ;
snd_soc_jack_report ( wm8996 - > jack , 0 , SND_JACK_BTN_0 ) ;
}
return ;
}
/* If we detected a lower impedence during initial startup
@ -2429,15 +2519,11 @@ static void wm8996_micd(struct snd_soc_codec *codec)
if ( val & 0x3fc ) {
if ( wm8996 - > jack_mic ) {
dev_dbg ( codec - > dev , " Mic button detected \n " ) ;
snd_soc_jack_report ( wm8996 - > jack ,
SND_JACK_HEADSET | SND_JACK_BTN_0 ,
SND_JACK_HEADSET | SND_JACK_BTN_0 ) ;
} else {
dev_dbg ( codec - > dev , " Headphone detected \n " ) ;
snd_soc_jack_report ( wm8996 - > jack ,
SND_JACK_HEADPHONE ,
SND_JACK_HEADSET |
snd_soc_jack_report ( wm8996 - > jack , SND_JACK_BTN_0 ,
SND_JACK_BTN_0 ) ;
} else if ( wm8996 - > detecting ) {
dev_dbg ( codec - > dev , " Headphone detected \n " ) ;
wm8996_hpdet_start ( codec ) ;
/* Increase the detection rate a bit for
* responsiveness .
@ -2445,8 +2531,6 @@ static void wm8996_micd(struct snd_soc_codec *codec)
snd_soc_update_bits ( codec , WM8996_MIC_DETECT_1 ,
WM8996_MICD_RATE_MASK ,
7 < < WM8996_MICD_RATE_SHIFT ) ;
wm8996 - > detecting = false ;
}
}
}
@ -2486,6 +2570,9 @@ static irqreturn_t wm8996_irq(int irq, void *data)
if ( irq_val & WM8996_MICD_EINT )
wm8996_micd ( codec ) ;
if ( irq_val & WM8996_HP_DONE_EINT )
wm8996_hpdet_irq ( codec ) ;
return IRQ_HANDLED ;
}