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/of_device.h> 17 #include <linux/of_irq.h> 18 #include <linux/pm_wakeirq.h> 19 #include <linux/slab.h> 20 #include <linux/delay.h> 21 #include <linux/workqueue.h> 22 #include <sound/soc.h> 23 #include <sound/jack.h> 24 #include <sound/da7219.h> 25 26 #include "da7219.h" 27 #include "da7219-aad.h" 28 29 30 /* 31 * Detection control 32 */ 33 34 void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack) 35 { 36 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 37 38 da7219->aad->jack = jack; 39 da7219->aad->jack_inserted = false; 40 41 /* Send an initial empty report */ 42 snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK); 43 44 /* Enable/Disable jack detection */ 45 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, 46 DA7219_ACCDET_EN_MASK, 47 (jack ? DA7219_ACCDET_EN_MASK : 0)); 48 } 49 EXPORT_SYMBOL_GPL(da7219_aad_jack_det); 50 51 /* 52 * Button/HPTest work 53 */ 54 55 static void da7219_aad_btn_det_work(struct work_struct *work) 56 { 57 struct da7219_aad_priv *da7219_aad = 58 container_of(work, struct da7219_aad_priv, btn_det_work); 59 struct snd_soc_codec *codec = da7219_aad->codec; 60 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); 61 u8 statusa, micbias_ctrl; 62 bool micbias_up = false; 63 int retries = 0; 64 65 /* Drive headphones/lineout */ 66 snd_soc_update_bits(codec, DA7219_HP_L_CTRL, 67 DA7219_HP_L_AMP_OE_MASK, 68 DA7219_HP_L_AMP_OE_MASK); 69 snd_soc_update_bits(codec, DA7219_HP_R_CTRL, 70 DA7219_HP_R_AMP_OE_MASK, 71 DA7219_HP_R_AMP_OE_MASK); 72 73 /* Make sure mic bias is up */ 74 snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); 75 snd_soc_dapm_sync(dapm); 76 77 do { 78 statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A); 79 if (statusa & DA7219_MICBIAS_UP_STS_MASK) 80 micbias_up = true; 81 else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES) 82 msleep(DA7219_AAD_MICBIAS_CHK_DELAY); 83 } while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES)); 84 85 if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES) 86 dev_warn(codec->dev, "Mic bias status check timed out"); 87 88 /* 89 * Mic bias pulse required to enable mic, must be done before enabling 90 * button detection to prevent erroneous button readings. 91 */ 92 if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) { 93 /* Pulse higher level voltage */ 94 micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL); 95 snd_soc_update_bits(codec, DA7219_MICBIAS_CTRL, 96 DA7219_MICBIAS1_LEVEL_MASK, 97 da7219_aad->micbias_pulse_lvl); 98 msleep(da7219_aad->micbias_pulse_time); 99 snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_ctrl); 100 101 } 102 103 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, 104 DA7219_BUTTON_CONFIG_MASK, 105 da7219_aad->btn_cfg); 106 } 107 108 static void da7219_aad_hptest_work(struct work_struct *work) 109 { 110 struct da7219_aad_priv *da7219_aad = 111 container_of(work, struct da7219_aad_priv, hptest_work); 112 struct snd_soc_codec *codec = da7219_aad->codec; 113 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); 114 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 115 116 u16 tonegen_freq_hptest; 117 u8 accdet_cfg8; 118 int report = 0; 119 120 /* Lock DAPM and any Kcontrols that are affected by this test */ 121 snd_soc_dapm_mutex_lock(dapm); 122 mutex_lock(&da7219->lock); 123 124 /* Bypass cache so it saves current settings */ 125 regcache_cache_bypass(da7219->regmap, true); 126 127 /* Make sure Tone Generator is disabled */ 128 snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0); 129 130 /* Enable HPTest block, 1KOhms check */ 131 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8, 132 DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK, 133 DA7219_HPTEST_EN_MASK | 134 DA7219_HPTEST_RES_SEL_1KOHMS); 135 136 /* Set gains to 0db */ 137 snd_soc_write(codec, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB); 138 snd_soc_write(codec, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB); 139 snd_soc_write(codec, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB); 140 snd_soc_write(codec, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB); 141 142 /* Disable DAC filters, EQs and soft mute */ 143 snd_soc_update_bits(codec, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK, 144 0); 145 snd_soc_update_bits(codec, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK, 146 0); 147 snd_soc_update_bits(codec, DA7219_DAC_FILTERS5, 148 DA7219_DAC_SOFTMUTE_EN_MASK, 0); 149 150 /* Enable HP left & right paths */ 151 snd_soc_update_bits(codec, DA7219_CP_CTRL, DA7219_CP_EN_MASK, 152 DA7219_CP_EN_MASK); 153 snd_soc_update_bits(codec, DA7219_DIG_ROUTING_DAC, 154 DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK, 155 DA7219_DAC_L_SRC_TONEGEN | 156 DA7219_DAC_R_SRC_TONEGEN); 157 snd_soc_update_bits(codec, DA7219_DAC_L_CTRL, 158 DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK, 159 DA7219_DAC_L_EN_MASK); 160 snd_soc_update_bits(codec, DA7219_DAC_R_CTRL, 161 DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK, 162 DA7219_DAC_R_EN_MASK); 163 snd_soc_update_bits(codec, DA7219_MIXOUT_L_SELECT, 164 DA7219_MIXOUT_L_MIX_SELECT_MASK, 165 DA7219_MIXOUT_L_MIX_SELECT_MASK); 166 snd_soc_update_bits(codec, DA7219_MIXOUT_R_SELECT, 167 DA7219_MIXOUT_R_MIX_SELECT_MASK, 168 DA7219_MIXOUT_R_MIX_SELECT_MASK); 169 snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1L, 170 DA7219_OUTFILT_ST_1L_SRC_MASK, 171 DA7219_DMIX_ST_SRC_OUTFILT1L); 172 snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1R, 173 DA7219_OUTFILT_ST_1R_SRC_MASK, 174 DA7219_DMIX_ST_SRC_OUTFILT1R); 175 snd_soc_update_bits(codec, DA7219_MIXOUT_L_CTRL, 176 DA7219_MIXOUT_L_AMP_EN_MASK, 177 DA7219_MIXOUT_L_AMP_EN_MASK); 178 snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL, 179 DA7219_MIXOUT_R_AMP_EN_MASK, 180 DA7219_MIXOUT_R_AMP_EN_MASK); 181 snd_soc_write(codec, DA7219_HP_L_CTRL, 182 DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); 183 snd_soc_write(codec, DA7219_HP_R_CTRL, 184 DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); 185 186 /* Configure & start Tone Generator */ 187 snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK); 188 tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); 189 regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L, 190 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest)); 191 snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2, 192 DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK, 193 DA7219_SWG_SEL_SRAMP | 194 DA7219_TONE_GEN_GAIN_MINUS_15DB); 195 snd_soc_write(codec, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK); 196 197 msleep(DA7219_AAD_HPTEST_PERIOD); 198 199 /* Grab comparator reading */ 200 accdet_cfg8 = snd_soc_read(codec, DA7219_ACCDET_CONFIG_8); 201 if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK) 202 report |= SND_JACK_HEADPHONE; 203 else 204 report |= SND_JACK_LINEOUT; 205 206 /* Stop tone generator */ 207 snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0); 208 209 msleep(DA7219_AAD_HPTEST_PERIOD); 210 211 /* Restore original settings from cache */ 212 regcache_mark_dirty(da7219->regmap); 213 regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL, 214 DA7219_HP_R_CTRL); 215 regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL, 216 DA7219_MIXOUT_R_CTRL); 217 regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L, 218 DA7219_DROUTING_ST_OUTFILT_1R); 219 regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT, 220 DA7219_MIXOUT_R_SELECT); 221 regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL, 222 DA7219_DAC_R_CTRL); 223 regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC, 224 DA7219_DIG_ROUTING_DAC); 225 regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL); 226 regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5, 227 DA7219_DAC_FILTERS5); 228 regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4, 229 DA7219_DAC_FILTERS1); 230 regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN, 231 DA7219_HP_R_GAIN); 232 regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN, 233 DA7219_DAC_R_GAIN); 234 regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER, 235 DA7219_TONE_GEN_ON_PER); 236 regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L, 237 DA7219_TONE_GEN_FREQ1_U); 238 regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1, 239 DA7219_TONE_GEN_CFG2); 240 241 regcache_cache_bypass(da7219->regmap, false); 242 243 /* Disable HPTest block */ 244 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8, 245 DA7219_HPTEST_EN_MASK, 0); 246 247 /* Drive Headphones/lineout */ 248 snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK, 249 DA7219_HP_L_AMP_OE_MASK); 250 snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, 251 DA7219_HP_R_AMP_OE_MASK); 252 253 mutex_unlock(&da7219->lock); 254 snd_soc_dapm_mutex_unlock(dapm); 255 256 /* 257 * Only send report if jack hasn't been removed during process, 258 * otherwise it's invalid and we drop it. 259 */ 260 if (da7219_aad->jack_inserted) 261 snd_soc_jack_report(da7219_aad->jack, report, 262 SND_JACK_HEADSET | SND_JACK_LINEOUT); 263 } 264 265 266 /* 267 * IRQ 268 */ 269 270 static irqreturn_t da7219_aad_irq_thread(int irq, void *data) 271 { 272 struct da7219_aad_priv *da7219_aad = data; 273 struct snd_soc_codec *codec = da7219_aad->codec; 274 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); 275 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 276 u8 events[DA7219_AAD_IRQ_REG_MAX]; 277 u8 statusa; 278 int i, report = 0, mask = 0; 279 280 /* Read current IRQ events */ 281 regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, 282 events, DA7219_AAD_IRQ_REG_MAX); 283 284 if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B]) 285 return IRQ_NONE; 286 287 /* Read status register for jack insertion & type status */ 288 statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A); 289 290 /* Clear events */ 291 regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A, 292 events, DA7219_AAD_IRQ_REG_MAX); 293 294 dev_dbg(codec->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n", 295 events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B], 296 statusa); 297 298 if (statusa & DA7219_JACK_INSERTION_STS_MASK) { 299 /* Jack Insertion */ 300 if (events[DA7219_AAD_IRQ_REG_A] & 301 DA7219_E_JACK_INSERTED_MASK) { 302 report |= SND_JACK_MECHANICAL; 303 mask |= SND_JACK_MECHANICAL; 304 da7219_aad->jack_inserted = true; 305 } 306 307 /* Jack type detection */ 308 if (events[DA7219_AAD_IRQ_REG_A] & 309 DA7219_E_JACK_DETECT_COMPLETE_MASK) { 310 /* 311 * If 4-pole, then enable button detection, else perform 312 * HP impedance test to determine output type to report. 313 * 314 * We schedule work here as the tasks themselves can 315 * take time to complete, and in particular for hptest 316 * we want to be able to check if the jack was removed 317 * during the procedure as this will invalidate the 318 * result. By doing this as work, the IRQ thread can 319 * handle a removal, and we can check at the end of 320 * hptest if we have a valid result or not. 321 */ 322 if (statusa & DA7219_JACK_TYPE_STS_MASK) { 323 report |= SND_JACK_HEADSET; 324 mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT; 325 schedule_work(&da7219_aad->btn_det_work); 326 } else { 327 schedule_work(&da7219_aad->hptest_work); 328 } 329 } 330 331 /* Button support for 4-pole jack */ 332 if (statusa & DA7219_JACK_TYPE_STS_MASK) { 333 for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) { 334 /* Button Press */ 335 if (events[DA7219_AAD_IRQ_REG_B] & 336 (DA7219_E_BUTTON_A_PRESSED_MASK << i)) { 337 report |= SND_JACK_BTN_0 >> i; 338 mask |= SND_JACK_BTN_0 >> i; 339 } 340 } 341 snd_soc_jack_report(da7219_aad->jack, report, mask); 342 343 for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) { 344 /* Button Release */ 345 if (events[DA7219_AAD_IRQ_REG_B] & 346 (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) { 347 report &= ~(SND_JACK_BTN_0 >> i); 348 mask |= SND_JACK_BTN_0 >> i; 349 } 350 } 351 } 352 } else { 353 /* Jack removal */ 354 if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) { 355 report = 0; 356 mask |= DA7219_AAD_REPORT_ALL_MASK; 357 da7219_aad->jack_inserted = false; 358 359 /* Un-drive headphones/lineout */ 360 snd_soc_update_bits(codec, DA7219_HP_R_CTRL, 361 DA7219_HP_R_AMP_OE_MASK, 0); 362 snd_soc_update_bits(codec, DA7219_HP_L_CTRL, 363 DA7219_HP_L_AMP_OE_MASK, 0); 364 365 /* Ensure button detection disabled */ 366 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, 367 DA7219_BUTTON_CONFIG_MASK, 0); 368 369 /* Disable mic bias */ 370 snd_soc_dapm_disable_pin(dapm, "Mic Bias"); 371 snd_soc_dapm_sync(dapm); 372 373 /* Cancel any pending work */ 374 cancel_work_sync(&da7219_aad->btn_det_work); 375 cancel_work_sync(&da7219_aad->hptest_work); 376 } 377 } 378 379 snd_soc_jack_report(da7219_aad->jack, report, mask); 380 381 return IRQ_HANDLED; 382 } 383 384 /* 385 * DT to pdata conversion 386 */ 387 388 static enum da7219_aad_micbias_pulse_lvl 389 da7219_aad_of_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val) 390 { 391 switch (val) { 392 case 2800: 393 return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V; 394 case 2900: 395 return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V; 396 default: 397 dev_warn(codec->dev, "Invalid micbias pulse level"); 398 return DA7219_AAD_MICBIAS_PULSE_LVL_OFF; 399 } 400 } 401 402 static enum da7219_aad_btn_cfg 403 da7219_aad_of_btn_cfg(struct snd_soc_codec *codec, u32 val) 404 { 405 switch (val) { 406 case 2: 407 return DA7219_AAD_BTN_CFG_2MS; 408 case 5: 409 return DA7219_AAD_BTN_CFG_5MS; 410 case 10: 411 return DA7219_AAD_BTN_CFG_10MS; 412 case 50: 413 return DA7219_AAD_BTN_CFG_50MS; 414 case 100: 415 return DA7219_AAD_BTN_CFG_100MS; 416 case 200: 417 return DA7219_AAD_BTN_CFG_200MS; 418 case 500: 419 return DA7219_AAD_BTN_CFG_500MS; 420 default: 421 dev_warn(codec->dev, "Invalid button config"); 422 return DA7219_AAD_BTN_CFG_10MS; 423 } 424 } 425 426 static enum da7219_aad_mic_det_thr 427 da7219_aad_of_mic_det_thr(struct snd_soc_codec *codec, u32 val) 428 { 429 switch (val) { 430 case 200: 431 return DA7219_AAD_MIC_DET_THR_200_OHMS; 432 case 500: 433 return DA7219_AAD_MIC_DET_THR_500_OHMS; 434 case 750: 435 return DA7219_AAD_MIC_DET_THR_750_OHMS; 436 case 1000: 437 return DA7219_AAD_MIC_DET_THR_1000_OHMS; 438 default: 439 dev_warn(codec->dev, "Invalid mic detect threshold"); 440 return DA7219_AAD_MIC_DET_THR_500_OHMS; 441 } 442 } 443 444 static enum da7219_aad_jack_ins_deb 445 da7219_aad_of_jack_ins_deb(struct snd_soc_codec *codec, u32 val) 446 { 447 switch (val) { 448 case 5: 449 return DA7219_AAD_JACK_INS_DEB_5MS; 450 case 10: 451 return DA7219_AAD_JACK_INS_DEB_10MS; 452 case 20: 453 return DA7219_AAD_JACK_INS_DEB_20MS; 454 case 50: 455 return DA7219_AAD_JACK_INS_DEB_50MS; 456 case 100: 457 return DA7219_AAD_JACK_INS_DEB_100MS; 458 case 200: 459 return DA7219_AAD_JACK_INS_DEB_200MS; 460 case 500: 461 return DA7219_AAD_JACK_INS_DEB_500MS; 462 case 1000: 463 return DA7219_AAD_JACK_INS_DEB_1S; 464 default: 465 dev_warn(codec->dev, "Invalid jack insert debounce"); 466 return DA7219_AAD_JACK_INS_DEB_20MS; 467 } 468 } 469 470 static enum da7219_aad_jack_det_rate 471 da7219_aad_of_jack_det_rate(struct snd_soc_codec *codec, const char *str) 472 { 473 if (!strcmp(str, "32ms_64ms")) { 474 return DA7219_AAD_JACK_DET_RATE_32_64MS; 475 } else if (!strcmp(str, "64ms_128ms")) { 476 return DA7219_AAD_JACK_DET_RATE_64_128MS; 477 } else if (!strcmp(str, "128ms_256ms")) { 478 return DA7219_AAD_JACK_DET_RATE_128_256MS; 479 } else if (!strcmp(str, "256ms_512ms")) { 480 return DA7219_AAD_JACK_DET_RATE_256_512MS; 481 } else { 482 dev_warn(codec->dev, "Invalid jack detect rate"); 483 return DA7219_AAD_JACK_DET_RATE_256_512MS; 484 } 485 } 486 487 static enum da7219_aad_jack_rem_deb 488 da7219_aad_of_jack_rem_deb(struct snd_soc_codec *codec, u32 val) 489 { 490 switch (val) { 491 case 1: 492 return DA7219_AAD_JACK_REM_DEB_1MS; 493 case 5: 494 return DA7219_AAD_JACK_REM_DEB_5MS; 495 case 10: 496 return DA7219_AAD_JACK_REM_DEB_10MS; 497 case 20: 498 return DA7219_AAD_JACK_REM_DEB_20MS; 499 default: 500 dev_warn(codec->dev, "Invalid jack removal debounce"); 501 return DA7219_AAD_JACK_REM_DEB_1MS; 502 } 503 } 504 505 static enum da7219_aad_btn_avg 506 da7219_aad_of_btn_avg(struct snd_soc_codec *codec, u32 val) 507 { 508 switch (val) { 509 case 1: 510 return DA7219_AAD_BTN_AVG_1; 511 case 2: 512 return DA7219_AAD_BTN_AVG_2; 513 case 4: 514 return DA7219_AAD_BTN_AVG_4; 515 case 8: 516 return DA7219_AAD_BTN_AVG_8; 517 default: 518 dev_warn(codec->dev, "Invalid button average value"); 519 return DA7219_AAD_BTN_AVG_2; 520 } 521 } 522 523 static enum da7219_aad_adc_1bit_rpt 524 da7219_aad_of_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val) 525 { 526 switch (val) { 527 case 1: 528 return DA7219_AAD_ADC_1BIT_RPT_1; 529 case 2: 530 return DA7219_AAD_ADC_1BIT_RPT_2; 531 case 4: 532 return DA7219_AAD_ADC_1BIT_RPT_4; 533 case 8: 534 return DA7219_AAD_ADC_1BIT_RPT_8; 535 default: 536 dev_warn(codec->dev, "Invalid ADC 1-bit repeat value"); 537 return DA7219_AAD_ADC_1BIT_RPT_1; 538 } 539 } 540 541 static struct da7219_aad_pdata *da7219_aad_of_to_pdata(struct snd_soc_codec *codec) 542 { 543 struct device_node *np = codec->dev->of_node; 544 struct device_node *aad_np = of_find_node_by_name(np, "da7219_aad"); 545 struct da7219_aad_pdata *aad_pdata; 546 const char *of_str; 547 u32 of_val32; 548 549 if (!aad_np) 550 return NULL; 551 552 aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL); 553 if (!aad_pdata) 554 goto out; 555 556 aad_pdata->irq = irq_of_parse_and_map(np, 0); 557 558 if (of_property_read_u32(aad_np, "dlg,micbias-pulse-lvl", 559 &of_val32) >= 0) 560 aad_pdata->micbias_pulse_lvl = 561 da7219_aad_of_micbias_pulse_lvl(codec, of_val32); 562 else 563 aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF; 564 565 if (of_property_read_u32(aad_np, "dlg,micbias-pulse-time", 566 &of_val32) >= 0) 567 aad_pdata->micbias_pulse_time = of_val32; 568 569 if (of_property_read_u32(aad_np, "dlg,btn-cfg", &of_val32) >= 0) 570 aad_pdata->btn_cfg = da7219_aad_of_btn_cfg(codec, of_val32); 571 else 572 aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS; 573 574 if (of_property_read_u32(aad_np, "dlg,mic-det-thr", &of_val32) >= 0) 575 aad_pdata->mic_det_thr = 576 da7219_aad_of_mic_det_thr(codec, of_val32); 577 else 578 aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS; 579 580 if (of_property_read_u32(aad_np, "dlg,jack-ins-deb", &of_val32) >= 0) 581 aad_pdata->jack_ins_deb = 582 da7219_aad_of_jack_ins_deb(codec, of_val32); 583 else 584 aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; 585 586 if (!of_property_read_string(aad_np, "dlg,jack-det-rate", &of_str)) 587 aad_pdata->jack_det_rate = 588 da7219_aad_of_jack_det_rate(codec, of_str); 589 else 590 aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS; 591 592 if (of_property_read_u32(aad_np, "dlg,jack-rem-deb", &of_val32) >= 0) 593 aad_pdata->jack_rem_deb = 594 da7219_aad_of_jack_rem_deb(codec, of_val32); 595 else 596 aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS; 597 598 if (of_property_read_u32(aad_np, "dlg,a-d-btn-thr", &of_val32) >= 0) 599 aad_pdata->a_d_btn_thr = (u8) of_val32; 600 else 601 aad_pdata->a_d_btn_thr = 0xA; 602 603 if (of_property_read_u32(aad_np, "dlg,d-b-btn-thr", &of_val32) >= 0) 604 aad_pdata->d_b_btn_thr = (u8) of_val32; 605 else 606 aad_pdata->d_b_btn_thr = 0x16; 607 608 if (of_property_read_u32(aad_np, "dlg,b-c-btn-thr", &of_val32) >= 0) 609 aad_pdata->b_c_btn_thr = (u8) of_val32; 610 else 611 aad_pdata->b_c_btn_thr = 0x21; 612 613 if (of_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &of_val32) >= 0) 614 aad_pdata->c_mic_btn_thr = (u8) of_val32; 615 else 616 aad_pdata->c_mic_btn_thr = 0x3E; 617 618 if (of_property_read_u32(aad_np, "dlg,btn-avg", &of_val32) >= 0) 619 aad_pdata->btn_avg = da7219_aad_of_btn_avg(codec, of_val32); 620 else 621 aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2; 622 623 if (of_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &of_val32) >= 0) 624 aad_pdata->adc_1bit_rpt = 625 da7219_aad_of_adc_1bit_rpt(codec, of_val32); 626 else 627 aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; 628 629 out: 630 of_node_put(aad_np); 631 632 return aad_pdata; 633 } 634 635 static void da7219_aad_handle_pdata(struct snd_soc_codec *codec) 636 { 637 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 638 struct da7219_aad_priv *da7219_aad = da7219->aad; 639 struct da7219_pdata *pdata = da7219->pdata; 640 641 if ((pdata) && (pdata->aad_pdata)) { 642 struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata; 643 u8 cfg, mask; 644 645 da7219_aad->irq = aad_pdata->irq; 646 647 switch (aad_pdata->micbias_pulse_lvl) { 648 case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V: 649 case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V: 650 da7219_aad->micbias_pulse_lvl = 651 (aad_pdata->micbias_pulse_lvl << 652 DA7219_MICBIAS1_LEVEL_SHIFT); 653 break; 654 default: 655 break; 656 } 657 658 da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time; 659 660 switch (aad_pdata->btn_cfg) { 661 case DA7219_AAD_BTN_CFG_2MS: 662 case DA7219_AAD_BTN_CFG_5MS: 663 case DA7219_AAD_BTN_CFG_10MS: 664 case DA7219_AAD_BTN_CFG_50MS: 665 case DA7219_AAD_BTN_CFG_100MS: 666 case DA7219_AAD_BTN_CFG_200MS: 667 case DA7219_AAD_BTN_CFG_500MS: 668 da7219_aad->btn_cfg = (aad_pdata->btn_cfg << 669 DA7219_BUTTON_CONFIG_SHIFT); 670 } 671 672 cfg = 0; 673 mask = 0; 674 switch (aad_pdata->mic_det_thr) { 675 case DA7219_AAD_MIC_DET_THR_200_OHMS: 676 case DA7219_AAD_MIC_DET_THR_500_OHMS: 677 case DA7219_AAD_MIC_DET_THR_750_OHMS: 678 case DA7219_AAD_MIC_DET_THR_1000_OHMS: 679 cfg |= (aad_pdata->mic_det_thr << 680 DA7219_MIC_DET_THRESH_SHIFT); 681 mask |= DA7219_MIC_DET_THRESH_MASK; 682 } 683 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, mask, cfg); 684 685 cfg = 0; 686 mask = 0; 687 switch (aad_pdata->jack_ins_deb) { 688 case DA7219_AAD_JACK_INS_DEB_5MS: 689 case DA7219_AAD_JACK_INS_DEB_10MS: 690 case DA7219_AAD_JACK_INS_DEB_20MS: 691 case DA7219_AAD_JACK_INS_DEB_50MS: 692 case DA7219_AAD_JACK_INS_DEB_100MS: 693 case DA7219_AAD_JACK_INS_DEB_200MS: 694 case DA7219_AAD_JACK_INS_DEB_500MS: 695 case DA7219_AAD_JACK_INS_DEB_1S: 696 cfg |= (aad_pdata->jack_ins_deb << 697 DA7219_JACKDET_DEBOUNCE_SHIFT); 698 mask |= DA7219_JACKDET_DEBOUNCE_MASK; 699 } 700 switch (aad_pdata->jack_det_rate) { 701 case DA7219_AAD_JACK_DET_RATE_32_64MS: 702 case DA7219_AAD_JACK_DET_RATE_64_128MS: 703 case DA7219_AAD_JACK_DET_RATE_128_256MS: 704 case DA7219_AAD_JACK_DET_RATE_256_512MS: 705 cfg |= (aad_pdata->jack_det_rate << 706 DA7219_JACK_DETECT_RATE_SHIFT); 707 mask |= DA7219_JACK_DETECT_RATE_MASK; 708 } 709 switch (aad_pdata->jack_rem_deb) { 710 case DA7219_AAD_JACK_REM_DEB_1MS: 711 case DA7219_AAD_JACK_REM_DEB_5MS: 712 case DA7219_AAD_JACK_REM_DEB_10MS: 713 case DA7219_AAD_JACK_REM_DEB_20MS: 714 cfg |= (aad_pdata->jack_rem_deb << 715 DA7219_JACKDET_REM_DEB_SHIFT); 716 mask |= DA7219_JACKDET_REM_DEB_MASK; 717 } 718 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_2, mask, cfg); 719 720 snd_soc_write(codec, DA7219_ACCDET_CONFIG_3, 721 aad_pdata->a_d_btn_thr); 722 snd_soc_write(codec, DA7219_ACCDET_CONFIG_4, 723 aad_pdata->d_b_btn_thr); 724 snd_soc_write(codec, DA7219_ACCDET_CONFIG_5, 725 aad_pdata->b_c_btn_thr); 726 snd_soc_write(codec, DA7219_ACCDET_CONFIG_6, 727 aad_pdata->c_mic_btn_thr); 728 729 cfg = 0; 730 mask = 0; 731 switch (aad_pdata->btn_avg) { 732 case DA7219_AAD_BTN_AVG_1: 733 case DA7219_AAD_BTN_AVG_2: 734 case DA7219_AAD_BTN_AVG_4: 735 case DA7219_AAD_BTN_AVG_8: 736 cfg |= (aad_pdata->btn_avg << 737 DA7219_BUTTON_AVERAGE_SHIFT); 738 mask |= DA7219_BUTTON_AVERAGE_MASK; 739 } 740 switch (aad_pdata->adc_1bit_rpt) { 741 case DA7219_AAD_ADC_1BIT_RPT_1: 742 case DA7219_AAD_ADC_1BIT_RPT_2: 743 case DA7219_AAD_ADC_1BIT_RPT_4: 744 case DA7219_AAD_ADC_1BIT_RPT_8: 745 cfg |= (aad_pdata->adc_1bit_rpt << 746 DA7219_ADC_1_BIT_REPEAT_SHIFT); 747 mask |= DA7219_ADC_1_BIT_REPEAT_MASK; 748 } 749 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_7, mask, cfg); 750 } 751 } 752 753 754 /* 755 * Init/Exit 756 */ 757 758 int da7219_aad_init(struct snd_soc_codec *codec) 759 { 760 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 761 struct da7219_aad_priv *da7219_aad; 762 u8 mask[DA7219_AAD_IRQ_REG_MAX]; 763 int ret; 764 765 da7219_aad = devm_kzalloc(codec->dev, sizeof(*da7219_aad), GFP_KERNEL); 766 if (!da7219_aad) 767 return -ENOMEM; 768 769 da7219->aad = da7219_aad; 770 da7219_aad->codec = codec; 771 772 /* Handle any DT/platform data */ 773 if ((codec->dev->of_node) && (da7219->pdata)) 774 da7219->pdata->aad_pdata = da7219_aad_of_to_pdata(codec); 775 776 da7219_aad_handle_pdata(codec); 777 778 /* Disable button detection */ 779 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, 780 DA7219_BUTTON_CONFIG_MASK, 0); 781 782 INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work); 783 INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); 784 785 ret = request_threaded_irq(da7219_aad->irq, NULL, 786 da7219_aad_irq_thread, 787 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 788 "da7219-aad", da7219_aad); 789 if (ret) { 790 dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); 791 return ret; 792 } 793 794 /* Unmask AAD IRQs */ 795 memset(mask, 0, DA7219_AAD_IRQ_REG_MAX); 796 regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, 797 &mask, DA7219_AAD_IRQ_REG_MAX); 798 799 return 0; 800 } 801 EXPORT_SYMBOL_GPL(da7219_aad_init); 802 803 void da7219_aad_exit(struct snd_soc_codec *codec) 804 { 805 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 806 struct da7219_aad_priv *da7219_aad = da7219->aad; 807 u8 mask[DA7219_AAD_IRQ_REG_MAX]; 808 809 /* Mask off AAD IRQs */ 810 memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX); 811 regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, 812 mask, DA7219_AAD_IRQ_REG_MAX); 813 814 free_irq(da7219_aad->irq, da7219_aad); 815 816 cancel_work_sync(&da7219_aad->btn_det_work); 817 cancel_work_sync(&da7219_aad->hptest_work); 818 } 819 EXPORT_SYMBOL_GPL(da7219_aad_exit); 820 821 MODULE_DESCRIPTION("ASoC DA7219 AAD Driver"); 822 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 823 MODULE_LICENSE("GPL"); 824