2015-09-29 18:44:01 +03:00
/*
* da7219 - aad . c - Dialog DA7219 ALSA SoC AAD Driver
*
* Copyright ( c ) 2015 Dialog Semiconductor Ltd .
*
* Author : Adam Thomson < Adam . Thomson . Opensource @ diasemi . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/module.h>
# include <linux/platform_device.h>
2016-07-29 16:46:54 +03:00
# include <linux/clk.h>
2016-06-21 20:50:21 +03:00
# include <linux/i2c.h>
# include <linux/property.h>
2015-09-29 18:44:01 +03:00
# include <linux/pm_wakeirq.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/workqueue.h>
# include <sound/soc.h>
# include <sound/jack.h>
# include <sound/da7219.h>
# include "da7219.h"
# include "da7219-aad.h"
/*
* Detection control
*/
2018-01-29 07:36:54 +03:00
void da7219_aad_jack_det ( struct snd_soc_component * component , struct snd_soc_jack * jack )
2015-09-29 18:44:01 +03:00
{
2018-01-29 07:36:54 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
da7219 - > aad - > jack = jack ;
da7219 - > aad - > jack_inserted = false ;
/* Send an initial empty report */
snd_soc_jack_report ( jack , 0 , DA7219_AAD_REPORT_ALL_MASK ) ;
/* Enable/Disable jack detection */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 ,
2015-09-29 18:44:01 +03:00
DA7219_ACCDET_EN_MASK ,
( jack ? DA7219_ACCDET_EN_MASK : 0 ) ) ;
}
EXPORT_SYMBOL_GPL ( da7219_aad_jack_det ) ;
/*
* Button / HPTest work
*/
static void da7219_aad_btn_det_work ( struct work_struct * work )
{
struct da7219_aad_priv * da7219_aad =
container_of ( work , struct da7219_aad_priv , btn_det_work ) ;
2018-01-29 07:36:54 +03:00
struct snd_soc_component * component = da7219_aad - > component ;
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
2018-08-09 12:48:50 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
u8 statusa , micbias_ctrl ;
bool micbias_up = false ;
int retries = 0 ;
/* Drive headphones/lineout */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_L_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_HP_L_AMP_OE_MASK ,
DA7219_HP_L_AMP_OE_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_R_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_HP_R_AMP_OE_MASK ,
DA7219_HP_R_AMP_OE_MASK ) ;
/* Make sure mic bias is up */
snd_soc_dapm_force_enable_pin ( dapm , " Mic Bias " ) ;
snd_soc_dapm_sync ( dapm ) ;
do {
2018-01-29 07:36:54 +03:00
statusa = snd_soc_component_read32 ( component , DA7219_ACCDET_STATUS_A ) ;
2015-09-29 18:44:01 +03:00
if ( statusa & DA7219_MICBIAS_UP_STS_MASK )
micbias_up = true ;
else if ( retries + + < DA7219_AAD_MICBIAS_CHK_RETRIES )
msleep ( DA7219_AAD_MICBIAS_CHK_DELAY ) ;
} while ( ( ! micbias_up ) & & ( retries < DA7219_AAD_MICBIAS_CHK_RETRIES ) ) ;
if ( retries > = DA7219_AAD_MICBIAS_CHK_RETRIES )
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Mic bias status check timed out " ) ;
2015-09-29 18:44:01 +03:00
2018-08-09 12:48:50 +03:00
da7219 - > micbias_on_event = true ;
2015-09-29 18:44:01 +03:00
/*
* Mic bias pulse required to enable mic , must be done before enabling
* button detection to prevent erroneous button readings .
*/
if ( da7219_aad - > micbias_pulse_lvl & & da7219_aad - > micbias_pulse_time ) {
/* Pulse higher level voltage */
2018-01-29 07:36:54 +03:00
micbias_ctrl = snd_soc_component_read32 ( component , DA7219_MICBIAS_CTRL ) ;
snd_soc_component_update_bits ( component , DA7219_MICBIAS_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_MICBIAS1_LEVEL_MASK ,
da7219_aad - > micbias_pulse_lvl ) ;
msleep ( da7219_aad - > micbias_pulse_time ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_MICBIAS_CTRL , micbias_ctrl ) ;
2015-09-29 18:44:01 +03:00
}
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 ,
2015-09-29 18:44:01 +03:00
DA7219_BUTTON_CONFIG_MASK ,
da7219_aad - > btn_cfg ) ;
}
static void da7219_aad_hptest_work ( struct work_struct * work )
{
struct da7219_aad_priv * da7219_aad =
container_of ( work , struct da7219_aad_priv , hptest_work ) ;
2018-01-29 07:36:54 +03:00
struct snd_soc_component * component = da7219_aad - > component ;
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
2019-01-05 05:02:46 +03:00
__le16 tonegen_freq_hptest ;
2017-06-19 12:56:33 +03:00
u8 pll_srm_sts , pll_ctrl , gain_ramp_ctrl , accdet_cfg8 ;
2016-07-29 16:46:54 +03:00
int report = 0 , ret = 0 ;
2015-09-29 18:44:01 +03:00
2017-06-19 12:56:33 +03:00
/* Lock DAPM, Kcontrols affected by this test and the PLL */
2015-09-29 18:44:01 +03:00
snd_soc_dapm_mutex_lock ( dapm ) ;
2017-06-19 12:56:33 +03:00
mutex_lock ( & da7219 - > ctrl_lock ) ;
mutex_lock ( & da7219 - > pll_lock ) ;
2015-09-29 18:44:01 +03:00
2016-07-29 16:46:54 +03:00
/* Ensure MCLK is available for HP test procedure */
if ( da7219 - > mclk ) {
ret = clk_prepare_enable ( da7219 - > mclk ) ;
if ( ret ) {
2018-01-29 07:36:54 +03:00
dev_err ( component - > dev , " Failed to enable mclk - %d \n " , ret ) ;
2017-06-19 12:56:33 +03:00
mutex_unlock ( & da7219 - > pll_lock ) ;
mutex_unlock ( & da7219 - > ctrl_lock ) ;
2016-07-29 16:46:54 +03:00
snd_soc_dapm_mutex_unlock ( dapm ) ;
return ;
}
}
2016-09-12 18:46:50 +03:00
/*
* If MCLK not present , then we ' re using the internal oscillator and
* require different frequency settings to achieve the same result .
2017-06-19 12:56:33 +03:00
*
* If MCLK is present , but PLL is not enabled then we enable it here to
* ensure a consistent detection procedure .
2016-09-12 18:46:50 +03:00
*/
2018-01-29 07:36:54 +03:00
pll_srm_sts = snd_soc_component_read32 ( component , DA7219_PLL_SRM_STS ) ;
2017-06-19 12:56:33 +03:00
if ( pll_srm_sts & DA7219_PLL_SRM_STS_MCLK ) {
2016-09-12 18:46:50 +03:00
tonegen_freq_hptest = cpu_to_le16 ( DA7219_AAD_HPTEST_RAMP_FREQ ) ;
2017-06-19 12:56:33 +03:00
2018-01-29 07:36:54 +03:00
pll_ctrl = snd_soc_component_read32 ( component , DA7219_PLL_CTRL ) ;
2017-06-19 12:56:33 +03:00
if ( ( pll_ctrl & DA7219_PLL_MODE_MASK ) = = DA7219_PLL_MODE_BYPASS )
2018-01-29 07:36:54 +03:00
da7219_set_pll ( component , DA7219_SYSCLK_PLL ,
2017-06-19 12:56:33 +03:00
DA7219_PLL_FREQ_OUT_98304 ) ;
} else {
2016-09-12 18:46:50 +03:00
tonegen_freq_hptest = cpu_to_le16 ( DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC ) ;
2017-06-19 12:56:33 +03:00
}
2016-09-12 18:46:50 +03:00
/* Ensure gain ramping at fastest rate */
2018-01-29 07:36:54 +03:00
gain_ramp_ctrl = snd_soc_component_read32 ( component , DA7219_GAIN_RAMP_CTRL ) ;
snd_soc_component_write ( component , DA7219_GAIN_RAMP_CTRL , DA7219_GAIN_RAMP_RATE_X8 ) ;
2016-09-12 18:46:50 +03:00
2015-09-29 18:44:01 +03:00
/* Bypass cache so it saves current settings */
regcache_cache_bypass ( da7219 - > regmap , true ) ;
/* Make sure Tone Generator is disabled */
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_TONE_GEN_CFG1 , 0 ) ;
2015-09-29 18:44:01 +03:00
/* Enable HPTest block, 1KOhms check */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_8 ,
2015-09-29 18:44:01 +03:00
DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK ,
DA7219_HPTEST_EN_MASK |
DA7219_HPTEST_RES_SEL_1KOHMS ) ;
/* Set gains to 0db */
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_DAC_L_GAIN , DA7219_DAC_DIGITAL_GAIN_0DB ) ;
snd_soc_component_write ( component , DA7219_DAC_R_GAIN , DA7219_DAC_DIGITAL_GAIN_0DB ) ;
snd_soc_component_write ( component , DA7219_HP_L_GAIN , DA7219_HP_AMP_GAIN_0DB ) ;
snd_soc_component_write ( component , DA7219_HP_R_GAIN , DA7219_HP_AMP_GAIN_0DB ) ;
2015-09-29 18:44:01 +03:00
/* Disable DAC filters, EQs and soft mute */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DAC_FILTERS1 , DA7219_HPF_MODE_MASK ,
2015-09-29 18:44:01 +03:00
0 ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DAC_FILTERS4 , DA7219_DAC_EQ_EN_MASK ,
2015-09-29 18:44:01 +03:00
0 ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DAC_FILTERS5 ,
2015-09-29 18:44:01 +03:00
DA7219_DAC_SOFTMUTE_EN_MASK , 0 ) ;
/* Enable HP left & right paths */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_CP_CTRL , DA7219_CP_EN_MASK ,
2015-09-29 18:44:01 +03:00
DA7219_CP_EN_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DIG_ROUTING_DAC ,
2015-09-29 18:44:01 +03:00
DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK ,
DA7219_DAC_L_SRC_TONEGEN |
DA7219_DAC_R_SRC_TONEGEN ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DAC_L_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK ,
DA7219_DAC_L_EN_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DAC_R_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK ,
DA7219_DAC_R_EN_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_MIXOUT_L_SELECT ,
2015-09-29 18:44:01 +03:00
DA7219_MIXOUT_L_MIX_SELECT_MASK ,
DA7219_MIXOUT_L_MIX_SELECT_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_MIXOUT_R_SELECT ,
2015-09-29 18:44:01 +03:00
DA7219_MIXOUT_R_MIX_SELECT_MASK ,
DA7219_MIXOUT_R_MIX_SELECT_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DROUTING_ST_OUTFILT_1L ,
2015-09-29 18:44:01 +03:00
DA7219_OUTFILT_ST_1L_SRC_MASK ,
DA7219_DMIX_ST_SRC_OUTFILT1L ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_DROUTING_ST_OUTFILT_1R ,
2015-09-29 18:44:01 +03:00
DA7219_OUTFILT_ST_1R_SRC_MASK ,
DA7219_DMIX_ST_SRC_OUTFILT1R ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_MIXOUT_L_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_MIXOUT_L_AMP_EN_MASK ,
DA7219_MIXOUT_L_AMP_EN_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_MIXOUT_R_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_MIXOUT_R_AMP_EN_MASK ,
DA7219_MIXOUT_R_AMP_EN_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_L_CTRL ,
2016-10-03 13:21:01 +03:00
DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK ,
DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_R_CTRL ,
2016-10-03 13:21:01 +03:00
DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK ,
DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK ) ;
msleep ( DA7219_SETTLING_DELAY ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_L_CTRL ,
2016-10-03 13:21:01 +03:00
DA7219_HP_L_AMP_MUTE_EN_MASK |
DA7219_HP_L_AMP_MIN_GAIN_EN_MASK , 0 ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_R_CTRL ,
2016-10-03 13:21:01 +03:00
DA7219_HP_R_AMP_MUTE_EN_MASK |
DA7219_HP_R_AMP_MIN_GAIN_EN_MASK , 0 ) ;
2015-09-29 18:44:01 +03:00
2016-09-12 18:46:50 +03:00
/*
* If we ' re running from the internal oscillator then give audio paths
* time to settle before running test .
*/
if ( ! ( pll_srm_sts & DA7219_PLL_SRM_STS_MCLK ) )
msleep ( DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY ) ;
2015-09-29 18:44:01 +03:00
/* Configure & start Tone Generator */
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_TONE_GEN_ON_PER , DA7219_BEEP_ON_PER_MASK ) ;
2015-09-29 18:44:01 +03:00
regmap_raw_write ( da7219 - > regmap , DA7219_TONE_GEN_FREQ1_L ,
& tonegen_freq_hptest , sizeof ( tonegen_freq_hptest ) ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_TONE_GEN_CFG2 ,
2015-09-29 18:44:01 +03:00
DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK ,
DA7219_SWG_SEL_SRAMP |
DA7219_TONE_GEN_GAIN_MINUS_15DB ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_TONE_GEN_CFG1 , DA7219_START_STOPN_MASK ) ;
2015-09-29 18:44:01 +03:00
msleep ( DA7219_AAD_HPTEST_PERIOD ) ;
/* Grab comparator reading */
2018-01-29 07:36:54 +03:00
accdet_cfg8 = snd_soc_component_read32 ( component , DA7219_ACCDET_CONFIG_8 ) ;
2015-09-29 18:44:01 +03:00
if ( accdet_cfg8 & DA7219_HPTEST_COMP_MASK )
report | = SND_JACK_HEADPHONE ;
else
report | = SND_JACK_LINEOUT ;
/* Stop tone generator */
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_TONE_GEN_CFG1 , 0 ) ;
2015-09-29 18:44:01 +03:00
msleep ( DA7219_AAD_HPTEST_PERIOD ) ;
/* Restore original settings from cache */
regcache_mark_dirty ( da7219 - > regmap ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_HP_L_CTRL ,
DA7219_HP_R_CTRL ) ;
2016-10-03 13:21:01 +03:00
msleep ( DA7219_SETTLING_DELAY ) ;
2015-09-29 18:44:01 +03:00
regcache_sync_region ( da7219 - > regmap , DA7219_MIXOUT_L_CTRL ,
DA7219_MIXOUT_R_CTRL ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_DROUTING_ST_OUTFILT_1L ,
DA7219_DROUTING_ST_OUTFILT_1R ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_MIXOUT_L_SELECT ,
DA7219_MIXOUT_R_SELECT ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_DAC_L_CTRL ,
DA7219_DAC_R_CTRL ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_DIG_ROUTING_DAC ,
DA7219_DIG_ROUTING_DAC ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_CP_CTRL , DA7219_CP_CTRL ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_DAC_FILTERS5 ,
DA7219_DAC_FILTERS5 ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_DAC_FILTERS4 ,
DA7219_DAC_FILTERS1 ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_HP_L_GAIN ,
DA7219_HP_R_GAIN ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_DAC_L_GAIN ,
DA7219_DAC_R_GAIN ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_TONE_GEN_ON_PER ,
DA7219_TONE_GEN_ON_PER ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_TONE_GEN_FREQ1_L ,
DA7219_TONE_GEN_FREQ1_U ) ;
regcache_sync_region ( da7219 - > regmap , DA7219_TONE_GEN_CFG1 ,
DA7219_TONE_GEN_CFG2 ) ;
regcache_cache_bypass ( da7219 - > regmap , false ) ;
/* Disable HPTest block */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_8 ,
2015-09-29 18:44:01 +03:00
DA7219_HPTEST_EN_MASK , 0 ) ;
2016-09-12 18:46:50 +03:00
/*
* If we ' re running from the internal oscillator then give audio paths
* time to settle before allowing headphones to be driven as required .
*/
if ( ! ( pll_srm_sts & DA7219_PLL_SRM_STS_MCLK ) )
msleep ( DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY ) ;
/* Restore gain ramping rate */
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_GAIN_RAMP_CTRL , gain_ramp_ctrl ) ;
2016-09-12 18:46:50 +03:00
2015-09-29 18:44:01 +03:00
/* Drive Headphones/lineout */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_L_CTRL , DA7219_HP_L_AMP_OE_MASK ,
2015-09-29 18:44:01 +03:00
DA7219_HP_L_AMP_OE_MASK ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_R_CTRL , DA7219_HP_R_AMP_OE_MASK ,
2015-09-29 18:44:01 +03:00
DA7219_HP_R_AMP_OE_MASK ) ;
2017-06-19 12:56:33 +03:00
/* Restore PLL to previous configuration, if re-configured */
if ( ( pll_srm_sts & DA7219_PLL_SRM_STS_MCLK ) & &
( ( pll_ctrl & DA7219_PLL_MODE_MASK ) = = DA7219_PLL_MODE_BYPASS ) )
2018-01-29 07:36:54 +03:00
da7219_set_pll ( component , DA7219_SYSCLK_MCLK , 0 ) ;
2017-06-19 12:56:33 +03:00
2016-07-29 16:46:54 +03:00
/* Remove MCLK, if previously enabled */
if ( da7219 - > mclk )
clk_disable_unprepare ( da7219 - > mclk ) ;
2017-06-19 12:56:33 +03:00
mutex_unlock ( & da7219 - > pll_lock ) ;
mutex_unlock ( & da7219 - > ctrl_lock ) ;
2015-09-29 18:44:01 +03:00
snd_soc_dapm_mutex_unlock ( dapm ) ;
/*
* Only send report if jack hasn ' t been removed during process ,
* otherwise it ' s invalid and we drop it .
*/
if ( da7219_aad - > jack_inserted )
snd_soc_jack_report ( da7219_aad - > jack , report ,
SND_JACK_HEADSET | SND_JACK_LINEOUT ) ;
}
/*
* IRQ
*/
static irqreturn_t da7219_aad_irq_thread ( int irq , void * data )
{
struct da7219_aad_priv * da7219_aad = data ;
2018-01-29 07:36:54 +03:00
struct snd_soc_component * component = da7219_aad - > component ;
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
u8 events [ DA7219_AAD_IRQ_REG_MAX ] ;
u8 statusa ;
int i , report = 0 , mask = 0 ;
/* Read current IRQ events */
regmap_bulk_read ( da7219 - > regmap , DA7219_ACCDET_IRQ_EVENT_A ,
events , DA7219_AAD_IRQ_REG_MAX ) ;
if ( ! events [ DA7219_AAD_IRQ_REG_A ] & & ! events [ DA7219_AAD_IRQ_REG_B ] )
return IRQ_NONE ;
/* Read status register for jack insertion & type status */
2018-01-29 07:36:54 +03:00
statusa = snd_soc_component_read32 ( component , DA7219_ACCDET_STATUS_A ) ;
2015-09-29 18:44:01 +03:00
/* Clear events */
regmap_bulk_write ( da7219 - > regmap , DA7219_ACCDET_IRQ_EVENT_A ,
events , DA7219_AAD_IRQ_REG_MAX ) ;
2018-01-29 07:36:54 +03:00
dev_dbg ( component - > dev , " IRQ events = 0x%x|0x%x, status = 0x%x \n " ,
2015-09-29 18:44:01 +03:00
events [ DA7219_AAD_IRQ_REG_A ] , events [ DA7219_AAD_IRQ_REG_B ] ,
statusa ) ;
if ( statusa & DA7219_JACK_INSERTION_STS_MASK ) {
/* Jack Insertion */
if ( events [ DA7219_AAD_IRQ_REG_A ] &
DA7219_E_JACK_INSERTED_MASK ) {
report | = SND_JACK_MECHANICAL ;
mask | = SND_JACK_MECHANICAL ;
da7219_aad - > jack_inserted = true ;
}
/* Jack type detection */
if ( events [ DA7219_AAD_IRQ_REG_A ] &
DA7219_E_JACK_DETECT_COMPLETE_MASK ) {
/*
* If 4 - pole , then enable button detection , else perform
* HP impedance test to determine output type to report .
*
* We schedule work here as the tasks themselves can
* take time to complete , and in particular for hptest
* we want to be able to check if the jack was removed
* during the procedure as this will invalidate the
* result . By doing this as work , the IRQ thread can
* handle a removal , and we can check at the end of
* hptest if we have a valid result or not .
*/
if ( statusa & DA7219_JACK_TYPE_STS_MASK ) {
report | = SND_JACK_HEADSET ;
mask | = SND_JACK_HEADSET | SND_JACK_LINEOUT ;
schedule_work ( & da7219_aad - > btn_det_work ) ;
} else {
schedule_work ( & da7219_aad - > hptest_work ) ;
}
}
/* Button support for 4-pole jack */
if ( statusa & DA7219_JACK_TYPE_STS_MASK ) {
for ( i = 0 ; i < DA7219_AAD_MAX_BUTTONS ; + + i ) {
/* Button Press */
if ( events [ DA7219_AAD_IRQ_REG_B ] &
( DA7219_E_BUTTON_A_PRESSED_MASK < < i ) ) {
report | = SND_JACK_BTN_0 > > i ;
mask | = SND_JACK_BTN_0 > > i ;
}
}
snd_soc_jack_report ( da7219_aad - > jack , report , mask ) ;
for ( i = 0 ; i < DA7219_AAD_MAX_BUTTONS ; + + i ) {
/* Button Release */
if ( events [ DA7219_AAD_IRQ_REG_B ] &
( DA7219_E_BUTTON_A_RELEASED_MASK > > i ) ) {
report & = ~ ( SND_JACK_BTN_0 > > i ) ;
mask | = SND_JACK_BTN_0 > > i ;
}
}
}
} else {
/* Jack removal */
if ( events [ DA7219_AAD_IRQ_REG_A ] & DA7219_E_JACK_REMOVED_MASK ) {
report = 0 ;
mask | = DA7219_AAD_REPORT_ALL_MASK ;
da7219_aad - > jack_inserted = false ;
/* Un-drive headphones/lineout */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_R_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_HP_R_AMP_OE_MASK , 0 ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_HP_L_CTRL ,
2015-09-29 18:44:01 +03:00
DA7219_HP_L_AMP_OE_MASK , 0 ) ;
/* Ensure button detection disabled */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 ,
2015-09-29 18:44:01 +03:00
DA7219_BUTTON_CONFIG_MASK , 0 ) ;
2018-08-09 12:48:50 +03:00
da7219 - > micbias_on_event = false ;
2015-09-29 18:44:01 +03:00
/* Disable mic bias */
snd_soc_dapm_disable_pin ( dapm , " Mic Bias " ) ;
snd_soc_dapm_sync ( dapm ) ;
/* Cancel any pending work */
cancel_work_sync ( & da7219_aad - > btn_det_work ) ;
cancel_work_sync ( & da7219_aad - > hptest_work ) ;
}
}
snd_soc_jack_report ( da7219_aad - > jack , report , mask ) ;
return IRQ_HANDLED ;
}
/*
2016-06-21 20:50:21 +03:00
* DT / ACPI to pdata conversion
2015-09-29 18:44:01 +03:00
*/
static enum da7219_aad_micbias_pulse_lvl
2018-01-29 07:36:54 +03:00
da7219_aad_fw_micbias_pulse_lvl ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 2800 :
return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V ;
case 2900 :
return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid micbias pulse level " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_MICBIAS_PULSE_LVL_OFF ;
}
}
static enum da7219_aad_btn_cfg
2018-01-29 07:36:54 +03:00
da7219_aad_fw_btn_cfg ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 2 :
return DA7219_AAD_BTN_CFG_2MS ;
case 5 :
return DA7219_AAD_BTN_CFG_5MS ;
case 10 :
return DA7219_AAD_BTN_CFG_10MS ;
case 50 :
return DA7219_AAD_BTN_CFG_50MS ;
case 100 :
return DA7219_AAD_BTN_CFG_100MS ;
case 200 :
return DA7219_AAD_BTN_CFG_200MS ;
case 500 :
return DA7219_AAD_BTN_CFG_500MS ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid button config " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_BTN_CFG_10MS ;
}
}
static enum da7219_aad_mic_det_thr
2018-01-29 07:36:54 +03:00
da7219_aad_fw_mic_det_thr ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 200 :
return DA7219_AAD_MIC_DET_THR_200_OHMS ;
case 500 :
return DA7219_AAD_MIC_DET_THR_500_OHMS ;
case 750 :
return DA7219_AAD_MIC_DET_THR_750_OHMS ;
case 1000 :
return DA7219_AAD_MIC_DET_THR_1000_OHMS ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid mic detect threshold " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_MIC_DET_THR_500_OHMS ;
}
}
static enum da7219_aad_jack_ins_deb
2018-01-29 07:36:54 +03:00
da7219_aad_fw_jack_ins_deb ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 5 :
return DA7219_AAD_JACK_INS_DEB_5MS ;
case 10 :
return DA7219_AAD_JACK_INS_DEB_10MS ;
case 20 :
return DA7219_AAD_JACK_INS_DEB_20MS ;
case 50 :
return DA7219_AAD_JACK_INS_DEB_50MS ;
case 100 :
return DA7219_AAD_JACK_INS_DEB_100MS ;
case 200 :
return DA7219_AAD_JACK_INS_DEB_200MS ;
case 500 :
return DA7219_AAD_JACK_INS_DEB_500MS ;
case 1000 :
return DA7219_AAD_JACK_INS_DEB_1S ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid jack insert debounce " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_JACK_INS_DEB_20MS ;
}
}
static enum da7219_aad_jack_det_rate
2018-01-29 07:36:54 +03:00
da7219_aad_fw_jack_det_rate ( struct snd_soc_component * component , const char * str )
2015-09-29 18:44:01 +03:00
{
if ( ! strcmp ( str , " 32ms_64ms " ) ) {
return DA7219_AAD_JACK_DET_RATE_32_64MS ;
} else if ( ! strcmp ( str , " 64ms_128ms " ) ) {
return DA7219_AAD_JACK_DET_RATE_64_128MS ;
} else if ( ! strcmp ( str , " 128ms_256ms " ) ) {
return DA7219_AAD_JACK_DET_RATE_128_256MS ;
} else if ( ! strcmp ( str , " 256ms_512ms " ) ) {
return DA7219_AAD_JACK_DET_RATE_256_512MS ;
} else {
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid jack detect rate " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_JACK_DET_RATE_256_512MS ;
}
}
static enum da7219_aad_jack_rem_deb
2018-01-29 07:36:54 +03:00
da7219_aad_fw_jack_rem_deb ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 1 :
return DA7219_AAD_JACK_REM_DEB_1MS ;
case 5 :
return DA7219_AAD_JACK_REM_DEB_5MS ;
case 10 :
return DA7219_AAD_JACK_REM_DEB_10MS ;
case 20 :
return DA7219_AAD_JACK_REM_DEB_20MS ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid jack removal debounce " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_JACK_REM_DEB_1MS ;
}
}
static enum da7219_aad_btn_avg
2018-01-29 07:36:54 +03:00
da7219_aad_fw_btn_avg ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 1 :
return DA7219_AAD_BTN_AVG_1 ;
case 2 :
return DA7219_AAD_BTN_AVG_2 ;
case 4 :
return DA7219_AAD_BTN_AVG_4 ;
case 8 :
return DA7219_AAD_BTN_AVG_8 ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid button average value " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_BTN_AVG_2 ;
}
}
static enum da7219_aad_adc_1bit_rpt
2018-01-29 07:36:54 +03:00
da7219_aad_fw_adc_1bit_rpt ( struct snd_soc_component * component , u32 val )
2015-09-29 18:44:01 +03:00
{
switch ( val ) {
case 1 :
return DA7219_AAD_ADC_1BIT_RPT_1 ;
case 2 :
return DA7219_AAD_ADC_1BIT_RPT_2 ;
case 4 :
return DA7219_AAD_ADC_1BIT_RPT_4 ;
case 8 :
return DA7219_AAD_ADC_1BIT_RPT_8 ;
default :
2018-01-29 07:36:54 +03:00
dev_warn ( component - > dev , " Invalid ADC 1-bit repeat value " ) ;
2015-09-29 18:44:01 +03:00
return DA7219_AAD_ADC_1BIT_RPT_1 ;
}
}
2018-01-29 07:36:54 +03:00
static struct da7219_aad_pdata * da7219_aad_fw_to_pdata ( struct snd_soc_component * component )
2015-09-29 18:44:01 +03:00
{
2018-01-29 07:36:54 +03:00
struct device * dev = component - > dev ;
2016-06-21 20:50:21 +03:00
struct i2c_client * i2c = to_i2c_client ( dev ) ;
struct fwnode_handle * aad_np ;
2015-09-29 18:44:01 +03:00
struct da7219_aad_pdata * aad_pdata ;
2016-06-21 20:50:21 +03:00
const char * fw_str ;
u32 fw_val32 ;
2015-09-29 18:44:01 +03:00
2016-06-21 20:50:21 +03:00
aad_np = device_get_named_child_node ( dev , " da7219_aad " ) ;
2015-09-29 18:44:01 +03:00
if ( ! aad_np )
return NULL ;
2018-01-29 07:36:54 +03:00
aad_pdata = devm_kzalloc ( dev , sizeof ( * aad_pdata ) , GFP_KERNEL ) ;
2015-09-29 18:44:01 +03:00
if ( ! aad_pdata )
2016-06-21 20:50:21 +03:00
return NULL ;
2015-09-29 18:44:01 +03:00
2016-06-21 20:50:21 +03:00
aad_pdata - > irq = i2c - > irq ;
2015-09-29 18:44:01 +03:00
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,micbias-pulse-lvl " ,
& fw_val32 ) > = 0 )
2015-09-29 18:44:01 +03:00
aad_pdata - > micbias_pulse_lvl =
2018-01-29 07:36:54 +03:00
da7219_aad_fw_micbias_pulse_lvl ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,micbias-pulse-time " ,
& fw_val32 ) > = 0 )
aad_pdata - > micbias_pulse_time = fw_val32 ;
2015-09-29 18:44:01 +03:00
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,btn-cfg " , & fw_val32 ) > = 0 )
2018-01-29 07:36:54 +03:00
aad_pdata - > btn_cfg = da7219_aad_fw_btn_cfg ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > btn_cfg = DA7219_AAD_BTN_CFG_10MS ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,mic-det-thr " , & fw_val32 ) > = 0 )
2015-09-29 18:44:01 +03:00
aad_pdata - > mic_det_thr =
2018-01-29 07:36:54 +03:00
da7219_aad_fw_mic_det_thr ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,jack-ins-deb " , & fw_val32 ) > = 0 )
2015-09-29 18:44:01 +03:00
aad_pdata - > jack_ins_deb =
2018-01-29 07:36:54 +03:00
da7219_aad_fw_jack_ins_deb ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS ;
2016-06-21 20:50:21 +03:00
if ( ! fwnode_property_read_string ( aad_np , " dlg,jack-det-rate " , & fw_str ) )
2015-09-29 18:44:01 +03:00
aad_pdata - > jack_det_rate =
2018-01-29 07:36:54 +03:00
da7219_aad_fw_jack_det_rate ( component , fw_str ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,jack-rem-deb " , & fw_val32 ) > = 0 )
2015-09-29 18:44:01 +03:00
aad_pdata - > jack_rem_deb =
2018-01-29 07:36:54 +03:00
da7219_aad_fw_jack_rem_deb ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,a-d-btn-thr " , & fw_val32 ) > = 0 )
aad_pdata - > a_d_btn_thr = ( u8 ) fw_val32 ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > a_d_btn_thr = 0xA ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,d-b-btn-thr " , & fw_val32 ) > = 0 )
aad_pdata - > d_b_btn_thr = ( u8 ) fw_val32 ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > d_b_btn_thr = 0x16 ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,b-c-btn-thr " , & fw_val32 ) > = 0 )
aad_pdata - > b_c_btn_thr = ( u8 ) fw_val32 ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > b_c_btn_thr = 0x21 ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,c-mic-btn-thr " , & fw_val32 ) > = 0 )
aad_pdata - > c_mic_btn_thr = ( u8 ) fw_val32 ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > c_mic_btn_thr = 0x3E ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,btn-avg " , & fw_val32 ) > = 0 )
2018-01-29 07:36:54 +03:00
aad_pdata - > btn_avg = da7219_aad_fw_btn_avg ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > btn_avg = DA7219_AAD_BTN_AVG_2 ;
2016-06-21 20:50:21 +03:00
if ( fwnode_property_read_u32 ( aad_np , " dlg,adc-1bit-rpt " , & fw_val32 ) > = 0 )
2015-09-29 18:44:01 +03:00
aad_pdata - > adc_1bit_rpt =
2018-01-29 07:36:54 +03:00
da7219_aad_fw_adc_1bit_rpt ( component , fw_val32 ) ;
2015-09-29 18:44:01 +03:00
else
aad_pdata - > adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1 ;
return aad_pdata ;
}
2018-01-29 07:36:54 +03:00
static void da7219_aad_handle_pdata ( struct snd_soc_component * component )
2015-09-29 18:44:01 +03:00
{
2018-01-29 07:36:54 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
struct da7219_aad_priv * da7219_aad = da7219 - > aad ;
struct da7219_pdata * pdata = da7219 - > pdata ;
if ( ( pdata ) & & ( pdata - > aad_pdata ) ) {
struct da7219_aad_pdata * aad_pdata = pdata - > aad_pdata ;
u8 cfg , mask ;
da7219_aad - > irq = aad_pdata - > irq ;
switch ( aad_pdata - > micbias_pulse_lvl ) {
case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V :
case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V :
da7219_aad - > micbias_pulse_lvl =
( aad_pdata - > micbias_pulse_lvl < <
DA7219_MICBIAS1_LEVEL_SHIFT ) ;
break ;
default :
break ;
}
da7219_aad - > micbias_pulse_time = aad_pdata - > micbias_pulse_time ;
switch ( aad_pdata - > btn_cfg ) {
case DA7219_AAD_BTN_CFG_2MS :
case DA7219_AAD_BTN_CFG_5MS :
case DA7219_AAD_BTN_CFG_10MS :
case DA7219_AAD_BTN_CFG_50MS :
case DA7219_AAD_BTN_CFG_100MS :
case DA7219_AAD_BTN_CFG_200MS :
case DA7219_AAD_BTN_CFG_500MS :
da7219_aad - > btn_cfg = ( aad_pdata - > btn_cfg < <
DA7219_BUTTON_CONFIG_SHIFT ) ;
}
cfg = 0 ;
mask = 0 ;
switch ( aad_pdata - > mic_det_thr ) {
case DA7219_AAD_MIC_DET_THR_200_OHMS :
case DA7219_AAD_MIC_DET_THR_500_OHMS :
case DA7219_AAD_MIC_DET_THR_750_OHMS :
case DA7219_AAD_MIC_DET_THR_1000_OHMS :
cfg | = ( aad_pdata - > mic_det_thr < <
DA7219_MIC_DET_THRESH_SHIFT ) ;
mask | = DA7219_MIC_DET_THRESH_MASK ;
}
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 , mask , cfg ) ;
2015-09-29 18:44:01 +03:00
cfg = 0 ;
mask = 0 ;
switch ( aad_pdata - > jack_ins_deb ) {
case DA7219_AAD_JACK_INS_DEB_5MS :
case DA7219_AAD_JACK_INS_DEB_10MS :
case DA7219_AAD_JACK_INS_DEB_20MS :
case DA7219_AAD_JACK_INS_DEB_50MS :
case DA7219_AAD_JACK_INS_DEB_100MS :
case DA7219_AAD_JACK_INS_DEB_200MS :
case DA7219_AAD_JACK_INS_DEB_500MS :
case DA7219_AAD_JACK_INS_DEB_1S :
cfg | = ( aad_pdata - > jack_ins_deb < <
DA7219_JACKDET_DEBOUNCE_SHIFT ) ;
mask | = DA7219_JACKDET_DEBOUNCE_MASK ;
}
switch ( aad_pdata - > jack_det_rate ) {
case DA7219_AAD_JACK_DET_RATE_32_64MS :
case DA7219_AAD_JACK_DET_RATE_64_128MS :
case DA7219_AAD_JACK_DET_RATE_128_256MS :
case DA7219_AAD_JACK_DET_RATE_256_512MS :
cfg | = ( aad_pdata - > jack_det_rate < <
DA7219_JACK_DETECT_RATE_SHIFT ) ;
mask | = DA7219_JACK_DETECT_RATE_MASK ;
}
switch ( aad_pdata - > jack_rem_deb ) {
case DA7219_AAD_JACK_REM_DEB_1MS :
case DA7219_AAD_JACK_REM_DEB_5MS :
case DA7219_AAD_JACK_REM_DEB_10MS :
case DA7219_AAD_JACK_REM_DEB_20MS :
cfg | = ( aad_pdata - > jack_rem_deb < <
DA7219_JACKDET_REM_DEB_SHIFT ) ;
mask | = DA7219_JACKDET_REM_DEB_MASK ;
}
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_2 , mask , cfg ) ;
2015-09-29 18:44:01 +03:00
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_ACCDET_CONFIG_3 ,
2015-09-29 18:44:01 +03:00
aad_pdata - > a_d_btn_thr ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_ACCDET_CONFIG_4 ,
2015-09-29 18:44:01 +03:00
aad_pdata - > d_b_btn_thr ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_ACCDET_CONFIG_5 ,
2015-09-29 18:44:01 +03:00
aad_pdata - > b_c_btn_thr ) ;
2018-01-29 07:36:54 +03:00
snd_soc_component_write ( component , DA7219_ACCDET_CONFIG_6 ,
2015-09-29 18:44:01 +03:00
aad_pdata - > c_mic_btn_thr ) ;
cfg = 0 ;
mask = 0 ;
switch ( aad_pdata - > btn_avg ) {
case DA7219_AAD_BTN_AVG_1 :
case DA7219_AAD_BTN_AVG_2 :
case DA7219_AAD_BTN_AVG_4 :
case DA7219_AAD_BTN_AVG_8 :
cfg | = ( aad_pdata - > btn_avg < <
DA7219_BUTTON_AVERAGE_SHIFT ) ;
mask | = DA7219_BUTTON_AVERAGE_MASK ;
}
switch ( aad_pdata - > adc_1bit_rpt ) {
case DA7219_AAD_ADC_1BIT_RPT_1 :
case DA7219_AAD_ADC_1BIT_RPT_2 :
case DA7219_AAD_ADC_1BIT_RPT_4 :
case DA7219_AAD_ADC_1BIT_RPT_8 :
cfg | = ( aad_pdata - > adc_1bit_rpt < <
DA7219_ADC_1_BIT_REPEAT_SHIFT ) ;
mask | = DA7219_ADC_1_BIT_REPEAT_MASK ;
}
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_7 , mask , cfg ) ;
2015-09-29 18:44:01 +03:00
}
}
2016-09-26 16:29:21 +03:00
/*
* Suspend / Resume
*/
2018-01-29 07:36:54 +03:00
void da7219_aad_suspend ( struct snd_soc_component * component )
2016-09-26 16:29:21 +03:00
{
2018-01-29 07:36:54 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2016-09-26 16:29:21 +03:00
struct da7219_aad_priv * da7219_aad = da7219 - > aad ;
2018-01-29 07:36:54 +03:00
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
2016-09-26 16:29:21 +03:00
u8 micbias_ctrl ;
if ( da7219_aad - > jack ) {
/* Disable jack detection during suspend */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 ,
2016-09-26 16:29:21 +03:00
DA7219_ACCDET_EN_MASK , 0 ) ;
/*
* If we have a 4 - pole jack inserted , then micbias will be
* enabled . We can disable micbias here , and keep a note to
* re - enable it on resume . If jack removal occurred during
* suspend then this will be dealt with through the IRQ handler .
*/
if ( da7219_aad - > jack_inserted ) {
2018-01-29 07:36:54 +03:00
micbias_ctrl = snd_soc_component_read32 ( component , DA7219_MICBIAS_CTRL ) ;
2016-09-26 16:29:21 +03:00
if ( micbias_ctrl & DA7219_MICBIAS1_EN_MASK ) {
snd_soc_dapm_disable_pin ( dapm , " Mic Bias " ) ;
snd_soc_dapm_sync ( dapm ) ;
da7219_aad - > micbias_resume_enable = true ;
}
}
}
}
2018-01-29 07:36:54 +03:00
void da7219_aad_resume ( struct snd_soc_component * component )
2016-09-26 16:29:21 +03:00
{
2018-01-29 07:36:54 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2016-09-26 16:29:21 +03:00
struct da7219_aad_priv * da7219_aad = da7219 - > aad ;
2018-01-29 07:36:54 +03:00
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
2016-09-26 16:29:21 +03:00
if ( da7219_aad - > jack ) {
/* Re-enable micbias if previously enabled for 4-pole jack */
if ( da7219_aad - > jack_inserted & &
da7219_aad - > micbias_resume_enable ) {
snd_soc_dapm_force_enable_pin ( dapm , " Mic Bias " ) ;
snd_soc_dapm_sync ( dapm ) ;
da7219_aad - > micbias_resume_enable = false ;
}
/* Re-enable jack detection */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 ,
2016-09-26 16:29:21 +03:00
DA7219_ACCDET_EN_MASK ,
DA7219_ACCDET_EN_MASK ) ;
}
}
2015-09-29 18:44:01 +03:00
/*
* Init / Exit
*/
2018-01-29 07:36:54 +03:00
int da7219_aad_init ( struct snd_soc_component * component )
2015-09-29 18:44:01 +03:00
{
2018-01-29 07:36:54 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
struct da7219_aad_priv * da7219_aad ;
u8 mask [ DA7219_AAD_IRQ_REG_MAX ] ;
int ret ;
2018-01-29 07:36:54 +03:00
da7219_aad = devm_kzalloc ( component - > dev , sizeof ( * da7219_aad ) , GFP_KERNEL ) ;
2015-09-29 18:44:01 +03:00
if ( ! da7219_aad )
return - ENOMEM ;
da7219 - > aad = da7219_aad ;
2018-01-29 07:36:54 +03:00
da7219_aad - > component = component ;
2015-09-29 18:44:01 +03:00
2016-06-21 20:50:21 +03:00
/* Handle any DT/ACPI/platform data */
if ( da7219 - > pdata & & ! da7219 - > pdata - > aad_pdata )
2018-01-29 07:36:54 +03:00
da7219 - > pdata - > aad_pdata = da7219_aad_fw_to_pdata ( component ) ;
2015-09-29 18:44:01 +03:00
2018-01-29 07:36:54 +03:00
da7219_aad_handle_pdata ( component ) ;
2015-09-29 18:44:01 +03:00
/* Disable button detection */
2018-01-29 07:36:54 +03:00
snd_soc_component_update_bits ( component , DA7219_ACCDET_CONFIG_1 ,
2015-09-29 18:44:01 +03:00
DA7219_BUTTON_CONFIG_MASK , 0 ) ;
INIT_WORK ( & da7219_aad - > btn_det_work , da7219_aad_btn_det_work ) ;
INIT_WORK ( & da7219_aad - > hptest_work , da7219_aad_hptest_work ) ;
ret = request_threaded_irq ( da7219_aad - > irq , NULL ,
da7219_aad_irq_thread ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" da7219-aad " , da7219_aad ) ;
if ( ret ) {
2018-01-29 07:36:54 +03:00
dev_err ( component - > dev , " Failed to request IRQ: %d \n " , ret ) ;
2015-09-29 18:44:01 +03:00
return ret ;
}
/* Unmask AAD IRQs */
memset ( mask , 0 , DA7219_AAD_IRQ_REG_MAX ) ;
regmap_bulk_write ( da7219 - > regmap , DA7219_ACCDET_IRQ_MASK_A ,
& mask , DA7219_AAD_IRQ_REG_MAX ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( da7219_aad_init ) ;
2018-01-29 07:36:54 +03:00
void da7219_aad_exit ( struct snd_soc_component * component )
2015-09-29 18:44:01 +03:00
{
2018-01-29 07:36:54 +03:00
struct da7219_priv * da7219 = snd_soc_component_get_drvdata ( component ) ;
2015-09-29 18:44:01 +03:00
struct da7219_aad_priv * da7219_aad = da7219 - > aad ;
u8 mask [ DA7219_AAD_IRQ_REG_MAX ] ;
/* Mask off AAD IRQs */
memset ( mask , DA7219_BYTE_MASK , DA7219_AAD_IRQ_REG_MAX ) ;
regmap_bulk_write ( da7219 - > regmap , DA7219_ACCDET_IRQ_MASK_A ,
mask , DA7219_AAD_IRQ_REG_MAX ) ;
free_irq ( da7219_aad - > irq , da7219_aad ) ;
cancel_work_sync ( & da7219_aad - > btn_det_work ) ;
cancel_work_sync ( & da7219_aad - > hptest_work ) ;
}
EXPORT_SYMBOL_GPL ( da7219_aad_exit ) ;
MODULE_DESCRIPTION ( " ASoC DA7219 AAD Driver " ) ;
MODULE_AUTHOR ( " Adam Thomson <Adam.Thomson.Opensource@diasemi.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;