18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Dialog Semiconductor Ltd. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/property.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 198c2ecf20Sopenharmony_ci#include <sound/soc.h> 208c2ecf20Sopenharmony_ci#include <sound/jack.h> 218c2ecf20Sopenharmony_ci#include <sound/da7219.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "da7219.h" 248c2ecf20Sopenharmony_ci#include "da7219-aad.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * Detection control 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_civoid da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci da7219->aad->jack = jack; 368c2ecf20Sopenharmony_ci da7219->aad->jack_inserted = false; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* Send an initial empty report */ 398c2ecf20Sopenharmony_ci snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Enable/Disable jack detection */ 428c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, 438c2ecf20Sopenharmony_ci DA7219_ACCDET_EN_MASK, 448c2ecf20Sopenharmony_ci (jack ? DA7219_ACCDET_EN_MASK : 0)); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da7219_aad_jack_det); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * Button/HPTest work 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void da7219_aad_btn_det_work(struct work_struct *work) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = 558c2ecf20Sopenharmony_ci container_of(work, struct da7219_aad_priv, btn_det_work); 568c2ecf20Sopenharmony_ci struct snd_soc_component *component = da7219_aad->component; 578c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 588c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 598c2ecf20Sopenharmony_ci u8 statusa, micbias_ctrl; 608c2ecf20Sopenharmony_ci bool micbias_up = false; 618c2ecf20Sopenharmony_ci int retries = 0; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Drive headphones/lineout */ 648c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, 658c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_OE_MASK, 668c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_OE_MASK); 678c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, 688c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_OE_MASK, 698c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_OE_MASK); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* Make sure mic bias is up */ 728c2ecf20Sopenharmony_ci snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); 738c2ecf20Sopenharmony_ci snd_soc_dapm_sync(dapm); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci do { 768c2ecf20Sopenharmony_ci statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A); 778c2ecf20Sopenharmony_ci if (statusa & DA7219_MICBIAS_UP_STS_MASK) 788c2ecf20Sopenharmony_ci micbias_up = true; 798c2ecf20Sopenharmony_ci else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES) 808c2ecf20Sopenharmony_ci msleep(DA7219_AAD_MICBIAS_CHK_DELAY); 818c2ecf20Sopenharmony_ci } while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES)); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES) 848c2ecf20Sopenharmony_ci dev_warn(component->dev, "Mic bias status check timed out"); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci da7219->micbias_on_event = true; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * Mic bias pulse required to enable mic, must be done before enabling 908c2ecf20Sopenharmony_ci * button detection to prevent erroneous button readings. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) { 938c2ecf20Sopenharmony_ci /* Pulse higher level voltage */ 948c2ecf20Sopenharmony_ci micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL); 958c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_MICBIAS_CTRL, 968c2ecf20Sopenharmony_ci DA7219_MICBIAS1_LEVEL_MASK, 978c2ecf20Sopenharmony_ci da7219_aad->micbias_pulse_lvl); 988c2ecf20Sopenharmony_ci msleep(da7219_aad->micbias_pulse_time); 998c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_ctrl); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, 1048c2ecf20Sopenharmony_ci DA7219_BUTTON_CONFIG_MASK, 1058c2ecf20Sopenharmony_ci da7219_aad->btn_cfg); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void da7219_aad_hptest_work(struct work_struct *work) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = 1118c2ecf20Sopenharmony_ci container_of(work, struct da7219_aad_priv, hptest_work); 1128c2ecf20Sopenharmony_ci struct snd_soc_component *component = da7219_aad->component; 1138c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 1148c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci __le16 tonegen_freq_hptest; 1178c2ecf20Sopenharmony_ci u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; 1188c2ecf20Sopenharmony_ci int report = 0, ret = 0; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Lock DAPM, Kcontrols affected by this test and the PLL */ 1218c2ecf20Sopenharmony_ci snd_soc_dapm_mutex_lock(dapm); 1228c2ecf20Sopenharmony_ci mutex_lock(&da7219->ctrl_lock); 1238c2ecf20Sopenharmony_ci mutex_lock(&da7219->pll_lock); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Ensure MCLK is available for HP test procedure */ 1268c2ecf20Sopenharmony_ci if (da7219->mclk) { 1278c2ecf20Sopenharmony_ci ret = clk_prepare_enable(da7219->mclk); 1288c2ecf20Sopenharmony_ci if (ret) { 1298c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to enable mclk - %d\n", ret); 1308c2ecf20Sopenharmony_ci mutex_unlock(&da7219->pll_lock); 1318c2ecf20Sopenharmony_ci mutex_unlock(&da7219->ctrl_lock); 1328c2ecf20Sopenharmony_ci snd_soc_dapm_mutex_unlock(dapm); 1338c2ecf20Sopenharmony_ci return; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * If MCLK not present, then we're using the internal oscillator and 1398c2ecf20Sopenharmony_ci * require different frequency settings to achieve the same result. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * If MCLK is present, but PLL is not enabled then we enable it here to 1428c2ecf20Sopenharmony_ci * ensure a consistent detection procedure. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci pll_srm_sts = snd_soc_component_read(component, DA7219_PLL_SRM_STS); 1458c2ecf20Sopenharmony_ci if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) { 1468c2ecf20Sopenharmony_ci tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci pll_ctrl = snd_soc_component_read(component, DA7219_PLL_CTRL); 1498c2ecf20Sopenharmony_ci if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS) 1508c2ecf20Sopenharmony_ci da7219_set_pll(component, DA7219_SYSCLK_PLL, 1518c2ecf20Sopenharmony_ci DA7219_PLL_FREQ_OUT_98304); 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_ci tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Ensure gain ramping at fastest rate */ 1578c2ecf20Sopenharmony_ci gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL); 1588c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Bypass cache so it saves current settings */ 1618c2ecf20Sopenharmony_ci regcache_cache_bypass(da7219->regmap, true); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Make sure Tone Generator is disabled */ 1648c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Enable HPTest block, 1KOhms check */ 1678c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8, 1688c2ecf20Sopenharmony_ci DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK, 1698c2ecf20Sopenharmony_ci DA7219_HPTEST_EN_MASK | 1708c2ecf20Sopenharmony_ci DA7219_HPTEST_RES_SEL_1KOHMS); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Set gains to 0db */ 1738c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB); 1748c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB); 1758c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB); 1768c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Disable DAC filters, EQs and soft mute */ 1798c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK, 1808c2ecf20Sopenharmony_ci 0); 1818c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK, 1828c2ecf20Sopenharmony_ci 0); 1838c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DAC_FILTERS5, 1848c2ecf20Sopenharmony_ci DA7219_DAC_SOFTMUTE_EN_MASK, 0); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Enable HP left & right paths */ 1878c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_CP_CTRL, DA7219_CP_EN_MASK, 1888c2ecf20Sopenharmony_ci DA7219_CP_EN_MASK); 1898c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DIG_ROUTING_DAC, 1908c2ecf20Sopenharmony_ci DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK, 1918c2ecf20Sopenharmony_ci DA7219_DAC_L_SRC_TONEGEN | 1928c2ecf20Sopenharmony_ci DA7219_DAC_R_SRC_TONEGEN); 1938c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL, 1948c2ecf20Sopenharmony_ci DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK, 1958c2ecf20Sopenharmony_ci DA7219_DAC_L_EN_MASK); 1968c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL, 1978c2ecf20Sopenharmony_ci DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK, 1988c2ecf20Sopenharmony_ci DA7219_DAC_R_EN_MASK); 1998c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_MIXOUT_L_SELECT, 2008c2ecf20Sopenharmony_ci DA7219_MIXOUT_L_MIX_SELECT_MASK, 2018c2ecf20Sopenharmony_ci DA7219_MIXOUT_L_MIX_SELECT_MASK); 2028c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_MIXOUT_R_SELECT, 2038c2ecf20Sopenharmony_ci DA7219_MIXOUT_R_MIX_SELECT_MASK, 2048c2ecf20Sopenharmony_ci DA7219_MIXOUT_R_MIX_SELECT_MASK); 2058c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1L, 2068c2ecf20Sopenharmony_ci DA7219_OUTFILT_ST_1L_SRC_MASK, 2078c2ecf20Sopenharmony_ci DA7219_DMIX_ST_SRC_OUTFILT1L); 2088c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1R, 2098c2ecf20Sopenharmony_ci DA7219_OUTFILT_ST_1R_SRC_MASK, 2108c2ecf20Sopenharmony_ci DA7219_DMIX_ST_SRC_OUTFILT1R); 2118c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_MIXOUT_L_CTRL, 2128c2ecf20Sopenharmony_ci DA7219_MIXOUT_L_AMP_EN_MASK, 2138c2ecf20Sopenharmony_ci DA7219_MIXOUT_L_AMP_EN_MASK); 2148c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_MIXOUT_R_CTRL, 2158c2ecf20Sopenharmony_ci DA7219_MIXOUT_R_AMP_EN_MASK, 2168c2ecf20Sopenharmony_ci DA7219_MIXOUT_R_AMP_EN_MASK); 2178c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, 2188c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK, 2198c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); 2208c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, 2218c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK, 2228c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); 2238c2ecf20Sopenharmony_ci msleep(DA7219_SETTLING_DELAY); 2248c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, 2258c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_MUTE_EN_MASK | 2268c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0); 2278c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, 2288c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_MUTE_EN_MASK | 2298c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * If we're running from the internal oscillator then give audio paths 2338c2ecf20Sopenharmony_ci * time to settle before running test. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)) 2368c2ecf20Sopenharmony_ci msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Configure & start Tone Generator */ 2398c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK); 2408c2ecf20Sopenharmony_ci regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L, 2418c2ecf20Sopenharmony_ci &tonegen_freq_hptest, sizeof(tonegen_freq_hptest)); 2428c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_TONE_GEN_CFG2, 2438c2ecf20Sopenharmony_ci DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK, 2448c2ecf20Sopenharmony_ci DA7219_SWG_SEL_SRAMP | 2458c2ecf20Sopenharmony_ci DA7219_TONE_GEN_GAIN_MINUS_15DB); 2468c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci msleep(DA7219_AAD_HPTEST_PERIOD); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Grab comparator reading */ 2518c2ecf20Sopenharmony_ci accdet_cfg8 = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_8); 2528c2ecf20Sopenharmony_ci if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK) 2538c2ecf20Sopenharmony_ci report |= SND_JACK_HEADPHONE; 2548c2ecf20Sopenharmony_ci else 2558c2ecf20Sopenharmony_ci report |= SND_JACK_LINEOUT; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Stop tone generator */ 2588c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci msleep(DA7219_AAD_HPTEST_PERIOD); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Restore original settings from cache */ 2638c2ecf20Sopenharmony_ci regcache_mark_dirty(da7219->regmap); 2648c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL, 2658c2ecf20Sopenharmony_ci DA7219_HP_R_CTRL); 2668c2ecf20Sopenharmony_ci msleep(DA7219_SETTLING_DELAY); 2678c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL, 2688c2ecf20Sopenharmony_ci DA7219_MIXOUT_R_CTRL); 2698c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L, 2708c2ecf20Sopenharmony_ci DA7219_DROUTING_ST_OUTFILT_1R); 2718c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT, 2728c2ecf20Sopenharmony_ci DA7219_MIXOUT_R_SELECT); 2738c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL, 2748c2ecf20Sopenharmony_ci DA7219_DAC_R_CTRL); 2758c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC, 2768c2ecf20Sopenharmony_ci DA7219_DIG_ROUTING_DAC); 2778c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL); 2788c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5, 2798c2ecf20Sopenharmony_ci DA7219_DAC_FILTERS5); 2808c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4, 2818c2ecf20Sopenharmony_ci DA7219_DAC_FILTERS1); 2828c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN, 2838c2ecf20Sopenharmony_ci DA7219_HP_R_GAIN); 2848c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN, 2858c2ecf20Sopenharmony_ci DA7219_DAC_R_GAIN); 2868c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER, 2878c2ecf20Sopenharmony_ci DA7219_TONE_GEN_ON_PER); 2888c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L, 2898c2ecf20Sopenharmony_ci DA7219_TONE_GEN_FREQ1_U); 2908c2ecf20Sopenharmony_ci regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1, 2918c2ecf20Sopenharmony_ci DA7219_TONE_GEN_CFG2); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci regcache_cache_bypass(da7219->regmap, false); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Disable HPTest block */ 2968c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8, 2978c2ecf20Sopenharmony_ci DA7219_HPTEST_EN_MASK, 0); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * If we're running from the internal oscillator then give audio paths 3018c2ecf20Sopenharmony_ci * time to settle before allowing headphones to be driven as required. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)) 3048c2ecf20Sopenharmony_ci msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Restore gain ramping rate */ 3078c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Drive Headphones/lineout */ 3108c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK, 3118c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_OE_MASK); 3128c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, 3138c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_OE_MASK); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Restore PLL to previous configuration, if re-configured */ 3168c2ecf20Sopenharmony_ci if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) && 3178c2ecf20Sopenharmony_ci ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)) 3188c2ecf20Sopenharmony_ci da7219_set_pll(component, DA7219_SYSCLK_MCLK, 0); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Remove MCLK, if previously enabled */ 3218c2ecf20Sopenharmony_ci if (da7219->mclk) 3228c2ecf20Sopenharmony_ci clk_disable_unprepare(da7219->mclk); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci mutex_unlock(&da7219->pll_lock); 3258c2ecf20Sopenharmony_ci mutex_unlock(&da7219->ctrl_lock); 3268c2ecf20Sopenharmony_ci snd_soc_dapm_mutex_unlock(dapm); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * Only send report if jack hasn't been removed during process, 3308c2ecf20Sopenharmony_ci * otherwise it's invalid and we drop it. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci if (da7219_aad->jack_inserted) 3338c2ecf20Sopenharmony_ci snd_soc_jack_report(da7219_aad->jack, report, 3348c2ecf20Sopenharmony_ci SND_JACK_HEADSET | SND_JACK_LINEOUT); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci/* 3398c2ecf20Sopenharmony_ci * IRQ 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic irqreturn_t da7219_aad_irq_thread(int irq, void *data) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = data; 3458c2ecf20Sopenharmony_ci struct snd_soc_component *component = da7219_aad->component; 3468c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 3478c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 3488c2ecf20Sopenharmony_ci u8 events[DA7219_AAD_IRQ_REG_MAX]; 3498c2ecf20Sopenharmony_ci u8 statusa; 3508c2ecf20Sopenharmony_ci int i, ret, report = 0, mask = 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* Read current IRQ events */ 3538c2ecf20Sopenharmony_ci ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, 3548c2ecf20Sopenharmony_ci events, DA7219_AAD_IRQ_REG_MAX); 3558c2ecf20Sopenharmony_ci if (ret) { 3568c2ecf20Sopenharmony_ci dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret); 3578c2ecf20Sopenharmony_ci return IRQ_NONE; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B]) 3618c2ecf20Sopenharmony_ci return IRQ_NONE; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Read status register for jack insertion & type status */ 3648c2ecf20Sopenharmony_ci statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Clear events */ 3678c2ecf20Sopenharmony_ci regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, 3688c2ecf20Sopenharmony_ci events, DA7219_AAD_IRQ_REG_MAX); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci dev_dbg(component->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n", 3718c2ecf20Sopenharmony_ci events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B], 3728c2ecf20Sopenharmony_ci statusa); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (statusa & DA7219_JACK_INSERTION_STS_MASK) { 3758c2ecf20Sopenharmony_ci /* Jack Insertion */ 3768c2ecf20Sopenharmony_ci if (events[DA7219_AAD_IRQ_REG_A] & 3778c2ecf20Sopenharmony_ci DA7219_E_JACK_INSERTED_MASK) { 3788c2ecf20Sopenharmony_ci report |= SND_JACK_MECHANICAL; 3798c2ecf20Sopenharmony_ci mask |= SND_JACK_MECHANICAL; 3808c2ecf20Sopenharmony_ci da7219_aad->jack_inserted = true; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Jack type detection */ 3848c2ecf20Sopenharmony_ci if (events[DA7219_AAD_IRQ_REG_A] & 3858c2ecf20Sopenharmony_ci DA7219_E_JACK_DETECT_COMPLETE_MASK) { 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * If 4-pole, then enable button detection, else perform 3888c2ecf20Sopenharmony_ci * HP impedance test to determine output type to report. 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * We schedule work here as the tasks themselves can 3918c2ecf20Sopenharmony_ci * take time to complete, and in particular for hptest 3928c2ecf20Sopenharmony_ci * we want to be able to check if the jack was removed 3938c2ecf20Sopenharmony_ci * during the procedure as this will invalidate the 3948c2ecf20Sopenharmony_ci * result. By doing this as work, the IRQ thread can 3958c2ecf20Sopenharmony_ci * handle a removal, and we can check at the end of 3968c2ecf20Sopenharmony_ci * hptest if we have a valid result or not. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci if (statusa & DA7219_JACK_TYPE_STS_MASK) { 3998c2ecf20Sopenharmony_ci report |= SND_JACK_HEADSET; 4008c2ecf20Sopenharmony_ci mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT; 4018c2ecf20Sopenharmony_ci schedule_work(&da7219_aad->btn_det_work); 4028c2ecf20Sopenharmony_ci } else { 4038c2ecf20Sopenharmony_ci schedule_work(&da7219_aad->hptest_work); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Button support for 4-pole jack */ 4088c2ecf20Sopenharmony_ci if (statusa & DA7219_JACK_TYPE_STS_MASK) { 4098c2ecf20Sopenharmony_ci for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) { 4108c2ecf20Sopenharmony_ci /* Button Press */ 4118c2ecf20Sopenharmony_ci if (events[DA7219_AAD_IRQ_REG_B] & 4128c2ecf20Sopenharmony_ci (DA7219_E_BUTTON_A_PRESSED_MASK << i)) { 4138c2ecf20Sopenharmony_ci report |= SND_JACK_BTN_0 >> i; 4148c2ecf20Sopenharmony_ci mask |= SND_JACK_BTN_0 >> i; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci snd_soc_jack_report(da7219_aad->jack, report, mask); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) { 4208c2ecf20Sopenharmony_ci /* Button Release */ 4218c2ecf20Sopenharmony_ci if (events[DA7219_AAD_IRQ_REG_B] & 4228c2ecf20Sopenharmony_ci (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) { 4238c2ecf20Sopenharmony_ci report &= ~(SND_JACK_BTN_0 >> i); 4248c2ecf20Sopenharmony_ci mask |= SND_JACK_BTN_0 >> i; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } else { 4298c2ecf20Sopenharmony_ci /* Jack removal */ 4308c2ecf20Sopenharmony_ci if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) { 4318c2ecf20Sopenharmony_ci report = 0; 4328c2ecf20Sopenharmony_ci mask |= DA7219_AAD_REPORT_ALL_MASK; 4338c2ecf20Sopenharmony_ci da7219_aad->jack_inserted = false; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Un-drive headphones/lineout */ 4368c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, 4378c2ecf20Sopenharmony_ci DA7219_HP_R_AMP_OE_MASK, 0); 4388c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, 4398c2ecf20Sopenharmony_ci DA7219_HP_L_AMP_OE_MASK, 0); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Ensure button detection disabled */ 4428c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, 4438c2ecf20Sopenharmony_ci DA7219_BUTTON_CONFIG_MASK, 0); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci da7219->micbias_on_event = false; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Disable mic bias */ 4488c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "Mic Bias"); 4498c2ecf20Sopenharmony_ci snd_soc_dapm_sync(dapm); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Cancel any pending work */ 4528c2ecf20Sopenharmony_ci cancel_work_sync(&da7219_aad->btn_det_work); 4538c2ecf20Sopenharmony_ci cancel_work_sync(&da7219_aad->hptest_work); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci snd_soc_jack_report(da7219_aad->jack, report, mask); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* 4638c2ecf20Sopenharmony_ci * DT/ACPI to pdata conversion 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic enum da7219_aad_micbias_pulse_lvl 4678c2ecf20Sopenharmony_ci da7219_aad_fw_micbias_pulse_lvl(struct device *dev, u32 val) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci switch (val) { 4708c2ecf20Sopenharmony_ci case 2800: 4718c2ecf20Sopenharmony_ci return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V; 4728c2ecf20Sopenharmony_ci case 2900: 4738c2ecf20Sopenharmony_ci return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V; 4748c2ecf20Sopenharmony_ci default: 4758c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid micbias pulse level"); 4768c2ecf20Sopenharmony_ci return DA7219_AAD_MICBIAS_PULSE_LVL_OFF; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic enum da7219_aad_btn_cfg 4818c2ecf20Sopenharmony_ci da7219_aad_fw_btn_cfg(struct device *dev, u32 val) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci switch (val) { 4848c2ecf20Sopenharmony_ci case 2: 4858c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_2MS; 4868c2ecf20Sopenharmony_ci case 5: 4878c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_5MS; 4888c2ecf20Sopenharmony_ci case 10: 4898c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_10MS; 4908c2ecf20Sopenharmony_ci case 50: 4918c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_50MS; 4928c2ecf20Sopenharmony_ci case 100: 4938c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_100MS; 4948c2ecf20Sopenharmony_ci case 200: 4958c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_200MS; 4968c2ecf20Sopenharmony_ci case 500: 4978c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_500MS; 4988c2ecf20Sopenharmony_ci default: 4998c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid button config"); 5008c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_CFG_10MS; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic enum da7219_aad_mic_det_thr 5058c2ecf20Sopenharmony_ci da7219_aad_fw_mic_det_thr(struct device *dev, u32 val) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci switch (val) { 5088c2ecf20Sopenharmony_ci case 200: 5098c2ecf20Sopenharmony_ci return DA7219_AAD_MIC_DET_THR_200_OHMS; 5108c2ecf20Sopenharmony_ci case 500: 5118c2ecf20Sopenharmony_ci return DA7219_AAD_MIC_DET_THR_500_OHMS; 5128c2ecf20Sopenharmony_ci case 750: 5138c2ecf20Sopenharmony_ci return DA7219_AAD_MIC_DET_THR_750_OHMS; 5148c2ecf20Sopenharmony_ci case 1000: 5158c2ecf20Sopenharmony_ci return DA7219_AAD_MIC_DET_THR_1000_OHMS; 5168c2ecf20Sopenharmony_ci default: 5178c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid mic detect threshold"); 5188c2ecf20Sopenharmony_ci return DA7219_AAD_MIC_DET_THR_500_OHMS; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic enum da7219_aad_jack_ins_deb 5238c2ecf20Sopenharmony_ci da7219_aad_fw_jack_ins_deb(struct device *dev, u32 val) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci switch (val) { 5268c2ecf20Sopenharmony_ci case 5: 5278c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_5MS; 5288c2ecf20Sopenharmony_ci case 10: 5298c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_10MS; 5308c2ecf20Sopenharmony_ci case 20: 5318c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_20MS; 5328c2ecf20Sopenharmony_ci case 50: 5338c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_50MS; 5348c2ecf20Sopenharmony_ci case 100: 5358c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_100MS; 5368c2ecf20Sopenharmony_ci case 200: 5378c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_200MS; 5388c2ecf20Sopenharmony_ci case 500: 5398c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_500MS; 5408c2ecf20Sopenharmony_ci case 1000: 5418c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_1S; 5428c2ecf20Sopenharmony_ci default: 5438c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid jack insert debounce"); 5448c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_INS_DEB_20MS; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic enum da7219_aad_jack_det_rate 5498c2ecf20Sopenharmony_ci da7219_aad_fw_jack_det_rate(struct device *dev, const char *str) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci if (!strcmp(str, "32ms_64ms")) { 5528c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_DET_RATE_32_64MS; 5538c2ecf20Sopenharmony_ci } else if (!strcmp(str, "64ms_128ms")) { 5548c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_DET_RATE_64_128MS; 5558c2ecf20Sopenharmony_ci } else if (!strcmp(str, "128ms_256ms")) { 5568c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_DET_RATE_128_256MS; 5578c2ecf20Sopenharmony_ci } else if (!strcmp(str, "256ms_512ms")) { 5588c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_DET_RATE_256_512MS; 5598c2ecf20Sopenharmony_ci } else { 5608c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid jack detect rate"); 5618c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_DET_RATE_256_512MS; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic enum da7219_aad_jack_rem_deb 5668c2ecf20Sopenharmony_ci da7219_aad_fw_jack_rem_deb(struct device *dev, u32 val) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci switch (val) { 5698c2ecf20Sopenharmony_ci case 1: 5708c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_REM_DEB_1MS; 5718c2ecf20Sopenharmony_ci case 5: 5728c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_REM_DEB_5MS; 5738c2ecf20Sopenharmony_ci case 10: 5748c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_REM_DEB_10MS; 5758c2ecf20Sopenharmony_ci case 20: 5768c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_REM_DEB_20MS; 5778c2ecf20Sopenharmony_ci default: 5788c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid jack removal debounce"); 5798c2ecf20Sopenharmony_ci return DA7219_AAD_JACK_REM_DEB_1MS; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic enum da7219_aad_btn_avg 5848c2ecf20Sopenharmony_ci da7219_aad_fw_btn_avg(struct device *dev, u32 val) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci switch (val) { 5878c2ecf20Sopenharmony_ci case 1: 5888c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_AVG_1; 5898c2ecf20Sopenharmony_ci case 2: 5908c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_AVG_2; 5918c2ecf20Sopenharmony_ci case 4: 5928c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_AVG_4; 5938c2ecf20Sopenharmony_ci case 8: 5948c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_AVG_8; 5958c2ecf20Sopenharmony_ci default: 5968c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid button average value"); 5978c2ecf20Sopenharmony_ci return DA7219_AAD_BTN_AVG_2; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic enum da7219_aad_adc_1bit_rpt 6028c2ecf20Sopenharmony_ci da7219_aad_fw_adc_1bit_rpt(struct device *dev, u32 val) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci switch (val) { 6058c2ecf20Sopenharmony_ci case 1: 6068c2ecf20Sopenharmony_ci return DA7219_AAD_ADC_1BIT_RPT_1; 6078c2ecf20Sopenharmony_ci case 2: 6088c2ecf20Sopenharmony_ci return DA7219_AAD_ADC_1BIT_RPT_2; 6098c2ecf20Sopenharmony_ci case 4: 6108c2ecf20Sopenharmony_ci return DA7219_AAD_ADC_1BIT_RPT_4; 6118c2ecf20Sopenharmony_ci case 8: 6128c2ecf20Sopenharmony_ci return DA7219_AAD_ADC_1BIT_RPT_8; 6138c2ecf20Sopenharmony_ci default: 6148c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid ADC 1-bit repeat value"); 6158c2ecf20Sopenharmony_ci return DA7219_AAD_ADC_1BIT_RPT_1; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 6228c2ecf20Sopenharmony_ci struct fwnode_handle *aad_np; 6238c2ecf20Sopenharmony_ci struct da7219_aad_pdata *aad_pdata; 6248c2ecf20Sopenharmony_ci const char *fw_str; 6258c2ecf20Sopenharmony_ci u32 fw_val32; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci aad_np = device_get_named_child_node(dev, "da7219_aad"); 6288c2ecf20Sopenharmony_ci if (!aad_np) 6298c2ecf20Sopenharmony_ci return NULL; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL); 6328c2ecf20Sopenharmony_ci if (!aad_pdata) 6338c2ecf20Sopenharmony_ci return NULL; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci aad_pdata->irq = i2c->irq; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl", 6388c2ecf20Sopenharmony_ci &fw_val32) >= 0) 6398c2ecf20Sopenharmony_ci aad_pdata->micbias_pulse_lvl = 6408c2ecf20Sopenharmony_ci da7219_aad_fw_micbias_pulse_lvl(dev, fw_val32); 6418c2ecf20Sopenharmony_ci else 6428c2ecf20Sopenharmony_ci aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time", 6458c2ecf20Sopenharmony_ci &fw_val32) >= 0) 6468c2ecf20Sopenharmony_ci aad_pdata->micbias_pulse_time = fw_val32; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0) 6498c2ecf20Sopenharmony_ci aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(dev, fw_val32); 6508c2ecf20Sopenharmony_ci else 6518c2ecf20Sopenharmony_ci aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0) 6548c2ecf20Sopenharmony_ci aad_pdata->mic_det_thr = 6558c2ecf20Sopenharmony_ci da7219_aad_fw_mic_det_thr(dev, fw_val32); 6568c2ecf20Sopenharmony_ci else 6578c2ecf20Sopenharmony_ci aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_200_OHMS; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0) 6608c2ecf20Sopenharmony_ci aad_pdata->jack_ins_deb = 6618c2ecf20Sopenharmony_ci da7219_aad_fw_jack_ins_deb(dev, fw_val32); 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str)) 6668c2ecf20Sopenharmony_ci aad_pdata->jack_det_rate = 6678c2ecf20Sopenharmony_ci da7219_aad_fw_jack_det_rate(dev, fw_str); 6688c2ecf20Sopenharmony_ci else 6698c2ecf20Sopenharmony_ci aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0) 6728c2ecf20Sopenharmony_ci aad_pdata->jack_rem_deb = 6738c2ecf20Sopenharmony_ci da7219_aad_fw_jack_rem_deb(dev, fw_val32); 6748c2ecf20Sopenharmony_ci else 6758c2ecf20Sopenharmony_ci aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0) 6788c2ecf20Sopenharmony_ci aad_pdata->a_d_btn_thr = (u8) fw_val32; 6798c2ecf20Sopenharmony_ci else 6808c2ecf20Sopenharmony_ci aad_pdata->a_d_btn_thr = 0xA; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0) 6838c2ecf20Sopenharmony_ci aad_pdata->d_b_btn_thr = (u8) fw_val32; 6848c2ecf20Sopenharmony_ci else 6858c2ecf20Sopenharmony_ci aad_pdata->d_b_btn_thr = 0x16; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0) 6888c2ecf20Sopenharmony_ci aad_pdata->b_c_btn_thr = (u8) fw_val32; 6898c2ecf20Sopenharmony_ci else 6908c2ecf20Sopenharmony_ci aad_pdata->b_c_btn_thr = 0x21; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0) 6938c2ecf20Sopenharmony_ci aad_pdata->c_mic_btn_thr = (u8) fw_val32; 6948c2ecf20Sopenharmony_ci else 6958c2ecf20Sopenharmony_ci aad_pdata->c_mic_btn_thr = 0x3E; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0) 6988c2ecf20Sopenharmony_ci aad_pdata->btn_avg = da7219_aad_fw_btn_avg(dev, fw_val32); 6998c2ecf20Sopenharmony_ci else 7008c2ecf20Sopenharmony_ci aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0) 7038c2ecf20Sopenharmony_ci aad_pdata->adc_1bit_rpt = 7048c2ecf20Sopenharmony_ci da7219_aad_fw_adc_1bit_rpt(dev, fw_val32); 7058c2ecf20Sopenharmony_ci else 7068c2ecf20Sopenharmony_ci aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return aad_pdata; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic void da7219_aad_handle_pdata(struct snd_soc_component *component) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 7148c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = da7219->aad; 7158c2ecf20Sopenharmony_ci struct da7219_pdata *pdata = da7219->pdata; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if ((pdata) && (pdata->aad_pdata)) { 7188c2ecf20Sopenharmony_ci struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata; 7198c2ecf20Sopenharmony_ci u8 cfg, mask; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci da7219_aad->irq = aad_pdata->irq; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci switch (aad_pdata->micbias_pulse_lvl) { 7248c2ecf20Sopenharmony_ci case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V: 7258c2ecf20Sopenharmony_ci case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V: 7268c2ecf20Sopenharmony_ci da7219_aad->micbias_pulse_lvl = 7278c2ecf20Sopenharmony_ci (aad_pdata->micbias_pulse_lvl << 7288c2ecf20Sopenharmony_ci DA7219_MICBIAS1_LEVEL_SHIFT); 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci default: 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci switch (aad_pdata->btn_cfg) { 7378c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_2MS: 7388c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_5MS: 7398c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_10MS: 7408c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_50MS: 7418c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_100MS: 7428c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_200MS: 7438c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_CFG_500MS: 7448c2ecf20Sopenharmony_ci da7219_aad->btn_cfg = (aad_pdata->btn_cfg << 7458c2ecf20Sopenharmony_ci DA7219_BUTTON_CONFIG_SHIFT); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci cfg = 0; 7498c2ecf20Sopenharmony_ci mask = 0; 7508c2ecf20Sopenharmony_ci switch (aad_pdata->mic_det_thr) { 7518c2ecf20Sopenharmony_ci case DA7219_AAD_MIC_DET_THR_200_OHMS: 7528c2ecf20Sopenharmony_ci case DA7219_AAD_MIC_DET_THR_500_OHMS: 7538c2ecf20Sopenharmony_ci case DA7219_AAD_MIC_DET_THR_750_OHMS: 7548c2ecf20Sopenharmony_ci case DA7219_AAD_MIC_DET_THR_1000_OHMS: 7558c2ecf20Sopenharmony_ci cfg |= (aad_pdata->mic_det_thr << 7568c2ecf20Sopenharmony_ci DA7219_MIC_DET_THRESH_SHIFT); 7578c2ecf20Sopenharmony_ci mask |= DA7219_MIC_DET_THRESH_MASK; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, mask, cfg); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci cfg = 0; 7628c2ecf20Sopenharmony_ci mask = 0; 7638c2ecf20Sopenharmony_ci switch (aad_pdata->jack_ins_deb) { 7648c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_5MS: 7658c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_10MS: 7668c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_20MS: 7678c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_50MS: 7688c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_100MS: 7698c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_200MS: 7708c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_500MS: 7718c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_INS_DEB_1S: 7728c2ecf20Sopenharmony_ci cfg |= (aad_pdata->jack_ins_deb << 7738c2ecf20Sopenharmony_ci DA7219_JACKDET_DEBOUNCE_SHIFT); 7748c2ecf20Sopenharmony_ci mask |= DA7219_JACKDET_DEBOUNCE_MASK; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci switch (aad_pdata->jack_det_rate) { 7778c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_DET_RATE_32_64MS: 7788c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_DET_RATE_64_128MS: 7798c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_DET_RATE_128_256MS: 7808c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_DET_RATE_256_512MS: 7818c2ecf20Sopenharmony_ci cfg |= (aad_pdata->jack_det_rate << 7828c2ecf20Sopenharmony_ci DA7219_JACK_DETECT_RATE_SHIFT); 7838c2ecf20Sopenharmony_ci mask |= DA7219_JACK_DETECT_RATE_MASK; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci switch (aad_pdata->jack_rem_deb) { 7868c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_REM_DEB_1MS: 7878c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_REM_DEB_5MS: 7888c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_REM_DEB_10MS: 7898c2ecf20Sopenharmony_ci case DA7219_AAD_JACK_REM_DEB_20MS: 7908c2ecf20Sopenharmony_ci cfg |= (aad_pdata->jack_rem_deb << 7918c2ecf20Sopenharmony_ci DA7219_JACKDET_REM_DEB_SHIFT); 7928c2ecf20Sopenharmony_ci mask |= DA7219_JACKDET_REM_DEB_MASK; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_2, mask, cfg); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_ACCDET_CONFIG_3, 7978c2ecf20Sopenharmony_ci aad_pdata->a_d_btn_thr); 7988c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_ACCDET_CONFIG_4, 7998c2ecf20Sopenharmony_ci aad_pdata->d_b_btn_thr); 8008c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_ACCDET_CONFIG_5, 8018c2ecf20Sopenharmony_ci aad_pdata->b_c_btn_thr); 8028c2ecf20Sopenharmony_ci snd_soc_component_write(component, DA7219_ACCDET_CONFIG_6, 8038c2ecf20Sopenharmony_ci aad_pdata->c_mic_btn_thr); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci cfg = 0; 8068c2ecf20Sopenharmony_ci mask = 0; 8078c2ecf20Sopenharmony_ci switch (aad_pdata->btn_avg) { 8088c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_AVG_1: 8098c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_AVG_2: 8108c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_AVG_4: 8118c2ecf20Sopenharmony_ci case DA7219_AAD_BTN_AVG_8: 8128c2ecf20Sopenharmony_ci cfg |= (aad_pdata->btn_avg << 8138c2ecf20Sopenharmony_ci DA7219_BUTTON_AVERAGE_SHIFT); 8148c2ecf20Sopenharmony_ci mask |= DA7219_BUTTON_AVERAGE_MASK; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci switch (aad_pdata->adc_1bit_rpt) { 8178c2ecf20Sopenharmony_ci case DA7219_AAD_ADC_1BIT_RPT_1: 8188c2ecf20Sopenharmony_ci case DA7219_AAD_ADC_1BIT_RPT_2: 8198c2ecf20Sopenharmony_ci case DA7219_AAD_ADC_1BIT_RPT_4: 8208c2ecf20Sopenharmony_ci case DA7219_AAD_ADC_1BIT_RPT_8: 8218c2ecf20Sopenharmony_ci cfg |= (aad_pdata->adc_1bit_rpt << 8228c2ecf20Sopenharmony_ci DA7219_ADC_1_BIT_REPEAT_SHIFT); 8238c2ecf20Sopenharmony_ci mask |= DA7219_ADC_1_BIT_REPEAT_MASK; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg); 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci/* 8318c2ecf20Sopenharmony_ci * Suspend/Resume 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_civoid da7219_aad_suspend(struct snd_soc_component *component) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 8378c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = da7219->aad; 8388c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 8398c2ecf20Sopenharmony_ci u8 micbias_ctrl; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (da7219_aad->jack) { 8428c2ecf20Sopenharmony_ci /* Disable jack detection during suspend */ 8438c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, 8448c2ecf20Sopenharmony_ci DA7219_ACCDET_EN_MASK, 0); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* 8478c2ecf20Sopenharmony_ci * If we have a 4-pole jack inserted, then micbias will be 8488c2ecf20Sopenharmony_ci * enabled. We can disable micbias here, and keep a note to 8498c2ecf20Sopenharmony_ci * re-enable it on resume. If jack removal occurred during 8508c2ecf20Sopenharmony_ci * suspend then this will be dealt with through the IRQ handler. 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_ci if (da7219_aad->jack_inserted) { 8538c2ecf20Sopenharmony_ci micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL); 8548c2ecf20Sopenharmony_ci if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) { 8558c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "Mic Bias"); 8568c2ecf20Sopenharmony_ci snd_soc_dapm_sync(dapm); 8578c2ecf20Sopenharmony_ci da7219_aad->micbias_resume_enable = true; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci synchronize_irq(da7219_aad->irq); 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_civoid da7219_aad_resume(struct snd_soc_component *component) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 8688c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = da7219->aad; 8698c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (da7219_aad->jack) { 8728c2ecf20Sopenharmony_ci /* Re-enable micbias if previously enabled for 4-pole jack */ 8738c2ecf20Sopenharmony_ci if (da7219_aad->jack_inserted && 8748c2ecf20Sopenharmony_ci da7219_aad->micbias_resume_enable) { 8758c2ecf20Sopenharmony_ci snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); 8768c2ecf20Sopenharmony_ci snd_soc_dapm_sync(dapm); 8778c2ecf20Sopenharmony_ci da7219_aad->micbias_resume_enable = false; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* Re-enable jack detection */ 8818c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, 8828c2ecf20Sopenharmony_ci DA7219_ACCDET_EN_MASK, 8838c2ecf20Sopenharmony_ci DA7219_ACCDET_EN_MASK); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci/* 8898c2ecf20Sopenharmony_ci * Init/Exit 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ciint da7219_aad_init(struct snd_soc_component *component) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 8958c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = da7219->aad; 8968c2ecf20Sopenharmony_ci u8 mask[DA7219_AAD_IRQ_REG_MAX]; 8978c2ecf20Sopenharmony_ci int ret; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci da7219_aad->component = component; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Handle any DT/ACPI/platform data */ 9028c2ecf20Sopenharmony_ci da7219_aad_handle_pdata(component); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* Disable button detection */ 9058c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, 9068c2ecf20Sopenharmony_ci DA7219_BUTTON_CONFIG_MASK, 0); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work); 9098c2ecf20Sopenharmony_ci INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci ret = request_threaded_irq(da7219_aad->irq, NULL, 9128c2ecf20Sopenharmony_ci da7219_aad_irq_thread, 9138c2ecf20Sopenharmony_ci IRQF_TRIGGER_LOW | IRQF_ONESHOT, 9148c2ecf20Sopenharmony_ci "da7219-aad", da7219_aad); 9158c2ecf20Sopenharmony_ci if (ret) { 9168c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to request IRQ: %d\n", ret); 9178c2ecf20Sopenharmony_ci return ret; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* Unmask AAD IRQs */ 9218c2ecf20Sopenharmony_ci memset(mask, 0, DA7219_AAD_IRQ_REG_MAX); 9228c2ecf20Sopenharmony_ci regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, 9238c2ecf20Sopenharmony_ci &mask, DA7219_AAD_IRQ_REG_MAX); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da7219_aad_init); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_civoid da7219_aad_exit(struct snd_soc_component *component) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 9328c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad = da7219->aad; 9338c2ecf20Sopenharmony_ci u8 mask[DA7219_AAD_IRQ_REG_MAX]; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Mask off AAD IRQs */ 9368c2ecf20Sopenharmony_ci memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX); 9378c2ecf20Sopenharmony_ci regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, 9388c2ecf20Sopenharmony_ci mask, DA7219_AAD_IRQ_REG_MAX); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci free_irq(da7219_aad->irq, da7219_aad); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci cancel_work_sync(&da7219_aad->btn_det_work); 9438c2ecf20Sopenharmony_ci cancel_work_sync(&da7219_aad->hptest_work); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da7219_aad_exit); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/* 9488c2ecf20Sopenharmony_ci * AAD related I2C probe handling 9498c2ecf20Sopenharmony_ci */ 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ciint da7219_aad_probe(struct i2c_client *i2c) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct da7219_priv *da7219 = i2c_get_clientdata(i2c); 9548c2ecf20Sopenharmony_ci struct device *dev = &i2c->dev; 9558c2ecf20Sopenharmony_ci struct da7219_aad_priv *da7219_aad; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci da7219_aad = devm_kzalloc(dev, sizeof(*da7219_aad), GFP_KERNEL); 9588c2ecf20Sopenharmony_ci if (!da7219_aad) 9598c2ecf20Sopenharmony_ci return -ENOMEM; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci da7219->aad = da7219_aad; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* Retrieve any DT/ACPI/platform data */ 9648c2ecf20Sopenharmony_ci if (da7219->pdata && !da7219->pdata->aad_pdata) 9658c2ecf20Sopenharmony_ci da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(dev); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return 0; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da7219_aad_probe); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC DA7219 AAD Driver"); 9728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 9738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 974