Linux Audio

Check our new training course

Loading...
v6.13.7
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver
   4 *
   5 * Copyright (c) 2015 Dialog Semiconductor Ltd.
   6 *
   7 * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
 
 
 
 
 
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/platform_device.h>
  12#include <linux/clk.h>
  13#include <linux/i2c.h>
  14#include <linux/property.h>
  15#include <linux/pm_wakeirq.h>
  16#include <linux/slab.h>
  17#include <linux/delay.h>
  18#include <linux/workqueue.h>
  19#include <sound/soc.h>
  20#include <sound/jack.h>
  21#include <sound/da7219.h>
  22
  23#include "da7219.h"
  24#include "da7219-aad.h"
  25
  26
  27/*
  28 * Detection control
  29 */
  30
  31void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack)
  32{
  33	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  34
  35	da7219->aad->jack = jack;
  36	da7219->aad->jack_inserted = false;
  37
  38	/* Send an initial empty report */
  39	snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);
  40
  41	/* Enable/Disable jack detection */
  42	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
  43			    DA7219_ACCDET_EN_MASK,
  44			    (jack ? DA7219_ACCDET_EN_MASK : 0));
  45}
 
  46
  47/*
  48 * Button/HPTest work
  49 */
  50
  51static void da7219_aad_btn_det_work(struct work_struct *work)
  52{
  53	struct da7219_aad_priv *da7219_aad =
  54		container_of(work, struct da7219_aad_priv, btn_det_work);
  55	struct snd_soc_component *component = da7219_aad->component;
  56	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
  57	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
  58	u8 statusa, micbias_ctrl;
  59	bool micbias_up = false;
  60	int retries = 0;
  61
  62	/* Drive headphones/lineout */
  63	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
  64			    DA7219_HP_L_AMP_OE_MASK,
  65			    DA7219_HP_L_AMP_OE_MASK);
  66	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
  67			    DA7219_HP_R_AMP_OE_MASK,
  68			    DA7219_HP_R_AMP_OE_MASK);
  69
  70	/* Make sure mic bias is up */
  71	snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
  72	snd_soc_dapm_sync(dapm);
  73
  74	do {
  75		statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A);
  76		if (statusa & DA7219_MICBIAS_UP_STS_MASK)
  77			micbias_up = true;
  78		else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)
  79			msleep(DA7219_AAD_MICBIAS_CHK_DELAY);
  80	} while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));
  81
  82	if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
  83		dev_warn(component->dev, "Mic bias status check timed out");
  84
  85	da7219->micbias_on_event = true;
  86
  87	/*
  88	 * Mic bias pulse required to enable mic, must be done before enabling
  89	 * button detection to prevent erroneous button readings.
  90	 */
  91	if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {
  92		/* Pulse higher level voltage */
  93		micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL);
  94		snd_soc_component_update_bits(component, DA7219_MICBIAS_CTRL,
  95				    DA7219_MICBIAS1_LEVEL_MASK,
  96				    da7219_aad->micbias_pulse_lvl);
  97		msleep(da7219_aad->micbias_pulse_time);
  98		snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_ctrl);
  99
 100	}
 101
 102	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 103			    DA7219_BUTTON_CONFIG_MASK,
 104			    da7219_aad->btn_cfg);
 105}
 106
 107static void da7219_aad_hptest_work(struct work_struct *work)
 108{
 109	struct da7219_aad_priv *da7219_aad =
 110		container_of(work, struct da7219_aad_priv, hptest_work);
 111	struct snd_soc_component *component = da7219_aad->component;
 112	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 113	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 114
 115	__le16 tonegen_freq_hptest;
 116	u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
 117	int report = 0, ret;
 118
 119	/* Lock DAPM, Kcontrols affected by this test and the PLL */
 120	snd_soc_dapm_mutex_lock(dapm);
 121	mutex_lock(&da7219->ctrl_lock);
 122	mutex_lock(&da7219->pll_lock);
 123
 124	/* Ensure MCLK is available for HP test procedure */
 125	if (da7219->mclk) {
 126		ret = clk_prepare_enable(da7219->mclk);
 127		if (ret) {
 128			dev_err(component->dev, "Failed to enable mclk - %d\n", ret);
 129			mutex_unlock(&da7219->pll_lock);
 130			mutex_unlock(&da7219->ctrl_lock);
 131			snd_soc_dapm_mutex_unlock(dapm);
 132			return;
 133		}
 134	}
 135
 136	/*
 137	 * If MCLK not present, then we're using the internal oscillator and
 138	 * require different frequency settings to achieve the same result.
 139	 *
 140	 * If MCLK is present, but PLL is not enabled then we enable it here to
 141	 * ensure a consistent detection procedure.
 142	 */
 143	pll_srm_sts = snd_soc_component_read(component, DA7219_PLL_SRM_STS);
 144	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {
 145		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
 146
 147		pll_ctrl = snd_soc_component_read(component, DA7219_PLL_CTRL);
 148		if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)
 149			da7219_set_pll(component, DA7219_SYSCLK_PLL,
 150				       DA7219_PLL_FREQ_OUT_98304);
 151	} else {
 152		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
 153	}
 154
 155	/* Ensure gain ramping at fastest rate */
 156	gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL);
 157	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
 158
 159	/* Bypass cache so it saves current settings */
 160	regcache_cache_bypass(da7219->regmap, true);
 161
 162	/* Make sure Tone Generator is disabled */
 163	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
 164
 165	/* Enable HPTest block, 1KOhms check */
 166	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
 167			    DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
 168			    DA7219_HPTEST_EN_MASK |
 169			    DA7219_HPTEST_RES_SEL_1KOHMS);
 170
 171	/* Set gains to 0db */
 172	snd_soc_component_write(component, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
 173	snd_soc_component_write(component, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
 174	snd_soc_component_write(component, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
 175	snd_soc_component_write(component, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
 176
 177	/* Disable DAC filters, EQs and soft mute */
 178	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
 179			    0);
 180	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
 181			    0);
 182	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS5,
 183			    DA7219_DAC_SOFTMUTE_EN_MASK, 0);
 184
 185	/* Enable HP left & right paths */
 186	snd_soc_component_update_bits(component, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
 187			    DA7219_CP_EN_MASK);
 188	snd_soc_component_update_bits(component, DA7219_DIG_ROUTING_DAC,
 189			    DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
 190			    DA7219_DAC_L_SRC_TONEGEN |
 191			    DA7219_DAC_R_SRC_TONEGEN);
 192	snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL,
 193			    DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
 194			    DA7219_DAC_L_EN_MASK);
 195	snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL,
 196			    DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
 197			    DA7219_DAC_R_EN_MASK);
 198	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_SELECT,
 199			    DA7219_MIXOUT_L_MIX_SELECT_MASK,
 200			    DA7219_MIXOUT_L_MIX_SELECT_MASK);
 201	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_SELECT,
 202			    DA7219_MIXOUT_R_MIX_SELECT_MASK,
 203			    DA7219_MIXOUT_R_MIX_SELECT_MASK);
 204	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1L,
 205			    DA7219_OUTFILT_ST_1L_SRC_MASK,
 206			    DA7219_DMIX_ST_SRC_OUTFILT1L);
 207	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1R,
 208			    DA7219_OUTFILT_ST_1R_SRC_MASK,
 209			    DA7219_DMIX_ST_SRC_OUTFILT1R);
 210	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_CTRL,
 211			    DA7219_MIXOUT_L_AMP_EN_MASK,
 212			    DA7219_MIXOUT_L_AMP_EN_MASK);
 213	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_CTRL,
 214			    DA7219_MIXOUT_R_AMP_EN_MASK,
 215			    DA7219_MIXOUT_R_AMP_EN_MASK);
 216	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 217			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
 218			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
 219	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 220			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
 221			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
 222	msleep(DA7219_SETTLING_DELAY);
 223	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 224			    DA7219_HP_L_AMP_MUTE_EN_MASK |
 225			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
 226	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 227			    DA7219_HP_R_AMP_MUTE_EN_MASK |
 228			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
 229
 230	/*
 231	 * If we're running from the internal oscillator then give audio paths
 232	 * time to settle before running test.
 233	 */
 234	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
 235		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
 236
 237	/* Configure & start Tone Generator */
 238	snd_soc_component_write(component, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
 239	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 240			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
 241	snd_soc_component_update_bits(component, DA7219_TONE_GEN_CFG2,
 242			    DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
 243			    DA7219_SWG_SEL_SRAMP |
 244			    DA7219_TONE_GEN_GAIN_MINUS_15DB);
 245	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
 246
 247	msleep(DA7219_AAD_HPTEST_PERIOD);
 248
 249	/* Grab comparator reading */
 250	accdet_cfg8 = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_8);
 251	if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
 252		report |= SND_JACK_HEADPHONE;
 253	else
 254		report |= SND_JACK_LINEOUT;
 255
 256	/* Stop tone generator */
 257	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
 258
 259	msleep(DA7219_AAD_HPTEST_PERIOD);
 260
 261	/* Restore original settings from cache */
 262	regcache_mark_dirty(da7219->regmap);
 263	regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
 264			     DA7219_HP_R_CTRL);
 265	msleep(DA7219_SETTLING_DELAY);
 266	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
 267			     DA7219_MIXOUT_R_CTRL);
 268	regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
 269			     DA7219_DROUTING_ST_OUTFILT_1R);
 270	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,
 271			     DA7219_MIXOUT_R_SELECT);
 272	regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,
 273			     DA7219_DAC_R_CTRL);
 274	regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,
 275			     DA7219_DIG_ROUTING_DAC);
 276	regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);
 277	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,
 278			     DA7219_DAC_FILTERS5);
 279	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,
 280			     DA7219_DAC_FILTERS1);
 281	regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,
 282			     DA7219_HP_R_GAIN);
 283	regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,
 284			     DA7219_DAC_R_GAIN);
 285	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,
 286			     DA7219_TONE_GEN_ON_PER);
 287	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 288			     DA7219_TONE_GEN_FREQ1_U);
 289	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,
 290			     DA7219_TONE_GEN_CFG2);
 291
 292	regcache_cache_bypass(da7219->regmap, false);
 293
 294	/* Disable HPTest block */
 295	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
 296			    DA7219_HPTEST_EN_MASK, 0);
 297
 298	/*
 299	 * If we're running from the internal oscillator then give audio paths
 300	 * time to settle before allowing headphones to be driven as required.
 301	 */
 302	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
 303		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
 304
 305	/* Restore gain ramping rate */
 306	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
 307
 308	/* Drive Headphones/lineout */
 309	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
 310			    DA7219_HP_L_AMP_OE_MASK);
 311	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
 312			    DA7219_HP_R_AMP_OE_MASK);
 313
 314	/* Restore PLL to previous configuration, if re-configured */
 315	if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&
 316	    ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))
 317		da7219_set_pll(component, DA7219_SYSCLK_MCLK, 0);
 318
 319	/* Remove MCLK, if previously enabled */
 320	if (da7219->mclk)
 321		clk_disable_unprepare(da7219->mclk);
 322
 323	mutex_unlock(&da7219->pll_lock);
 324	mutex_unlock(&da7219->ctrl_lock);
 325	snd_soc_dapm_mutex_unlock(dapm);
 326
 327	/*
 328	 * Only send report if jack hasn't been removed during process,
 329	 * otherwise it's invalid and we drop it.
 330	 */
 331	if (da7219_aad->jack_inserted)
 332		snd_soc_jack_report(da7219_aad->jack, report,
 333				    SND_JACK_HEADSET | SND_JACK_LINEOUT);
 334}
 335
 336static void da7219_aad_jack_det_work(struct work_struct *work)
 337{
 338	struct da7219_aad_priv *da7219_aad =
 339		container_of(work, struct da7219_aad_priv, jack_det_work.work);
 340	struct snd_soc_component *component = da7219_aad->component;
 341
 342	/* Enable ground switch */
 343	snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);
 344}
 345
 346/*
 347 * IRQ
 348 */
 349
 350static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
 351{
 352	struct da7219_aad_priv *da7219_aad = data;
 353	struct snd_soc_component *component = da7219_aad->component;
 354	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 355	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 356	u8 events[DA7219_AAD_IRQ_REG_MAX];
 357	u8 statusa;
 358	int i, ret, report = 0, mask = 0;
 359
 360	/* Read current IRQ events */
 361	ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
 362			       events, DA7219_AAD_IRQ_REG_MAX);
 363	if (ret) {
 364		dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret);
 365		return IRQ_NONE;
 366	}
 367
 368	if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
 369		return IRQ_NONE;
 370
 371	/* Read status register for jack insertion & type status */
 372	statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A);
 373
 374	if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_INSERTED_MASK) {
 375		u8 srm_st;
 376		int delay = 0;
 377
 378		srm_st = snd_soc_component_read(component,
 379					DA7219_PLL_SRM_STS) & DA7219_PLL_SRM_STS_MCLK;
 380		delay = (da7219_aad->gnd_switch_delay * ((srm_st == 0x0) ? 2 : 1) - 2);
 381		queue_delayed_work(da7219_aad->aad_wq,
 382							&da7219_aad->jack_det_work,
 383							msecs_to_jiffies(delay));
 384	}
 385
 386	/* Clear events */
 387	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
 388			  events, DA7219_AAD_IRQ_REG_MAX);
 389
 390	dev_dbg(component->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
 391		events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
 392		statusa);
 393
 394	if (statusa & DA7219_JACK_INSERTION_STS_MASK) {
 395		/* Jack Insertion */
 396		if (events[DA7219_AAD_IRQ_REG_A] &
 397		    DA7219_E_JACK_INSERTED_MASK) {
 398			report |= SND_JACK_MECHANICAL;
 399			mask |= SND_JACK_MECHANICAL;
 400			da7219_aad->jack_inserted = true;
 401		}
 402
 403		/* Jack type detection */
 404		if (events[DA7219_AAD_IRQ_REG_A] &
 405		    DA7219_E_JACK_DETECT_COMPLETE_MASK) {
 406			/*
 407			 * If 4-pole, then enable button detection, else perform
 408			 * HP impedance test to determine output type to report.
 409			 *
 410			 * We schedule work here as the tasks themselves can
 411			 * take time to complete, and in particular for hptest
 412			 * we want to be able to check if the jack was removed
 413			 * during the procedure as this will invalidate the
 414			 * result. By doing this as work, the IRQ thread can
 415			 * handle a removal, and we can check at the end of
 416			 * hptest if we have a valid result or not.
 417			 */
 418
 419			cancel_delayed_work_sync(&da7219_aad->jack_det_work);
 420			/* Disable ground switch */
 421			snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
 422
 423			if (statusa & DA7219_JACK_TYPE_STS_MASK) {
 424				report |= SND_JACK_HEADSET;
 425				mask |=	SND_JACK_HEADSET | SND_JACK_LINEOUT;
 426				queue_work(da7219_aad->aad_wq, &da7219_aad->btn_det_work);
 427			} else {
 428				queue_work(da7219_aad->aad_wq, &da7219_aad->hptest_work);
 429			}
 430		}
 431
 432		/* Button support for 4-pole jack */
 433		if (statusa & DA7219_JACK_TYPE_STS_MASK) {
 434			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
 435				/* Button Press */
 436				if (events[DA7219_AAD_IRQ_REG_B] &
 437				    (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {
 438					report |= SND_JACK_BTN_0 >> i;
 439					mask |= SND_JACK_BTN_0 >> i;
 440				}
 441			}
 442			snd_soc_jack_report(da7219_aad->jack, report, mask);
 443
 444			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
 445				/* Button Release */
 446				if (events[DA7219_AAD_IRQ_REG_B] &
 447				    (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {
 448					report &= ~(SND_JACK_BTN_0 >> i);
 449					mask |= SND_JACK_BTN_0 >> i;
 450				}
 451			}
 452		}
 453	} else {
 454		/* Jack removal */
 455		if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {
 456			report = 0;
 457			mask |= DA7219_AAD_REPORT_ALL_MASK;
 458			da7219_aad->jack_inserted = false;
 459
 460			/* Cancel any pending work */
 461			cancel_delayed_work_sync(&da7219_aad->jack_det_work);
 462			cancel_work_sync(&da7219_aad->btn_det_work);
 463			cancel_work_sync(&da7219_aad->hptest_work);
 464
 465			/* Un-drive headphones/lineout */
 466			snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 467					    DA7219_HP_R_AMP_OE_MASK, 0);
 468			snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 469					    DA7219_HP_L_AMP_OE_MASK, 0);
 470
 471			/* Ensure button detection disabled */
 472			snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 473					    DA7219_BUTTON_CONFIG_MASK, 0);
 474
 475			da7219->micbias_on_event = false;
 476
 477			/* Disable mic bias */
 478			snd_soc_dapm_disable_pin(dapm, "Mic Bias");
 479			snd_soc_dapm_sync(dapm);
 480
 481			/* Disable ground switch */
 482			snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
 
 483		}
 484	}
 485
 486	snd_soc_jack_report(da7219_aad->jack, report, mask);
 487
 488	return IRQ_HANDLED;
 489}
 490
 491/*
 492 * DT/ACPI to pdata conversion
 493 */
 494
 495static enum da7219_aad_micbias_pulse_lvl
 496	da7219_aad_fw_micbias_pulse_lvl(struct device *dev, u32 val)
 497{
 498	switch (val) {
 499	case 2800:
 500		return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;
 501	case 2900:
 502		return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
 503	default:
 504		dev_warn(dev, "Invalid micbias pulse level");
 505		return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
 506	}
 507}
 508
 509static enum da7219_aad_btn_cfg
 510	da7219_aad_fw_btn_cfg(struct device *dev, u32 val)
 511{
 512	switch (val) {
 513	case 2:
 514		return DA7219_AAD_BTN_CFG_2MS;
 515	case 5:
 516		return DA7219_AAD_BTN_CFG_5MS;
 517	case 10:
 518		return DA7219_AAD_BTN_CFG_10MS;
 519	case 50:
 520		return DA7219_AAD_BTN_CFG_50MS;
 521	case 100:
 522		return DA7219_AAD_BTN_CFG_100MS;
 523	case 200:
 524		return DA7219_AAD_BTN_CFG_200MS;
 525	case 500:
 526		return DA7219_AAD_BTN_CFG_500MS;
 527	default:
 528		dev_warn(dev, "Invalid button config");
 529		return DA7219_AAD_BTN_CFG_10MS;
 530	}
 531}
 532
 533static enum da7219_aad_mic_det_thr
 534	da7219_aad_fw_mic_det_thr(struct device *dev, u32 val)
 535{
 536	switch (val) {
 537	case 200:
 538		return DA7219_AAD_MIC_DET_THR_200_OHMS;
 539	case 500:
 540		return DA7219_AAD_MIC_DET_THR_500_OHMS;
 541	case 750:
 542		return DA7219_AAD_MIC_DET_THR_750_OHMS;
 543	case 1000:
 544		return DA7219_AAD_MIC_DET_THR_1000_OHMS;
 545	default:
 546		dev_warn(dev, "Invalid mic detect threshold");
 547		return DA7219_AAD_MIC_DET_THR_500_OHMS;
 548	}
 549}
 550
 551static enum da7219_aad_jack_ins_deb
 552	da7219_aad_fw_jack_ins_deb(struct device *dev, u32 val)
 553{
 554	switch (val) {
 555	case 5:
 556		return DA7219_AAD_JACK_INS_DEB_5MS;
 557	case 10:
 558		return DA7219_AAD_JACK_INS_DEB_10MS;
 559	case 20:
 560		return DA7219_AAD_JACK_INS_DEB_20MS;
 561	case 50:
 562		return DA7219_AAD_JACK_INS_DEB_50MS;
 563	case 100:
 564		return DA7219_AAD_JACK_INS_DEB_100MS;
 565	case 200:
 566		return DA7219_AAD_JACK_INS_DEB_200MS;
 567	case 500:
 568		return DA7219_AAD_JACK_INS_DEB_500MS;
 569	case 1000:
 570		return DA7219_AAD_JACK_INS_DEB_1S;
 571	default:
 572		dev_warn(dev, "Invalid jack insert debounce");
 573		return DA7219_AAD_JACK_INS_DEB_20MS;
 574	}
 575}
 576
 577static enum da7219_aad_jack_ins_det_pty
 578	da7219_aad_fw_jack_ins_det_pty(struct device *dev, const char *str)
 579{
 580	if (!strcmp(str, "low")) {
 581		return DA7219_AAD_JACK_INS_DET_PTY_LOW;
 582	} else if (!strcmp(str, "high")) {
 583		return DA7219_AAD_JACK_INS_DET_PTY_HIGH;
 584	} else {
 585		dev_warn(dev, "Invalid jack insertion detection polarity");
 586		return DA7219_AAD_JACK_INS_DET_PTY_LOW;
 587	}
 588}
 589
 590static enum da7219_aad_jack_det_rate
 591	da7219_aad_fw_jack_det_rate(struct device *dev, const char *str)
 592{
 593	if (!strcmp(str, "32_64")) {
 594		return DA7219_AAD_JACK_DET_RATE_32_64MS;
 595	} else if (!strcmp(str, "64_128")) {
 596		return DA7219_AAD_JACK_DET_RATE_64_128MS;
 597	} else if (!strcmp(str, "128_256")) {
 598		return DA7219_AAD_JACK_DET_RATE_128_256MS;
 599	} else if (!strcmp(str, "256_512")) {
 600		return DA7219_AAD_JACK_DET_RATE_256_512MS;
 601	} else {
 602		dev_warn(dev, "Invalid jack detect rate");
 603		return DA7219_AAD_JACK_DET_RATE_256_512MS;
 604	}
 605}
 606
 607static enum da7219_aad_jack_rem_deb
 608	da7219_aad_fw_jack_rem_deb(struct device *dev, u32 val)
 609{
 610	switch (val) {
 611	case 1:
 612		return DA7219_AAD_JACK_REM_DEB_1MS;
 613	case 5:
 614		return DA7219_AAD_JACK_REM_DEB_5MS;
 615	case 10:
 616		return DA7219_AAD_JACK_REM_DEB_10MS;
 617	case 20:
 618		return DA7219_AAD_JACK_REM_DEB_20MS;
 619	default:
 620		dev_warn(dev, "Invalid jack removal debounce");
 621		return DA7219_AAD_JACK_REM_DEB_1MS;
 622	}
 623}
 624
 625static enum da7219_aad_btn_avg
 626	da7219_aad_fw_btn_avg(struct device *dev, u32 val)
 627{
 628	switch (val) {
 629	case 1:
 630		return DA7219_AAD_BTN_AVG_1;
 631	case 2:
 632		return DA7219_AAD_BTN_AVG_2;
 633	case 4:
 634		return DA7219_AAD_BTN_AVG_4;
 635	case 8:
 636		return DA7219_AAD_BTN_AVG_8;
 637	default:
 638		dev_warn(dev, "Invalid button average value");
 639		return DA7219_AAD_BTN_AVG_2;
 640	}
 641}
 642
 643static enum da7219_aad_adc_1bit_rpt
 644	da7219_aad_fw_adc_1bit_rpt(struct device *dev, u32 val)
 645{
 646	switch (val) {
 647	case 1:
 648		return DA7219_AAD_ADC_1BIT_RPT_1;
 649	case 2:
 650		return DA7219_AAD_ADC_1BIT_RPT_2;
 651	case 4:
 652		return DA7219_AAD_ADC_1BIT_RPT_4;
 653	case 8:
 654		return DA7219_AAD_ADC_1BIT_RPT_8;
 655	default:
 656		dev_warn(dev, "Invalid ADC 1-bit repeat value");
 657		return DA7219_AAD_ADC_1BIT_RPT_1;
 658	}
 659}
 660
 661static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
 662{
 
 663	struct i2c_client *i2c = to_i2c_client(dev);
 664	struct fwnode_handle *aad_np;
 665	struct da7219_aad_pdata *aad_pdata;
 666	const char *fw_str;
 667	u32 fw_val32;
 668
 669	aad_np = device_get_named_child_node(dev, "da7219_aad");
 670	if (!aad_np)
 671		return NULL;
 672
 673	aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);
 674	if (!aad_pdata) {
 675		fwnode_handle_put(aad_np);
 676		return NULL;
 677	}
 678
 679	aad_pdata->irq = i2c->irq;
 680
 681	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
 682				     &fw_val32) >= 0)
 683		aad_pdata->micbias_pulse_lvl =
 684			da7219_aad_fw_micbias_pulse_lvl(dev, fw_val32);
 685	else
 686		aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
 687
 688	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time",
 689				     &fw_val32) >= 0)
 690		aad_pdata->micbias_pulse_time = fw_val32;
 691
 692	if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)
 693		aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(dev, fw_val32);
 694	else
 695		aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
 696
 697	if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)
 698		aad_pdata->mic_det_thr =
 699			da7219_aad_fw_mic_det_thr(dev, fw_val32);
 700	else
 701		aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_200_OHMS;
 702
 703	if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
 704		aad_pdata->jack_ins_deb =
 705			da7219_aad_fw_jack_ins_deb(dev, fw_val32);
 706	else
 707		aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
 708
 709	if (!fwnode_property_read_string(aad_np, "dlg,jack-ins-det-pty", &fw_str))
 710		aad_pdata->jack_ins_det_pty =
 711			da7219_aad_fw_jack_ins_det_pty(dev, fw_str);
 712	else
 713		aad_pdata->jack_ins_det_pty = DA7219_AAD_JACK_INS_DET_PTY_LOW;
 714
 715	if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
 716		aad_pdata->jack_det_rate =
 717			da7219_aad_fw_jack_det_rate(dev, fw_str);
 718	else
 719		aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
 720
 721	if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)
 722		aad_pdata->jack_rem_deb =
 723			da7219_aad_fw_jack_rem_deb(dev, fw_val32);
 724	else
 725		aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
 726
 727	if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0)
 728		aad_pdata->a_d_btn_thr = (u8) fw_val32;
 729	else
 730		aad_pdata->a_d_btn_thr = 0xA;
 731
 732	if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0)
 733		aad_pdata->d_b_btn_thr = (u8) fw_val32;
 734	else
 735		aad_pdata->d_b_btn_thr = 0x16;
 736
 737	if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0)
 738		aad_pdata->b_c_btn_thr = (u8) fw_val32;
 739	else
 740		aad_pdata->b_c_btn_thr = 0x21;
 741
 742	if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0)
 743		aad_pdata->c_mic_btn_thr = (u8) fw_val32;
 744	else
 745		aad_pdata->c_mic_btn_thr = 0x3E;
 746
 747	if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)
 748		aad_pdata->btn_avg = da7219_aad_fw_btn_avg(dev, fw_val32);
 749	else
 750		aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
 751
 752	if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)
 753		aad_pdata->adc_1bit_rpt =
 754			da7219_aad_fw_adc_1bit_rpt(dev, fw_val32);
 755	else
 756		aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
 757
 758	fwnode_handle_put(aad_np);
 759
 760	return aad_pdata;
 761}
 762
 763static void da7219_aad_handle_pdata(struct snd_soc_component *component)
 764{
 765	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 766	struct da7219_aad_priv *da7219_aad = da7219->aad;
 767	struct da7219_pdata *pdata = da7219->pdata;
 768
 769	if ((pdata) && (pdata->aad_pdata)) {
 770		struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;
 771		u8 cfg, mask;
 772
 773		da7219_aad->irq = aad_pdata->irq;
 774
 775		switch (aad_pdata->micbias_pulse_lvl) {
 776		case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:
 777		case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:
 778			da7219_aad->micbias_pulse_lvl =
 779				(aad_pdata->micbias_pulse_lvl <<
 780				 DA7219_MICBIAS1_LEVEL_SHIFT);
 781			break;
 782		default:
 783			break;
 784		}
 785
 786		da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;
 787
 788		switch (aad_pdata->btn_cfg) {
 789		case DA7219_AAD_BTN_CFG_2MS:
 790		case DA7219_AAD_BTN_CFG_5MS:
 791		case DA7219_AAD_BTN_CFG_10MS:
 792		case DA7219_AAD_BTN_CFG_50MS:
 793		case DA7219_AAD_BTN_CFG_100MS:
 794		case DA7219_AAD_BTN_CFG_200MS:
 795		case DA7219_AAD_BTN_CFG_500MS:
 796			da7219_aad->btn_cfg  = (aad_pdata->btn_cfg <<
 797						DA7219_BUTTON_CONFIG_SHIFT);
 798		}
 799
 800		cfg = 0;
 801		mask = 0;
 802		switch (aad_pdata->mic_det_thr) {
 803		case DA7219_AAD_MIC_DET_THR_200_OHMS:
 804		case DA7219_AAD_MIC_DET_THR_500_OHMS:
 805		case DA7219_AAD_MIC_DET_THR_750_OHMS:
 806		case DA7219_AAD_MIC_DET_THR_1000_OHMS:
 807			cfg |= (aad_pdata->mic_det_thr <<
 808				DA7219_MIC_DET_THRESH_SHIFT);
 809			mask |= DA7219_MIC_DET_THRESH_MASK;
 810		}
 811		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, mask, cfg);
 812
 813		cfg = 0;
 814		mask = 0;
 815		switch (aad_pdata->jack_ins_deb) {
 816		case DA7219_AAD_JACK_INS_DEB_5MS:
 817		case DA7219_AAD_JACK_INS_DEB_10MS:
 818		case DA7219_AAD_JACK_INS_DEB_20MS:
 819		case DA7219_AAD_JACK_INS_DEB_50MS:
 820		case DA7219_AAD_JACK_INS_DEB_100MS:
 821		case DA7219_AAD_JACK_INS_DEB_200MS:
 822		case DA7219_AAD_JACK_INS_DEB_500MS:
 823		case DA7219_AAD_JACK_INS_DEB_1S:
 824			cfg |= (aad_pdata->jack_ins_deb <<
 825				DA7219_JACKDET_DEBOUNCE_SHIFT);
 826			mask |= DA7219_JACKDET_DEBOUNCE_MASK;
 827		}
 828		switch (aad_pdata->jack_det_rate) {
 829		case DA7219_AAD_JACK_DET_RATE_32_64MS:
 830		case DA7219_AAD_JACK_DET_RATE_64_128MS:
 831		case DA7219_AAD_JACK_DET_RATE_128_256MS:
 832		case DA7219_AAD_JACK_DET_RATE_256_512MS:
 833			cfg |= (aad_pdata->jack_det_rate <<
 834				DA7219_JACK_DETECT_RATE_SHIFT);
 835			mask |= DA7219_JACK_DETECT_RATE_MASK;
 836		}
 837		switch (aad_pdata->jack_rem_deb) {
 838		case DA7219_AAD_JACK_REM_DEB_1MS:
 839		case DA7219_AAD_JACK_REM_DEB_5MS:
 840		case DA7219_AAD_JACK_REM_DEB_10MS:
 841		case DA7219_AAD_JACK_REM_DEB_20MS:
 842			cfg |= (aad_pdata->jack_rem_deb <<
 843				DA7219_JACKDET_REM_DEB_SHIFT);
 844			mask |= DA7219_JACKDET_REM_DEB_MASK;
 845		}
 846		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_2, mask, cfg);
 847
 848		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_3,
 849			      aad_pdata->a_d_btn_thr);
 850		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_4,
 851			      aad_pdata->d_b_btn_thr);
 852		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_5,
 853			      aad_pdata->b_c_btn_thr);
 854		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_6,
 855			      aad_pdata->c_mic_btn_thr);
 856
 857		cfg = 0;
 858		mask = 0;
 859		switch (aad_pdata->btn_avg) {
 860		case DA7219_AAD_BTN_AVG_1:
 861		case DA7219_AAD_BTN_AVG_2:
 862		case DA7219_AAD_BTN_AVG_4:
 863		case DA7219_AAD_BTN_AVG_8:
 864			cfg |= (aad_pdata->btn_avg <<
 865				DA7219_BUTTON_AVERAGE_SHIFT);
 866			mask |= DA7219_BUTTON_AVERAGE_MASK;
 867		}
 868		switch (aad_pdata->adc_1bit_rpt) {
 869		case DA7219_AAD_ADC_1BIT_RPT_1:
 870		case DA7219_AAD_ADC_1BIT_RPT_2:
 871		case DA7219_AAD_ADC_1BIT_RPT_4:
 872		case DA7219_AAD_ADC_1BIT_RPT_8:
 873			cfg |= (aad_pdata->adc_1bit_rpt <<
 874			       DA7219_ADC_1_BIT_REPEAT_SHIFT);
 875			mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
 876		}
 877		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg);
 878
 879		switch (aad_pdata->jack_ins_det_pty) {
 880		case DA7219_AAD_JACK_INS_DET_PTY_LOW:
 881			snd_soc_component_write(component, 0xF0, 0x8B);
 882			snd_soc_component_write(component, 0x75, 0x80);
 883			snd_soc_component_write(component, 0xF0, 0x00);
 884			break;
 885		case DA7219_AAD_JACK_INS_DET_PTY_HIGH:
 886			snd_soc_component_write(component, 0xF0, 0x8B);
 887			snd_soc_component_write(component, 0x75, 0x00);
 888			snd_soc_component_write(component, 0xF0, 0x00);
 889			break;
 890		default:
 891			break;
 892		}
 893	}
 894}
 895
 896static void da7219_aad_handle_gnd_switch_time(struct snd_soc_component *component)
 897{
 898	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 899	struct da7219_aad_priv *da7219_aad = da7219->aad;
 900	u8 jack_det;
 901
 902	jack_det = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_2)
 903		& DA7219_JACK_DETECT_RATE_MASK;
 904	switch (jack_det) {
 905	case 0x00:
 906		da7219_aad->gnd_switch_delay = 32;
 907		break;
 908	case 0x10:
 909		da7219_aad->gnd_switch_delay = 64;
 910		break;
 911	case 0x20:
 912		da7219_aad->gnd_switch_delay = 128;
 913		break;
 914	case 0x30:
 915		da7219_aad->gnd_switch_delay = 256;
 916		break;
 917	default:
 918		da7219_aad->gnd_switch_delay = 32;
 919		break;
 920	}
 921}
 922
 923/*
 924 * Suspend/Resume
 925 */
 926
 927void da7219_aad_suspend(struct snd_soc_component *component)
 928{
 929	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 930	struct da7219_aad_priv *da7219_aad = da7219->aad;
 931	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 932	u8 micbias_ctrl;
 933
 934	disable_irq(da7219_aad->irq);
 935
 936	if (da7219_aad->jack) {
 937		/* Disable jack detection during suspend */
 938		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 939				    DA7219_ACCDET_EN_MASK, 0);
 940		cancel_delayed_work_sync(&da7219_aad->jack_det_work);
 941		/* Disable ground switch */
 942		snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
 943
 944		/*
 945		 * If we have a 4-pole jack inserted, then micbias will be
 946		 * enabled. We can disable micbias here, and keep a note to
 947		 * re-enable it on resume. If jack removal occurred during
 948		 * suspend then this will be dealt with through the IRQ handler.
 949		 */
 950		if (da7219_aad->jack_inserted) {
 951			micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL);
 952			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
 953				snd_soc_dapm_disable_pin(dapm, "Mic Bias");
 954				snd_soc_dapm_sync(dapm);
 955				da7219_aad->micbias_resume_enable = true;
 956			}
 957		}
 958	}
 959}
 960
 961void da7219_aad_resume(struct snd_soc_component *component)
 962{
 963	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 964	struct da7219_aad_priv *da7219_aad = da7219->aad;
 965	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 966
 967	if (da7219_aad->jack) {
 968		/* Re-enable micbias if previously enabled for 4-pole jack */
 969		if (da7219_aad->jack_inserted &&
 970		    da7219_aad->micbias_resume_enable) {
 971			snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
 972			snd_soc_dapm_sync(dapm);
 973			da7219_aad->micbias_resume_enable = false;
 974		}
 975
 976		/* Re-enable jack detection */
 977		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 978				    DA7219_ACCDET_EN_MASK,
 979				    DA7219_ACCDET_EN_MASK);
 980	}
 981
 982	enable_irq(da7219_aad->irq);
 983}
 984
 985
 986/*
 987 * Init/Exit
 988 */
 989
 990int da7219_aad_init(struct snd_soc_component *component)
 991{
 992	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 993	struct da7219_aad_priv *da7219_aad = da7219->aad;
 994	u8 mask[DA7219_AAD_IRQ_REG_MAX];
 995	int ret;
 996
 997	da7219_aad->component = component;
 
 
 
 
 
 998
 999	/* Handle any DT/ACPI/platform data */
1000	da7219_aad_handle_pdata(component);
 
 
 
1001
1002	/* Disable button detection */
1003	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
1004			    DA7219_BUTTON_CONFIG_MASK, 0);
1005
1006	da7219_aad_handle_gnd_switch_time(component);
1007
1008	da7219_aad->aad_wq = create_singlethread_workqueue("da7219-aad");
1009	if (!da7219_aad->aad_wq) {
1010		dev_err(component->dev, "Failed to create aad workqueue\n");
1011		return -ENOMEM;
1012	}
1013
1014	INIT_DELAYED_WORK(&da7219_aad->jack_det_work, da7219_aad_jack_det_work);
1015	INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
1016	INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
1017
1018	ret = request_threaded_irq(da7219_aad->irq, NULL,
1019				   da7219_aad_irq_thread,
1020				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
1021				   "da7219-aad", da7219_aad);
1022	if (ret) {
1023		dev_err(component->dev, "Failed to request IRQ: %d\n", ret);
1024		return ret;
1025	}
1026
1027	/* Unmask AAD IRQs */
1028	memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);
1029	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
1030			  &mask, DA7219_AAD_IRQ_REG_MAX);
1031
1032	return 0;
1033}
 
