The switching between the earphone and the Horn channel of wm9714 is controlled by the register software, which is a little different from the method of inserting the earphone in the TV to let the amplifier pull down and turn off the external sound directly. You can set the value of 0x1c in wm9714, where 0x00a0 and 0x1200 in the headset.
In the circuit, the eint11 is fixed externally to a high level. The eint11 is lowered by inserting a headset to trigger the interruption, and then the wm9714 register control is implemented. First, add the initialization channel settings and registration interruption in wm9713_soc_probe () in wm9713.c.
# Define hdphone_eintpin irq_eint (11)
# Define hdphone_gpiopin initi64xx_gpn (11)
# Define output_value_hp (0x00a0)
# Define output_value_spk (0x1200)
Static int wm9713_soc_probe (struct platform_device * pdev)
{
......
Initi_gpio_cfgpin (hdphone_gpiopin, initi_gpio_sfn (2); // configure gpio11 as an external interrupt
Initi_gpio_setpull (hdphone_gpiopin, initi_gpio_pull_none); // The hardware is not pulled down by default.
Set_irq_type (hdphone_eintpin, irq_type_edge_both); // The insertion and unplugging of the headset will trigger interruption.
If (readl (89c64xx_gpndat) & (1 <11) // if the power-on is powered on, set the channel; otherwise, set the headset
{
Ac97_write (codec, ac97_rec_gain, output_value_spk );
}
Else
{
Ac97_write (codec, ac97_rec_gain, output_value_hp );
}
Ret = request_irq (hdphone_eintpin, initi6400_9713hdsp_irq, // register the interrupt and interrupt processing functions for eint11. The parameters include the interrupt mode,
Irqf_disabled, "hdphonspeak", null); // interrupt name
If (Ret <0) // if the registration fails, execute GOTO
{
Printk (kern_err "request_irq (89c6400_9713hdsp_irq) failed !!! /N ");
Goto irq_err;
}
.........
Irq_err:
Free_irq (hdphone_eintpin, null); // release interruption
.........
}
The handler is interrupted as follows:
Static irqreturn_t initi6400_9713hdsp_irq (int irq, void * dev_id)
{
Struct snd_soc_codec * codec = wm9713_dai-> codec; // obtain the codec of the system
Writel (readl (initi64xx_eint0mask) | (1 <11), initi64xx_eint0mask); // disable eint0 interrupt before deal it
Writel (1 <11, 89c64xx_eint0pend); // disable interrupt
If (readl (s3c2464xx_gpndat) & (1 <11) // if it is a speaker, otherwise it is a headset
{
Ac97_write (codec, ac97_rec_gain, output_value_spk );
}
Else
{
Ac97_write (codec, ac97_rec_gain, output_value_hp );
}
Writel (readl (89c64xx_eint0mask )&(~ (1 <11), 89c64xx_eint0mask); // enable interrupt after deal it
Return irq_handled;
}
The above is OK. In practice, we still find a problem. The plug-in and plug-in earphones have been normal, but the speaker does not sound when it is started for the first time and only played with the speaker, that is to say, it always takes the headset to trigger the Speaker and the headset
Sound? Through the test waveform, we found that there was a headset Input Waveform and the switching was normal. However, there was no waveform in the Power Amplifier input, and it was estimated that the channel was still switched. The reason was that when the sound was played, entered
When you determine sndrv_pcm_stream_playback, The 0x1c register is written as 0xaa,
Overwrite the 0x1200 value required by the speaker, and block this sentence. You can set the print statement in the initiation6400_ac97_trigger:
For (temp = 0x00; temp <= 0x7e; temp + = 0x02)
Initi6400_ac97_read (0, temp );
Read all the register values of 9714 when cmd = 1 starts playing the audio and make a judgment.
========================== Win CE practices ================================== ==================================
Initializing:
IRQ = irq_eint11; // interrupt gpio
DWORD m_dwsysintrhpsense = NULL; // headset switching flag
Handle m_hhpsenseinterrupt = NULL; // the headset switches the interrupt handle.
Handle m_hhpsenseinterruptthread; // headset switch interrupt thread handle
If (! Kerneliocontrol (ioctl_hal_request_sysintr, & IRQ,
Sizeof (DWORD), & m_dwsysintrhpsense, sizeof (DWORD ),
Null) // gpio for interrupt control registration
{
Wav_err (_ T ("[WAV: Err] initinterruptthread (): HP sense ioctl_hal_request_sysintr failed/n/R ")));
M_dwsysintrhpsense = sysintr_undefined;
Return false;
}
M_hhpsenseinterrupt = createevent (null, false, false, null); // initialize the interrupt handle
If (m_hhpsenseinterrupt = NULL)
{
Wav_err (_ T ("[WAV: Err] initinterruptthread (): HP sense createevent () failed/n/R ")));
Return (false );
}
If (! Interruptinitialize (m_dwsysintrhpsense, m_hhpsenseinterrupt, null, 0) // bind the interrupt handle and flag
{
Wav_err (_ T ("[WAV: Err] initinterruptthread (): HP sense interruptinitialize () failed/n/R ")));
Return false;
}
M_hhpsenseinterruptthread = createthread (lpsecurity_attributes) null, 0,
(Lpthread_start_routine) callinterruptthreadhpsense, this, 0, null); // create an interrupt thread
If (m_hhpsenseinterruptthread = NULL) // if no thread is created successfully, return.
{
Wav_err (_ T ("[WAV: Err] initinterruptthread (): HP sense createthread () failed/n/R ")));
Return false;
}
Void callinterruptthreadhpsense (hardwarecontext * phwcontext)
{
Phwcontext-> interruptthreadhpsense (); // call the interrupt processing function through the hardware context
}
Interrupt handling function:
Void hardwarecontext: interruptthreadhpsense ()
{
......
If (! (G_pgpioreg-> gpndat & (1 <11) // If you insert a headset
{
Writecodecregister (wm9713_output_mux, output_value_hp );
Retailmsg (ac97_hp_debug, (_ T ("[WAV:] headphone output/n/R ")));
}
While (true)
{
Waitforsingleobject (m_hhpsenseinterrupt, infinite); // The thread waits for interruption
G_pgpioreg-> eint0mask | = (0x1 <11); // mask eint9, clear interrupt pending
G_pgpioreg-> eint0pend = (0x1 <11); // clear pending eint9
If (g_pgpioreg-> gpndat & (1 <11 ))
{
Writecodecregister (wm9713_output_mux, output_value_spk );
Retailmsg (ac97_hp_debug, (_ T ("[WAV:] Speak output/n/R ")));
}
Else
{
Writecodecregister (wm9713_output_mux, output_value_hp );
Retailmsg (ac97_hp_debug, (_ T ("[WAV:] headphone output/n/R ")));
}
Interruptdone (m_dwsysintrhpsense );
G_pgpioreg-> eint0mask & = ~ (0x1 <11); // unmask eint9, enable interrupt
}
......
}
For this approach, we also need to make a NOTE: For waitforsingleobject in a thread loop, if the event is an event actively set, we need
The setevent function is used to enable events. However, when an interrupt event is bound to an interrupt event, the event becomes a signal when the interrupt occurs passively, so the setevent function is not required.