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 35 void 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 } 50 EXPORT_SYMBOL_GPL(da7219_aad_jack_det); 51 52 /* 53 * Button/HPTest work 54 */ 55 56 static 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 109 static 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 326 static 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 444 static 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 458 static 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 482 static 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 500 static 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 526 static 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 543 static 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 561 static 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 579 static 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 597 static 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 690 static 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 813 void 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 842 void 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 869 int 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 } 912 EXPORT_SYMBOL_GPL(da7219_aad_init); 913 914 void 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 } 930 EXPORT_SYMBOL_GPL(da7219_aad_exit); 931 932 MODULE_DESCRIPTION("ASoC DA7219 AAD Driver"); 933 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 934 MODULE_LICENSE("GPL"); 935