1034
1035void da7219_aad_exit(struct snd_soc_component *component)
1036{
1037	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
1038	struct da7219_aad_priv *da7219_aad = da7219->aad;
1039	u8 mask[DA7219_AAD_IRQ_REG_MAX];
1040
1041	/* Mask off AAD IRQs */
1042	memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);
1043	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
1044			  mask, DA7219_AAD_IRQ_REG_MAX);
1045
1046	free_irq(da7219_aad->irq, da7219_aad);
1047
1048	cancel_delayed_work_sync(&da7219_aad->jack_det_work);
1049	cancel_work_sync(&da7219_aad->btn_det_work);
1050	cancel_work_sync(&da7219_aad->hptest_work);
1051	destroy_workqueue(da7219_aad->aad_wq);
1052}
1053
1054/*
1055 * AAD related I2C probe handling
1056 */
1057
1058int da7219_aad_probe(struct i2c_client *i2c)
1059{
1060	struct da7219_priv *da7219 = i2c_get_clientdata(i2c);
1061	struct device *dev = &i2c->dev;
1062	struct da7219_aad_priv *da7219_aad;
1063
1064	da7219_aad = devm_kzalloc(dev, sizeof(*da7219_aad), GFP_KERNEL);
1065	if (!da7219_aad)
1066		return -ENOMEM;
1067
1068	da7219->aad = da7219_aad;
1069
1070	/* Retrieve any DT/ACPI/platform data */
1071	if (da7219->pdata && !da7219->pdata->aad_pdata)
1072		da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(dev);
1073
1074	return 0;
1075}
 
