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/i2c.h> 17 #include <linux/property.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/ACPI to pdata conversion 386 */ 387 388 static enum da7219_aad_micbias_pulse_lvl 389 da7219_aad_fw_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_fw_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_fw_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_fw_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_fw_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_fw_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_fw_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_fw_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_fw_to_pdata(struct snd_soc_codec *codec) 542 { 543 struct device *dev = codec->dev; 544 struct i2c_client *i2c = to_i2c_client(dev); 545 struct fwnode_handle *aad_np; 546 struct da7219_aad_pdata *aad_pdata; 547 const char *fw_str; 548 u32 fw_val32; 549 550 aad_np = device_get_named_child_node(dev, "da7219_aad"); 551 if (!aad_np) 552 return NULL; 553 554 aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL); 555 if (!aad_pdata) 556 return NULL; 557 558 aad_pdata->irq = i2c->irq; 559 560 if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl", 561 &fw_val32) >= 0) 562 aad_pdata->micbias_pulse_lvl = 563 da7219_aad_fw_micbias_pulse_lvl(codec, fw_val32); 564 else 565 aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF; 566 567 if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time", 568 &fw_val32) >= 0) 569 aad_pdata->micbias_pulse_time = fw_val32; 570 571 if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0) 572 aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(codec, fw_val32); 573 else 574 aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS; 575 576 if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0) 577 aad_pdata->mic_det_thr = 578 da7219_aad_fw_mic_det_thr(codec, fw_val32); 579 else 580 aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS; 581 582 if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0) 583 aad_pdata->jack_ins_deb = 584 da7219_aad_fw_jack_ins_deb(codec, fw_val32); 585 else 586 aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; 587 588 if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str)) 589 aad_pdata->jack_det_rate = 590 da7219_aad_fw_jack_det_rate(codec, fw_str); 591 else 592 aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS; 593 594 if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0) 595 aad_pdata->jack_rem_deb = 596 da7219_aad_fw_jack_rem_deb(codec, fw_val32); 597 else 598 aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS; 599 600 if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0) 601 aad_pdata->a_d_btn_thr = (u8) fw_val32; 602 else 603 aad_pdata->a_d_btn_thr = 0xA; 604 605 if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0) 606 aad_pdata->d_b_btn_thr = (u8) fw_val32; 607 else 608 aad_pdata->d_b_btn_thr = 0x16; 609 610 if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0) 611 aad_pdata->b_c_btn_thr = (u8) fw_val32; 612 else 613 aad_pdata->b_c_btn_thr = 0x21; 614 615 if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0) 616 aad_pdata->c_mic_btn_thr = (u8) fw_val32; 617 else 618 aad_pdata->c_mic_btn_thr = 0x3E; 619 620 if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0) 621 aad_pdata->btn_avg = da7219_aad_fw_btn_avg(codec, fw_val32); 622 else 623 aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2; 624 625 if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0) 626 aad_pdata->adc_1bit_rpt = 627 da7219_aad_fw_adc_1bit_rpt(codec, fw_val32); 628 else 629 aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; 630 631 return aad_pdata; 632 } 633 634 static void da7219_aad_handle_pdata(struct snd_soc_codec *codec) 635 { 636 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 637 struct da7219_aad_priv *da7219_aad = da7219->aad; 638 struct da7219_pdata *pdata = da7219->pdata; 639 640 if ((pdata) && (pdata->aad_pdata)) { 641 struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata; 642 u8 cfg, mask; 643 644 da7219_aad->irq = aad_pdata->irq; 645 646 switch (aad_pdata->micbias_pulse_lvl) { 647 case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V: 648 case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V: 649 da7219_aad->micbias_pulse_lvl = 650 (aad_pdata->micbias_pulse_lvl << 651 DA7219_MICBIAS1_LEVEL_SHIFT); 652 break; 653 default: 654 break; 655 } 656 657 da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time; 658 659 switch (aad_pdata->btn_cfg) { 660 case DA7219_AAD_BTN_CFG_2MS: 661 case DA7219_AAD_BTN_CFG_5MS: 662 case DA7219_AAD_BTN_CFG_10MS: 663 case DA7219_AAD_BTN_CFG_50MS: 664 case DA7219_AAD_BTN_CFG_100MS: 665 case DA7219_AAD_BTN_CFG_200MS: 666 case DA7219_AAD_BTN_CFG_500MS: 667 da7219_aad->btn_cfg = (aad_pdata->btn_cfg << 668 DA7219_BUTTON_CONFIG_SHIFT); 669 } 670 671 cfg = 0; 672 mask = 0; 673 switch (aad_pdata->mic_det_thr) { 674 case DA7219_AAD_MIC_DET_THR_200_OHMS: 675 case DA7219_AAD_MIC_DET_THR_500_OHMS: 676 case DA7219_AAD_MIC_DET_THR_750_OHMS: 677 case DA7219_AAD_MIC_DET_THR_1000_OHMS: 678 cfg |= (aad_pdata->mic_det_thr << 679 DA7219_MIC_DET_THRESH_SHIFT); 680 mask |= DA7219_MIC_DET_THRESH_MASK; 681 } 682 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, mask, cfg); 683 684 cfg = 0; 685 mask = 0; 686 switch (aad_pdata->jack_ins_deb) { 687 case DA7219_AAD_JACK_INS_DEB_5MS: 688 case DA7219_AAD_JACK_INS_DEB_10MS: 689 case DA7219_AAD_JACK_INS_DEB_20MS: 690 case DA7219_AAD_JACK_INS_DEB_50MS: 691 case DA7219_AAD_JACK_INS_DEB_100MS: 692 case DA7219_AAD_JACK_INS_DEB_200MS: 693 case DA7219_AAD_JACK_INS_DEB_500MS: 694 case DA7219_AAD_JACK_INS_DEB_1S: 695 cfg |= (aad_pdata->jack_ins_deb << 696 DA7219_JACKDET_DEBOUNCE_SHIFT); 697 mask |= DA7219_JACKDET_DEBOUNCE_MASK; 698 } 699 switch (aad_pdata->jack_det_rate) { 700 case DA7219_AAD_JACK_DET_RATE_32_64MS: 701 case DA7219_AAD_JACK_DET_RATE_64_128MS: 702 case DA7219_AAD_JACK_DET_RATE_128_256MS: 703 case DA7219_AAD_JACK_DET_RATE_256_512MS: 704 cfg |= (aad_pdata->jack_det_rate << 705 DA7219_JACK_DETECT_RATE_SHIFT); 706 mask |= DA7219_JACK_DETECT_RATE_MASK; 707 } 708 switch (aad_pdata->jack_rem_deb) { 709 case DA7219_AAD_JACK_REM_DEB_1MS: 710 case DA7219_AAD_JACK_REM_DEB_5MS: 711 case DA7219_AAD_JACK_REM_DEB_10MS: 712 case DA7219_AAD_JACK_REM_DEB_20MS: 713 cfg |= (aad_pdata->jack_rem_deb << 714 DA7219_JACKDET_REM_DEB_SHIFT); 715 mask |= DA7219_JACKDET_REM_DEB_MASK; 716 } 717 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_2, mask, cfg); 718 719 snd_soc_write(codec, DA7219_ACCDET_CONFIG_3, 720 aad_pdata->a_d_btn_thr); 721 snd_soc_write(codec, DA7219_ACCDET_CONFIG_4, 722 aad_pdata->d_b_btn_thr); 723 snd_soc_write(codec, DA7219_ACCDET_CONFIG_5, 724 aad_pdata->b_c_btn_thr); 725 snd_soc_write(codec, DA7219_ACCDET_CONFIG_6, 726 aad_pdata->c_mic_btn_thr); 727 728 cfg = 0; 729 mask = 0; 730 switch (aad_pdata->btn_avg) { 731 case DA7219_AAD_BTN_AVG_1: 732 case DA7219_AAD_BTN_AVG_2: 733 case DA7219_AAD_BTN_AVG_4: 734 case DA7219_AAD_BTN_AVG_8: 735 cfg |= (aad_pdata->btn_avg << 736 DA7219_BUTTON_AVERAGE_SHIFT); 737 mask |= DA7219_BUTTON_AVERAGE_MASK; 738 } 739 switch (aad_pdata->adc_1bit_rpt) { 740 case DA7219_AAD_ADC_1BIT_RPT_1: 741 case DA7219_AAD_ADC_1BIT_RPT_2: 742 case DA7219_AAD_ADC_1BIT_RPT_4: 743 case DA7219_AAD_ADC_1BIT_RPT_8: 744 cfg |= (aad_pdata->adc_1bit_rpt << 745 DA7219_ADC_1_BIT_REPEAT_SHIFT); 746 mask |= DA7219_ADC_1_BIT_REPEAT_MASK; 747 } 748 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_7, mask, cfg); 749 } 750 } 751 752 753 /* 754 * Init/Exit 755 */ 756 757 int da7219_aad_init(struct snd_soc_codec *codec) 758 { 759 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 760 struct da7219_aad_priv *da7219_aad; 761 u8 mask[DA7219_AAD_IRQ_REG_MAX]; 762 int ret; 763 764 da7219_aad = devm_kzalloc(codec->dev, sizeof(*da7219_aad), GFP_KERNEL); 765 if (!da7219_aad) 766 return -ENOMEM; 767 768 da7219->aad = da7219_aad; 769 da7219_aad->codec = codec; 770 771 /* Handle any DT/ACPI/platform data */ 772 if (da7219->pdata && !da7219->pdata->aad_pdata) 773 da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(codec); 774 775 da7219_aad_handle_pdata(codec); 776 777 /* Disable button detection */ 778 snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, 779 DA7219_BUTTON_CONFIG_MASK, 0); 780 781 INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work); 782 INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); 783 784 ret = request_threaded_irq(da7219_aad->irq, NULL, 785 da7219_aad_irq_thread, 786 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 787 "da7219-aad", da7219_aad); 788 if (ret) { 789 dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); 790 return ret; 791 } 792 793 /* Unmask AAD IRQs */ 794 memset(mask, 0, DA7219_AAD_IRQ_REG_MAX); 795 regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, 796 &mask, DA7219_AAD_IRQ_REG_MAX); 797 798 return 0; 799 } 800 EXPORT_SYMBOL_GPL(da7219_aad_init); 801 802 void da7219_aad_exit(struct snd_soc_codec *codec) 803 { 804 struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); 805 struct da7219_aad_priv *da7219_aad = da7219->aad; 806 u8 mask[DA7219_AAD_IRQ_REG_MAX]; 807 808 /* Mask off AAD IRQs */ 809 memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX); 810 regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A, 811 mask, DA7219_AAD_IRQ_REG_MAX); 812 813 free_irq(da7219_aad->irq, da7219_aad); 814 815 cancel_work_sync(&da7219_aad->btn_det_work); 816 cancel_work_sync(&da7219_aad->hptest_work); 817 } 818 EXPORT_SYMBOL_GPL(da7219_aad_exit); 819 820 MODULE_DESCRIPTION("ASoC DA7219 AAD Driver"); 821 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 822 MODULE_LICENSE("GPL"); 823