1076
1077MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
1078MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
1079MODULE_AUTHOR("David Rau <David.Rau.opensource@dm.renesas.com>");
1080MODULE_LICENSE("GPL");
v4.10.11
 
  1/*
  2 * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver
  3 *
  4 * Copyright (c) 2015 Dialog Semiconductor Ltd.
  5 *
  6 * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
  7 *
  8 * This program is free software; you can redistribute  it and/or modify it
  9 * under  the terms of  the GNU General  Public License as published by the
 10 * Free Software Foundation;  either version 2 of the  License, or (at your
 11 * option) any later version.
 12 */
 13
 14#include <linux/module.h>
 15#include <linux/platform_device.h>
 16#include <linux/clk.h>
 17#include <linux/i2c.h>
 18#include <linux/property.h>
 19#include <linux/pm_wakeirq.h>
 20#include <linux/slab.h>
 21#include <linux/delay.h>
 22#include <linux/workqueue.h>
 23#include <sound/soc.h>
 24#include <sound/jack.h>
 25#include <sound/da7219.h>
 26
 27#include "da7219.h"
 28#include "da7219-aad.h"
 29
 30
 31/*
 32 * Detection control
 33 */
 34
 35void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 36{
 37	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 38
 39	da7219->aad->jack = jack;
 40	da7219->aad->jack_inserted = false;
 41
 42	/* Send an initial empty report */
 43	snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);
 44
 45	/* Enable/Disable jack detection */
 46	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
 47			    DA7219_ACCDET_EN_MASK,
 48			    (jack ? DA7219_ACCDET_EN_MASK : 0));
 49}
 50EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
 51
 52/*
 53 * Button/HPTest work
 54 */
 55
 56static void da7219_aad_btn_det_work(struct work_struct *work)
 57{
 58	struct da7219_aad_priv *da7219_aad =
 59		container_of(work, struct da7219_aad_priv, btn_det_work);
 60	struct snd_soc_codec *codec = da7219_aad->codec;
 61	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
 62	u8 statusa, micbias_ctrl;
 63	bool micbias_up = false;
 64	int retries = 0;
 65
 66	/* Drive headphones/lineout */
 67	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
 68			    DA7219_HP_L_AMP_OE_MASK,
 69			    DA7219_HP_L_AMP_OE_MASK);
 70	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
 71			    DA7219_HP_R_AMP_OE_MASK,
 72			    DA7219_HP_R_AMP_OE_MASK);
 73
 74	/* Make sure mic bias is up */
 75	snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
 76	snd_soc_dapm_sync(dapm);
 77
 78	do {
 79		statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
 80		if (statusa & DA7219_MICBIAS_UP_STS_MASK)
 81			micbias_up = true;
 82		else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)
 83			msleep(DA7219_AAD_MICBIAS_CHK_DELAY);
 84	} while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));
 85
 86	if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
 87		dev_warn(codec->dev, "Mic bias status check timed out");
 
 
 88
 89	/*
 90	 * Mic bias pulse required to enable mic, must be done before enabling
 91	 * button detection to prevent erroneous button readings.
 92	 */
 93	if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {
 94		/* Pulse higher level voltage */
 95		micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
 96		snd_soc_update_bits(codec, DA7219_MICBIAS_CTRL,
 97				    DA7219_MICBIAS1_LEVEL_MASK,
 98				    da7219_aad->micbias_pulse_lvl);
 99		msleep(da7219_aad->micbias_pulse_time);
100		snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_ctrl);
101
102	}
103
104	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
105			    DA7219_BUTTON_CONFIG_MASK,
106			    da7219_aad->btn_cfg);
107}
108
109static void da7219_aad_hptest_work(struct work_struct *work)
110{
111	struct da7219_aad_priv *da7219_aad =
112		container_of(work, struct da7219_aad_priv, hptest_work);
113	struct snd_soc_codec *codec = da7219_aad->codec;
114	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
115	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
116
117	u16 tonegen_freq_hptest;
118	u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8;
119	int report = 0, ret = 0;
120
121	/* Lock DAPM and any Kcontrols that are affected by this test */
122	snd_soc_dapm_mutex_lock(dapm);
123	mutex_lock(&da7219->lock);
 
124
125	/* Ensure MCLK is available for HP test procedure */
126	if (da7219->mclk) {
127		ret = clk_prepare_enable(da7219->mclk);
128		if (ret) {
129			dev_err(codec->dev, "Failed to enable mclk - %d\n", ret);
130			mutex_unlock(&da7219->lock);
 
131			snd_soc_dapm_mutex_unlock(dapm);
132			return;
133		}
134	}
135
136	/*
137	 * If MCLK not present, then we're using the internal oscillator and
138	 * require different frequency settings to achieve the same result.
 
 
 
139	 */
140	pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS);
141	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)
142		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
143	else
 
 
 
 
 
144		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
 
145
146	/* Ensure gain ramping at fastest rate */
147	gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
148	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
149
150	/* Bypass cache so it saves current settings */
151	regcache_cache_bypass(da7219->regmap, true);
152
153	/* Make sure Tone Generator is disabled */
154	snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
155
156	/* Enable HPTest block, 1KOhms check */
157	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
158			    DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
159			    DA7219_HPTEST_EN_MASK |
160			    DA7219_HPTEST_RES_SEL_1KOHMS);
161
162	/* Set gains to 0db */
163	snd_soc_write(codec, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
164	snd_soc_write(codec, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
165	snd_soc_write(codec, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
166	snd_soc_write(codec, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
167
168	/* Disable DAC filters, EQs and soft mute */
169	snd_soc_update_bits(codec, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
170			    0);
171	snd_soc_update_bits(codec, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
172			    0);
173	snd_soc_update_bits(codec, DA7219_DAC_FILTERS5,
174			    DA7219_DAC_SOFTMUTE_EN_MASK, 0);
175
176	/* Enable HP left & right paths */
177	snd_soc_update_bits(codec, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
178			    DA7219_CP_EN_MASK);
179	snd_soc_update_bits(codec, DA7219_DIG_ROUTING_DAC,
180			    DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
181			    DA7219_DAC_L_SRC_TONEGEN |
182			    DA7219_DAC_R_SRC_TONEGEN);
183	snd_soc_update_bits(codec, DA7219_DAC_L_CTRL,
184			    DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
185			    DA7219_DAC_L_EN_MASK);
186	snd_soc_update_bits(codec, DA7219_DAC_R_CTRL,
187			    DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
188			    DA7219_DAC_R_EN_MASK);
189	snd_soc_update_bits(codec, DA7219_MIXOUT_L_SELECT,
190			    DA7219_MIXOUT_L_MIX_SELECT_MASK,
191			    DA7219_MIXOUT_L_MIX_SELECT_MASK);
192	snd_soc_update_bits(codec, DA7219_MIXOUT_R_SELECT,
193			    DA7219_MIXOUT_R_MIX_SELECT_MASK,
194			    DA7219_MIXOUT_R_MIX_SELECT_MASK);
195	snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1L,
196			    DA7219_OUTFILT_ST_1L_SRC_MASK,
197			    DA7219_DMIX_ST_SRC_OUTFILT1L);
198	snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1R,
199			    DA7219_OUTFILT_ST_1R_SRC_MASK,
200			    DA7219_DMIX_ST_SRC_OUTFILT1R);
201	snd_soc_update_bits(codec, DA7219_MIXOUT_L_CTRL,
202			    DA7219_MIXOUT_L_AMP_EN_MASK,
203			    DA7219_MIXOUT_L_AMP_EN_MASK);
204	snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,
205			    DA7219_MIXOUT_R_AMP_EN_MASK,
206			    DA7219_MIXOUT_R_AMP_EN_MASK);
207	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
208			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
209			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
210	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
211			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
212			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
213	msleep(DA7219_SETTLING_DELAY);
214	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
215			    DA7219_HP_L_AMP_MUTE_EN_MASK |
216			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
217	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
218			    DA7219_HP_R_AMP_MUTE_EN_MASK |
219			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
220
221	/*
222	 * If we're running from the internal oscillator then give audio paths
223	 * time to settle before running test.
224	 */
225	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
226		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
227
228	/* Configure & start Tone Generator */
229	snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
230	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
231			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
232	snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2,
233			    DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
234			    DA7219_SWG_SEL_SRAMP |
235			    DA7219_TONE_GEN_GAIN_MINUS_15DB);
236	snd_soc_write(codec, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
237
238	msleep(DA7219_AAD_HPTEST_PERIOD);
239
240	/* Grab comparator reading */
241	accdet_cfg8 = snd_soc_read(codec, DA7219_ACCDET_CONFIG_8);
242	if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
243		report |= SND_JACK_HEADPHONE;
244	else
245		report |= SND_JACK_LINEOUT;
246
247	/* Stop tone generator */
248	snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
249
250	msleep(DA7219_AAD_HPTEST_PERIOD);
251
252	/* Restore original settings from cache */
253	regcache_mark_dirty(da7219->regmap);
254	regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
255			     DA7219_HP_R_CTRL);
256	msleep(DA7219_SETTLING_DELAY);
257	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
258			     DA7219_MIXOUT_R_CTRL);
259	regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
260			     DA7219_DROUTING_ST_OUTFILT_1R);
261	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,
262			     DA7219_MIXOUT_R_SELECT);
263	regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,
264			     DA7219_DAC_R_CTRL);
265	regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,
266			     DA7219_DIG_ROUTING_DAC);
267	regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);
268	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,
269			     DA7219_DAC_FILTERS5);
270	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,
271			     DA7219_DAC_FILTERS1);
272	regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,
273			     DA7219_HP_R_GAIN);
274	regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,
275			     DA7219_DAC_R_GAIN);
276	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,
277			     DA7219_TONE_GEN_ON_PER);
278	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
279			     DA7219_TONE_GEN_FREQ1_U);
280	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,
281			     DA7219_TONE_GEN_CFG2);
282
283	regcache_cache_bypass(da7219->regmap, false);
284
285	/* Disable HPTest block */
286	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
287			    DA7219_HPTEST_EN_MASK, 0);
288
289	/*
290	 * If we're running from the internal oscillator then give audio paths
291	 * time to settle before allowing headphones to be driven as required.
292	 */
293	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
294		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
295
296	/* Restore gain ramping rate */
297	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
298
299	/* Drive Headphones/lineout */
300	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
301			    DA7219_HP_L_AMP_OE_MASK);
302	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
303			    DA7219_HP_R_AMP_OE_MASK);
304
 
 
 
 
 
305	/* Remove MCLK, if previously enabled */
306	if (da7219->mclk)
307		clk_disable_unprepare(da7219->mclk);
308
309	mutex_unlock(&da7219->lock);
 
310	snd_soc_dapm_mutex_unlock(dapm);
311
312	/*
313	 * Only send report if jack hasn't been removed during process,
314	 * otherwise it's invalid and we drop it.
315	 */
316	if (da7219_aad->jack_inserted)
317		snd_soc_jack_report(da7219_aad->jack, report,
318				    SND_JACK_HEADSET | SND_JACK_LINEOUT);
319}
320
 
 
 
 
 
 
 
 
 
321
322/*
323 * IRQ
324 */
325
326static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
327{
328	struct da7219_aad_priv *da7219_aad = data;
329	struct snd_soc_codec *codec = da7219_aad->codec;
330	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
331	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
332	u8 events[DA7219_AAD_IRQ_REG_MAX];
333	u8 statusa;
334	int i, report = 0, mask = 0;
335
336	/* Read current IRQ events */
337	regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
338			 events, DA7219_AAD_IRQ_REG_MAX);
 
 
 
 
339
340	if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
341		return IRQ_NONE;
342
343	/* Read status register for jack insertion & type status */
344	statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
 
 
 
 
 
 
 
 
 
 
 
 
345
346	/* Clear events */
347	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
348			  events, DA7219_AAD_IRQ_REG_MAX);
349
350	dev_dbg(codec->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
351		events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
352		statusa);
353
354	if (statusa & DA7219_JACK_INSERTION_STS_MASK) {
355		/* Jack Insertion */
356		if (events[DA7219_AAD_IRQ_REG_A] &
357		    DA7219_E_JACK_INSERTED_MASK) {
358			report |= SND_JACK_MECHANICAL;
359			mask |= SND_JACK_MECHANICAL;
360			da7219_aad->jack_inserted = true;
361		}
362
363		/* Jack type detection */
364		if (events[DA7219_AAD_IRQ_REG_A] &
365		    DA7219_E_JACK_DETECT_COMPLETE_MASK) {
366			/*
367			 * If 4-pole, then enable button detection, else perform
368			 * HP impedance test to determine output type to report.
369			 *
370			 * We schedule work here as the tasks themselves can
371			 * take time to complete, and in particular for hptest
372			 * we want to be able to check if the jack was removed
373			 * during the procedure as this will invalidate the
374			 * result. By doing this as work, the IRQ thread can
375			 * handle a removal, and we can check at the end of
376			 * hptest if we have a valid result or not.
377			 */
 
 
 
 
 
378			if (statusa & DA7219_JACK_TYPE_STS_MASK) {
379				report |= SND_JACK_HEADSET;
380				mask |=	SND_JACK_HEADSET | SND_JACK_LINEOUT;
381				schedule_work(&da7219_aad->btn_det_work);
382			} else {
383				schedule_work(&da7219_aad->hptest_work);
384			}
385		}
386
387		/* Button support for 4-pole jack */
388		if (statusa & DA7219_JACK_TYPE_STS_MASK) {
389			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
390				/* Button Press */
391				if (events[DA7219_AAD_IRQ_REG_B] &
392				    (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {
393					report |= SND_JACK_BTN_0 >> i;
394					mask |= SND_JACK_BTN_0 >> i;
395				}
396			}
397			snd_soc_jack_report(da7219_aad->jack, report, mask);
398
399			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
400				/* Button Release */
401				if (events[DA7219_AAD_IRQ_REG_B] &
402				    (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {
403					report &= ~(SND_JACK_BTN_0 >> i);
404					mask |= SND_JACK_BTN_0 >> i;
405				}
406			}
407		}
408	} else {
409		/* Jack removal */
410		if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {
411			report = 0;
412			mask |= DA7219_AAD_REPORT_ALL_MASK;
413			da7219_aad->jack_inserted = false;
414
 
 
 
 
 
415			/* Un-drive headphones/lineout */
416			snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
417					    DA7219_HP_R_AMP_OE_MASK, 0);
418			snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
419					    DA7219_HP_L_AMP_OE_MASK, 0);
420
421			/* Ensure button detection disabled */
422			snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
423					    DA7219_BUTTON_CONFIG_MASK, 0);
424
 
 
425			/* Disable mic bias */
426			snd_soc_dapm_disable_pin(dapm, "Mic Bias");
427			snd_soc_dapm_sync(dapm);
428
429			/* Cancel any pending work */
430			cancel_work_sync(&da7219_aad->btn_det_work);
431			cancel_work_sync(&da7219_aad->hptest_work);
432		}
433	}
434
435	snd_soc_jack_report(da7219_aad->jack, report, mask);
436
437	return IRQ_HANDLED;
438}
439
440/*
441 * DT/ACPI to pdata conversion
442 */
443
444static enum da7219_aad_micbias_pulse_lvl
445	da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val)
446{
447	switch (val) {
448	case 2800:
449		return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;
450	case 2900:
451		return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
452	default:
453		dev_warn(codec->dev, "Invalid micbias pulse level");
454		return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
455	}
456}
457
458static enum da7219_aad_btn_cfg
459	da7219_aad_fw_btn_cfg(struct snd_soc_codec *codec, u32 val)
460{
461	switch (val) {
462	case 2:
463		return DA7219_AAD_BTN_CFG_2MS;
464	case 5:
465		return DA7219_AAD_BTN_CFG_5MS;
466	case 10:
467		return DA7219_AAD_BTN_CFG_10MS;
468	case 50:
469		return DA7219_AAD_BTN_CFG_50MS;
470	case 100:
471		return DA7219_AAD_BTN_CFG_100MS;
472	case 200:
473		return DA7219_AAD_BTN_CFG_200MS;
474	case 500:
475		return DA7219_AAD_BTN_CFG_500MS;
476	default:
477		dev_warn(codec->dev, "Invalid button config");
478		return DA7219_AAD_BTN_CFG_10MS;
479	}
480}
481
482static enum da7219_aad_mic_det_thr
483	da7219_aad_fw_mic_det_thr(struct snd_soc_codec *codec, u32 val)
484{
485	switch (val) {
486	case 200:
487		return DA7219_AAD_MIC_DET_THR_200_OHMS;
488	case 500:
489		return DA7219_AAD_MIC_DET_THR_500_OHMS;
490	case 750:
491		return DA7219_AAD_MIC_DET_THR_750_OHMS;
492	case 1000:
493		return DA7219_AAD_MIC_DET_THR_1000_OHMS;
494	default:
495		dev_warn(codec->dev, "Invalid mic detect threshold");
496		return DA7219_AAD_MIC_DET_THR_500_OHMS;
497	}
498}
499
500static enum da7219_aad_jack_ins_deb
501	da7219_aad_fw_jack_ins_deb(struct snd_soc_codec *codec, u32 val)
502{
503	switch (val) {
504	case 5:
505		return DA7219_AAD_JACK_INS_DEB_5MS;
506	case 10:
507		return DA7219_AAD_JACK_INS_DEB_10MS;
508	case 20:
509		return DA7219_AAD_JACK_INS_DEB_20MS;
510	case 50:
511		return DA7219_AAD_JACK_INS_DEB_50MS;
512	case 100:
513		return DA7219_AAD_JACK_INS_DEB_100MS;
514	case 200:
515		return DA7219_AAD_JACK_INS_DEB_200MS;
516	case 500:
517		return DA7219_AAD_JACK_INS_DEB_500MS;
518	case 1000:
519		return DA7219_AAD_JACK_INS_DEB_1S;
520	default:
521		dev_warn(codec->dev, "Invalid jack insert debounce");
522		return DA7219_AAD_JACK_INS_DEB_20MS;
523	}
524}
525
 
 
 
 
 
 
 
 
 
 
 
 
 
526static enum da7219_aad_jack_det_rate
527	da7219_aad_fw_jack_det_rate(struct snd_soc_codec *codec, const char *str)
528{
529	if (!strcmp(str, "32ms_64ms")) {
530		return DA7219_AAD_JACK_DET_RATE_32_64MS;
531	} else if (!strcmp(str, "64ms_128ms")) {
532		return DA7219_AAD_JACK_DET_RATE_64_128MS;
533	} else if (!strcmp(str, "128ms_256ms")) {
534		return DA7219_AAD_JACK_DET_RATE_128_256MS;
535	} else if (!strcmp(str, "256ms_512ms")) {
536		return DA7219_AAD_JACK_DET_RATE_256_512MS;
537	} else {
538		dev_warn(codec->dev, "Invalid jack detect rate");
539		return DA7219_AAD_JACK_DET_RATE_256_512MS;
540	}
541}
542
543static enum da7219_aad_jack_rem_deb
544	da7219_aad_fw_jack_rem_deb(struct snd_soc_codec *codec, u32 val)
545{
546	switch (val) {
547	case 1:
548		return DA7219_AAD_JACK_REM_DEB_1MS;
549	case 5:
550		return DA7219_AAD_JACK_REM_DEB_5MS;
551	case 10:
552		return DA7219_AAD_JACK_REM_DEB_10MS;
553	case 20:
554		return DA7219_AAD_JACK_REM_DEB_20MS;
555	default:
556		dev_warn(codec->dev, "Invalid jack removal debounce");
557		return DA7219_AAD_JACK_REM_DEB_1MS;
558	}
559}
560
561static enum da7219_aad_btn_avg
562	da7219_aad_fw_btn_avg(struct snd_soc_codec *codec, u32 val)
563{
564	switch (val) {
565	case 1:
566		return DA7219_AAD_BTN_AVG_1;
567	case 2:
568		return DA7219_AAD_BTN_AVG_2;
569	case 4:
570		return DA7219_AAD_BTN_AVG_4;
571	case 8:
572		return DA7219_AAD_BTN_AVG_8;
573	default:
574		dev_warn(codec->dev, "Invalid button average value");
575		return DA7219_AAD_BTN_AVG_2;
576	}
577}
578
579static enum da7219_aad_adc_1bit_rpt
580	da7219_aad_fw_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val)
581{
582	switch (val) {
583	case 1:
584		return DA7219_AAD_ADC_1BIT_RPT_1;
585	case 2:
586		return DA7219_AAD_ADC_1BIT_RPT_2;
587	case 4:
588		return DA7219_AAD_ADC_1BIT_RPT_4;
589	case 8:
590		return DA7219_AAD_ADC_1BIT_RPT_8;
591	default:
592		dev_warn(codec->dev, "Invalid ADC 1-bit repeat value");
593		return DA7219_AAD_ADC_1BIT_RPT_1;
594	}
595}
596
597static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *codec)
598{
599	struct device *dev = codec->dev;
600	struct i2c_client *i2c = to_i2c_client(dev);
601	struct fwnode_handle *aad_np;
602	struct da7219_aad_pdata *aad_pdata;
603	const char *fw_str;
604	u32 fw_val32;
605
606	aad_np = device_get_named_child_node(dev, "da7219_aad");
607	if (!aad_np)
608		return NULL;
609
610	aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL);
611	if (!aad_pdata)
 
612		return NULL;
 
613
614	aad_pdata->irq = i2c->irq;
615
616	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
617				     &fw_val32) >= 0)
618		aad_pdata->micbias_pulse_lvl =
619			da7219_aad_fw_micbias_pulse_lvl(codec, fw_val32);
620	else
621		aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
622
623	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time",
624				     &fw_val32) >= 0)
625		aad_pdata->micbias_pulse_time = fw_val32;
626
627	if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)
628		aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(codec, fw_val32);
629	else
630		aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
631
632	if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)
633		aad_pdata->mic_det_thr =
634			da7219_aad_fw_mic_det_thr(codec, fw_val32);
635	else
636		aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
637
638	if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
639		aad_pdata->jack_ins_deb =
640			da7219_aad_fw_jack_ins_deb(codec, fw_val32);
641	else
642		aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
643
 
 
 
 
 
 
644	if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
645		aad_pdata->jack_det_rate =
646			da7219_aad_fw_jack_det_rate(codec, fw_str);
647	else
648		aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
649
650	if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)
651		aad_pdata->jack_rem_deb =
652			da7219_aad_fw_jack_rem_deb(codec, fw_val32);
653	else
654		aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
655
656	if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0)
657		aad_pdata->a_d_btn_thr = (u8) fw_val32;
658	else
659		aad_pdata->a_d_btn_thr = 0xA;
660
661	if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0)
662		aad_pdata->d_b_btn_thr = (u8) fw_val32;
663	else
664		aad_pdata->d_b_btn_thr = 0x16;
665
666	if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0)
667		aad_pdata->b_c_btn_thr = (u8) fw_val32;
668	else
669		aad_pdata->b_c_btn_thr = 0x21;
670
671	if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0)
672		aad_pdata->c_mic_btn_thr = (u8) fw_val32;
673	else
674		aad_pdata->c_mic_btn_thr = 0x3E;
675
676	if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)
677		aad_pdata->btn_avg = da7219_aad_fw_btn_avg(codec, fw_val32);
678	else
679		aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
680
681	if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)
682		aad_pdata->adc_1bit_rpt =
683			da7219_aad_fw_adc_1bit_rpt(codec, fw_val32);
684	else
685		aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
686
 
 
687	return aad_pdata;
688}
689
690static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
691{
692	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
693	struct da7219_aad_priv *da7219_aad = da7219->aad;
694	struct da7219_pdata *pdata = da7219->pdata;
695
696	if ((pdata) && (pdata->aad_pdata)) {
697		struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;
698		u8 cfg, mask;
699
700		da7219_aad->irq = aad_pdata->irq;
701
702		switch (aad_pdata->micbias_pulse_lvl) {
703		case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:
704		case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:
705			da7219_aad->micbias_pulse_lvl =
706				(aad_pdata->micbias_pulse_lvl <<
707				 DA7219_MICBIAS1_LEVEL_SHIFT);
708			break;
709		default:
710			break;
711		}
712
713		da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;
714
715		switch (aad_pdata->btn_cfg) {
716		case DA7219_AAD_BTN_CFG_2MS:
717		case DA7219_AAD_BTN_CFG_5MS:
718		case DA7219_AAD_BTN_CFG_10MS:
719		case DA7219_AAD_BTN_CFG_50MS:
720		case DA7219_AAD_BTN_CFG_100MS:
721		case DA7219_AAD_BTN_CFG_200MS:
722		case DA7219_AAD_BTN_CFG_500MS:
723			da7219_aad->btn_cfg  = (aad_pdata->btn_cfg <<
724						DA7219_BUTTON_CONFIG_SHIFT);
725		}
726
727		cfg = 0;
728		mask = 0;
729		switch (aad_pdata->mic_det_thr) {
730		case DA7219_AAD_MIC_DET_THR_200_OHMS:
731		case DA7219_AAD_MIC_DET_THR_500_OHMS:
732		case DA7219_AAD_MIC_DET_THR_750_OHMS:
733		case DA7219_AAD_MIC_DET_THR_1000_OHMS:
734			cfg |= (aad_pdata->mic_det_thr <<
735				DA7219_MIC_DET_THRESH_SHIFT);
736			mask |= DA7219_MIC_DET_THRESH_MASK;
737		}
738		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, mask, cfg);
739
740		cfg = 0;
741		mask = 0;
742		switch (aad_pdata->jack_ins_deb) {
743		case DA7219_AAD_JACK_INS_DEB_5MS:
744		case DA7219_AAD_JACK_INS_DEB_10MS:
745		case DA7219_AAD_JACK_INS_DEB_20MS:
746		case DA7219_AAD_JACK_INS_DEB_50MS:
747		case DA7219_AAD_JACK_INS_DEB_100MS:
748		case DA7219_AAD_JACK_INS_DEB_200MS:
749		case DA7219_AAD_JACK_INS_DEB_500MS:
750		case DA7219_AAD_JACK_INS_DEB_1S:
751			cfg |= (aad_pdata->jack_ins_deb <<
752				DA7219_JACKDET_DEBOUNCE_SHIFT);
753			mask |= DA7219_JACKDET_DEBOUNCE_MASK;
754		}
755		switch (aad_pdata->jack_det_rate) {
756		case DA7219_AAD_JACK_DET_RATE_32_64MS:
757		case DA7219_AAD_JACK_DET_RATE_64_128MS:
758		case DA7219_AAD_JACK_DET_RATE_128_256MS:
759		case DA7219_AAD_JACK_DET_RATE_256_512MS:
760			cfg |= (aad_pdata->jack_det_rate <<
761				DA7219_JACK_DETECT_RATE_SHIFT);
762			mask |= DA7219_JACK_DETECT_RATE_MASK;
763		}
764		switch (aad_pdata->jack_rem_deb) {
765		case DA7219_AAD_JACK_REM_DEB_1MS:
766		case DA7219_AAD_JACK_REM_DEB_5MS:
767		case DA7219_AAD_JACK_REM_DEB_10MS:
768		case DA7219_AAD_JACK_REM_DEB_20MS:
769			cfg |= (aad_pdata->jack_rem_deb <<
770				DA7219_JACKDET_REM_DEB_SHIFT);
771			mask |= DA7219_JACKDET_REM_DEB_MASK;
772		}
773		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_2, mask, cfg);
774
775		snd_soc_write(codec, DA7219_ACCDET_CONFIG_3,
776			      aad_pdata->a_d_btn_thr);
777		snd_soc_write(codec, DA7219_ACCDET_CONFIG_4,
778			      aad_pdata->d_b_btn_thr);
779		snd_soc_write(codec, DA7219_ACCDET_CONFIG_5,
780			      aad_pdata->b_c_btn_thr);
781		snd_soc_write(codec, DA7219_ACCDET_CONFIG_6,
782			      aad_pdata->c_mic_btn_thr);
783
784		cfg = 0;
785		mask = 0;
786		switch (aad_pdata->btn_avg) {
787		case DA7219_AAD_BTN_AVG_1:
788		case DA7219_AAD_BTN_AVG_2:
789		case DA7219_AAD_BTN_AVG_4:
790		case DA7219_AAD_BTN_AVG_8:
791			cfg |= (aad_pdata->btn_avg <<
792				DA7219_BUTTON_AVERAGE_SHIFT);
793			mask |= DA7219_BUTTON_AVERAGE_MASK;
794		}
795		switch (aad_pdata->adc_1bit_rpt) {
796		case DA7219_AAD_ADC_1BIT_RPT_1:
797		case DA7219_AAD_ADC_1BIT_RPT_2:
798		case DA7219_AAD_ADC_1BIT_RPT_4:
799		case DA7219_AAD_ADC_1BIT_RPT_8:
800			cfg |= (aad_pdata->adc_1bit_rpt <<
801			       DA7219_ADC_1_BIT_REPEAT_SHIFT);
802			mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
803		}
804		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_7, mask, cfg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805	}
806}
807
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
808
809/*
810 * Suspend/Resume
811 */
812
813void da7219_aad_suspend(struct snd_soc_codec *codec)
814{
815	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
816	struct da7219_aad_priv *da7219_aad = da7219->aad;
817	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
818	u8 micbias_ctrl;
819
 
 
820	if (da7219_aad->jack) {
821		/* Disable jack detection during suspend */
822		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
823				    DA7219_ACCDET_EN_MASK, 0);
 
 
 
824
825		/*
826		 * If we have a 4-pole jack inserted, then micbias will be
827		 * enabled. We can disable micbias here, and keep a note to
828		 * re-enable it on resume. If jack removal occurred during
829		 * suspend then this will be dealt with through the IRQ handler.
830		 */
831		if (da7219_aad->jack_inserted) {
832			micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
833			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
834				snd_soc_dapm_disable_pin(dapm, "Mic Bias");
835				snd_soc_dapm_sync(dapm);
836				da7219_aad->micbias_resume_enable = true;
837			}
838		}
839	}
840}
841
842void da7219_aad_resume(struct snd_soc_codec *codec)
843{
844	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
845	struct da7219_aad_priv *da7219_aad = da7219->aad;
846	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
847
848	if (da7219_aad->jack) {
849		/* Re-enable micbias if previously enabled for 4-pole jack */
850		if (da7219_aad->jack_inserted &&
851		    da7219_aad->micbias_resume_enable) {
852			snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
853			snd_soc_dapm_sync(dapm);
854			da7219_aad->micbias_resume_enable = false;
855		}
856
857		/* Re-enable jack detection */
858		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
859				    DA7219_ACCDET_EN_MASK,
860				    DA7219_ACCDET_EN_MASK);
861	}
 
 
862}
863
864
865/*
866 * Init/Exit
867 */
868
869int da7219_aad_init(struct snd_soc_codec *codec)
870{
871	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
872	struct da7219_aad_priv *da7219_aad;
873	u8 mask[DA7219_AAD_IRQ_REG_MAX];
874	int ret;
875
876	da7219_aad = devm_kzalloc(codec->dev, sizeof(*da7219_aad), GFP_KERNEL);
877	if (!da7219_aad)
878		return -ENOMEM;
879
880	da7219->aad = da7219_aad;
881	da7219_aad->codec = codec;
882
883	/* Handle any DT/ACPI/platform data */
884	if (da7219->pdata && !da7219->pdata->aad_pdata)
885		da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(codec);
886
887	da7219_aad_handle_pdata(codec);
888
889	/* Disable button detection */
890	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
891			    DA7219_BUTTON_CONFIG_MASK, 0);
892
 
 
 
 
 
 
 
 
 
893	INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
894	INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
895
896	ret = request_threaded_irq(da7219_aad->irq, NULL,
897				   da7219_aad_irq_thread,
898				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
899				   "da7219-aad", da7219_aad);
900	if (ret) {
901		dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
902		return ret;
903	}
904
905	/* Unmask AAD IRQs */
906	memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);
907	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
908			  &mask, DA7219_AAD_IRQ_REG_MAX);
909
910	return 0;
911}
912EXPORT_SYMBOL_GPL(da7219_aad_init);
913
914void da7219_aad_exit(struct snd_soc_codec *codec)
915{
916	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
917	struct da7219_aad_priv *da7219_aad = da7219->aad;
918	u8 mask[DA7219_AAD_IRQ_REG_MAX];
919
920	/* Mask off AAD IRQs */
921	memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);
922	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
923			  mask, DA7219_AAD_IRQ_REG_MAX);
924
925	free_irq(da7219_aad->irq, da7219_aad);
926
 
927	cancel_work_sync(&da7219_aad->btn_det_work);
928	cancel_work_sync(&da7219_aad->hptest_work);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
929}
930EXPORT_SYMBOL_GPL(da7219_aad_exit);
931
932MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
933MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
 
934MODULE_LICENSE("GPL");