linux/sound/soc/codecs/da7219-aad.c
<<
>>
Prefs
   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, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
 119        int report = 0, ret = 0;
 120
 121        /* Lock DAPM, Kcontrols affected by this test and the PLL */
 122        snd_soc_dapm_mutex_lock(dapm);
 123        mutex_lock(&da7219->ctrl_lock);
 124        mutex_lock(&da7219->pll_lock);
 125
 126        /* Ensure MCLK is available for HP test procedure */
 127        if (da7219->mclk) {
 128                ret = clk_prepare_enable(da7219->mclk);
 129                if (ret) {
 130                        dev_err(codec->dev, "Failed to enable mclk - %d\n", ret);
 131                        mutex_unlock(&da7219->pll_lock);
 132                        mutex_unlock(&da7219->ctrl_lock);
 133                        snd_soc_dapm_mutex_unlock(dapm);
 134                        return;
 135                }
 136        }
 137
 138        /*
 139         * If MCLK not present, then we're using the internal oscillator and
 140         * require different frequency settings to achieve the same result.
 141         *
 142         * If MCLK is present, but PLL is not enabled then we enable it here to
 143         * ensure a consistent detection procedure.
 144         */
 145        pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS);
 146        if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {
 147                tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
 148
 149                pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL);
 150                if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)
 151                        da7219_set_pll(codec, DA7219_SYSCLK_PLL,
 152                                       DA7219_PLL_FREQ_OUT_98304);
 153        } else {
 154                tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
 155        }
 156
 157        /* Ensure gain ramping at fastest rate */
 158        gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
 159        snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
 160
 161        /* Bypass cache so it saves current settings */
 162        regcache_cache_bypass(da7219->regmap, true);
 163
 164        /* Make sure Tone Generator is disabled */
 165        snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
 166
 167        /* Enable HPTest block, 1KOhms check */
 168        snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
 169                            DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
 170                            DA7219_HPTEST_EN_MASK |
 171                            DA7219_HPTEST_RES_SEL_1KOHMS);
 172
 173        /* Set gains to 0db */
 174        snd_soc_write(codec, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
 175        snd_soc_write(codec, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
 176        snd_soc_write(codec, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
 177        snd_soc_write(codec, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
 178
 179        /* Disable DAC filters, EQs and soft mute */
 180        snd_soc_update_bits(codec, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
 181                            0);
 182        snd_soc_update_bits(codec, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
 183                            0);
 184        snd_soc_update_bits(codec, DA7219_DAC_FILTERS5,
 185                            DA7219_DAC_SOFTMUTE_EN_MASK, 0);
 186
 187        /* Enable HP left & right paths */
 188        snd_soc_update_bits(codec, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
 189                            DA7219_CP_EN_MASK);
 190        snd_soc_update_bits(codec, DA7219_DIG_ROUTING_DAC,
 191                            DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
 192                            DA7219_DAC_L_SRC_TONEGEN |
 193                            DA7219_DAC_R_SRC_TONEGEN);
 194        snd_soc_update_bits(codec, DA7219_DAC_L_CTRL,
 195                            DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
 196                            DA7219_DAC_L_EN_MASK);
 197        snd_soc_update_bits(codec, DA7219_DAC_R_CTRL,
 198                            DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
 199                            DA7219_DAC_R_EN_MASK);
 200        snd_soc_update_bits(codec, DA7219_MIXOUT_L_SELECT,
 201                            DA7219_MIXOUT_L_MIX_SELECT_MASK,
 202                            DA7219_MIXOUT_L_MIX_SELECT_MASK);
 203        snd_soc_update_bits(codec, DA7219_MIXOUT_R_SELECT,
 204                            DA7219_MIXOUT_R_MIX_SELECT_MASK,
 205                            DA7219_MIXOUT_R_MIX_SELECT_MASK);
 206        snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1L,
 207                            DA7219_OUTFILT_ST_1L_SRC_MASK,
 208                            DA7219_DMIX_ST_SRC_OUTFILT1L);
 209        snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1R,
 210                            DA7219_OUTFILT_ST_1R_SRC_MASK,
 211                            DA7219_DMIX_ST_SRC_OUTFILT1R);
 212        snd_soc_update_bits(codec, DA7219_MIXOUT_L_CTRL,
 213                            DA7219_MIXOUT_L_AMP_EN_MASK,
 214                            DA7219_MIXOUT_L_AMP_EN_MASK);
 215        snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,
 216                            DA7219_MIXOUT_R_AMP_EN_MASK,
 217                            DA7219_MIXOUT_R_AMP_EN_MASK);
 218        snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
 219                            DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
 220                            DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
 221        snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
 222                            DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
 223                            DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
 224        msleep(DA7219_SETTLING_DELAY);
 225        snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
 226                            DA7219_HP_L_AMP_MUTE_EN_MASK |
 227                            DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
 228        snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
 229                            DA7219_HP_R_AMP_MUTE_EN_MASK |
 230                            DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
 231
 232        /*
 233         * If we're running from the internal oscillator then give audio paths
 234         * time to settle before running test.
 235         */
 236        if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
 237                msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
 238
 239        /* Configure & start Tone Generator */
 240        snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
 241        regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 242                         &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
 243        snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2,
 244                            DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
 245                            DA7219_SWG_SEL_SRAMP |
 246                            DA7219_TONE_GEN_GAIN_MINUS_15DB);
 247        snd_soc_write(codec, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
 248
 249        msleep(DA7219_AAD_HPTEST_PERIOD);
 250
 251        /* Grab comparator reading */
 252        accdet_cfg8 = snd_soc_read(codec, DA7219_ACCDET_CONFIG_8);
 253        if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
 254                report |= SND_JACK_HEADPHONE;
 255        else
 256                report |= SND_JACK_LINEOUT;
 257
 258        /* Stop tone generator */
 259        snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
 260
 261        msleep(DA7219_AAD_HPTEST_PERIOD);
 262
 263        /* Restore original settings from cache */
 264        regcache_mark_dirty(da7219->regmap);
 265        regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
 266                             DA7219_HP_R_CTRL);
 267        msleep(DA7219_SETTLING_DELAY);
 268        regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
 269                             DA7219_MIXOUT_R_CTRL);
 270        regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
 271                             DA7219_DROUTING_ST_OUTFILT_1R);
 272        regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,
 273                             DA7219_MIXOUT_R_SELECT);
 274        regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,
 275                             DA7219_DAC_R_CTRL);
 276        regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,
 277                             DA7219_DIG_ROUTING_DAC);
 278        regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);
 279        regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,
 280                             DA7219_DAC_FILTERS5);
 281        regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,
 282                             DA7219_DAC_FILTERS1);
 283        regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,
 284                             DA7219_HP_R_GAIN);
 285        regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,
 286                             DA7219_DAC_R_GAIN);
 287        regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,
 288                             DA7219_TONE_GEN_ON_PER);
 289        regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 290                             DA7219_TONE_GEN_FREQ1_U);
 291        regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,
 292                             DA7219_TONE_GEN_CFG2);
 293
 294        regcache_cache_bypass(da7219->regmap, false);
 295
 296        /* Disable HPTest block */
 297        snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
 298                            DA7219_HPTEST_EN_MASK, 0);
 299
 300        /*
 301         * If we're running from the internal oscillator then give audio paths
 302         * time to settle before allowing headphones to be driven as required.
 303         */
 304        if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
 305                msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
 306
 307        /* Restore gain ramping rate */
 308        snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
 309
 310        /* Drive Headphones/lineout */
 311        snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
 312                            DA7219_HP_L_AMP_OE_MASK);
 313        snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
 314                            DA7219_HP_R_AMP_OE_MASK);
 315
 316        /* Restore PLL to previous configuration, if re-configured */
 317        if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&
 318            ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))
 319                da7219_set_pll(codec, DA7219_SYSCLK_MCLK, 0);
 320
 321        /* Remove MCLK, if previously enabled */
 322        if (da7219->mclk)
 323                clk_disable_unprepare(da7219->mclk);
 324
 325        mutex_unlock(&da7219->pll_lock);
 326        mutex_unlock(&da7219->ctrl_lock);
 327        snd_soc_dapm_mutex_unlock(dapm);
 328
 329        /*
 330         * Only send report if jack hasn't been removed during process,
 331         * otherwise it's invalid and we drop it.
 332         */
 333        if (da7219_aad->jack_inserted)
 334                snd_soc_jack_report(da7219_aad->jack, report,
 335                                    SND_JACK_HEADSET | SND_JACK_LINEOUT);
 336}
 337
 338
 339/*
 340 * IRQ
 341 */
 342
 343static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
 344{
 345        struct da7219_aad_priv *da7219_aad = data;
 346        struct snd_soc_codec *codec = da7219_aad->codec;
 347        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 348        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 349        u8 events[DA7219_AAD_IRQ_REG_MAX];
 350        u8 statusa;
 351        int i, report = 0, mask = 0;
 352
 353        /* Read current IRQ events */
 354        regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
 355                         events, DA7219_AAD_IRQ_REG_MAX);
 356
 357        if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
 358                return IRQ_NONE;
 359
 360        /* Read status register for jack insertion & type status */
 361        statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
 362
 363        /* Clear events */
 364        regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
 365                          events, DA7219_AAD_IRQ_REG_MAX);
 366
 367        dev_dbg(codec->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
 368                events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
 369                statusa);
 370
 371        if (statusa & DA7219_JACK_INSERTION_STS_MASK) {
 372                /* Jack Insertion */
 373                if (events[DA7219_AAD_IRQ_REG_A] &
 374                    DA7219_E_JACK_INSERTED_MASK) {
 375                        report |= SND_JACK_MECHANICAL;
 376                        mask |= SND_JACK_MECHANICAL;
 377                        da7219_aad->jack_inserted = true;
 378                }
 379
 380                /* Jack type detection */
 381                if (events[DA7219_AAD_IRQ_REG_A] &
 382                    DA7219_E_JACK_DETECT_COMPLETE_MASK) {
 383                        /*
 384                         * If 4-pole, then enable button detection, else perform
 385                         * HP impedance test to determine output type to report.
 386                         *
 387                         * We schedule work here as the tasks themselves can
 388                         * take time to complete, and in particular for hptest
 389                         * we want to be able to check if the jack was removed
 390                         * during the procedure as this will invalidate the
 391                         * result. By doing this as work, the IRQ thread can
 392                         * handle a removal, and we can check at the end of
 393                         * hptest if we have a valid result or not.
 394                         */
 395                        if (statusa & DA7219_JACK_TYPE_STS_MASK) {
 396                                report |= SND_JACK_HEADSET;
 397                                mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT;
 398                                schedule_work(&da7219_aad->btn_det_work);
 399                        } else {
 400                                schedule_work(&da7219_aad->hptest_work);
 401                        }
 402                }
 403
 404                /* Button support for 4-pole jack */
 405                if (statusa & DA7219_JACK_TYPE_STS_MASK) {
 406                        for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
 407                                /* Button Press */
 408                                if (events[DA7219_AAD_IRQ_REG_B] &
 409                                    (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {
 410                                        report |= SND_JACK_BTN_0 >> i;
 411                                        mask |= SND_JACK_BTN_0 >> i;
 412                                }
 413                        }
 414                        snd_soc_jack_report(da7219_aad->jack, report, mask);
 415
 416                        for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
 417                                /* Button Release */
 418                                if (events[DA7219_AAD_IRQ_REG_B] &
 419                                    (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {
 420                                        report &= ~(SND_JACK_BTN_0 >> i);
 421                                        mask |= SND_JACK_BTN_0 >> i;
 422                                }
 423                        }
 424                }
 425        } else {
 426                /* Jack removal */
 427                if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {
 428                        report = 0;
 429                        mask |= DA7219_AAD_REPORT_ALL_MASK;
 430                        da7219_aad->jack_inserted = false;
 431
 432                        /* Un-drive headphones/lineout */
 433                        snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
 434                                            DA7219_HP_R_AMP_OE_MASK, 0);
 435                        snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
 436                                            DA7219_HP_L_AMP_OE_MASK, 0);
 437
 438                        /* Ensure button detection disabled */
 439                        snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
 440                                            DA7219_BUTTON_CONFIG_MASK, 0);
 441
 442                        /* Disable mic bias */
 443                        snd_soc_dapm_disable_pin(dapm, "Mic Bias");
 444                        snd_soc_dapm_sync(dapm);
 445
 446                        /* Cancel any pending work */
 447                        cancel_work_sync(&da7219_aad->btn_det_work);
 448                        cancel_work_sync(&da7219_aad->hptest_work);
 449                }
 450        }
 451
 452        snd_soc_jack_report(da7219_aad->jack, report, mask);
 453
 454        return IRQ_HANDLED;
 455}
 456
 457/*
 458 * DT/ACPI to pdata conversion
 459 */
 460
 461static enum da7219_aad_micbias_pulse_lvl
 462        da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val)
 463{
 464        switch (val) {
 465        case 2800:
 466                return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;
 467        case 2900:
 468                return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
 469        default:
 470                dev_warn(codec->dev, "Invalid micbias pulse level");
 471                return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
 472        }
 473}
 474
 475static enum da7219_aad_btn_cfg
 476        da7219_aad_fw_btn_cfg(struct snd_soc_codec *codec, u32 val)
 477{
 478        switch (val) {
 479        case 2:
 480                return DA7219_AAD_BTN_CFG_2MS;
 481        case 5:
 482                return DA7219_AAD_BTN_CFG_5MS;
 483        case 10:
 484                return DA7219_AAD_BTN_CFG_10MS;
 485        case 50:
 486                return DA7219_AAD_BTN_CFG_50MS;
 487        case 100:
 488                return DA7219_AAD_BTN_CFG_100MS;
 489        case 200:
 490                return DA7219_AAD_BTN_CFG_200MS;
 491        case 500:
 492                return DA7219_AAD_BTN_CFG_500MS;
 493        default:
 494                dev_warn(codec->dev, "Invalid button config");
 495                return DA7219_AAD_BTN_CFG_10MS;
 496        }
 497}
 498
 499static enum da7219_aad_mic_det_thr
 500        da7219_aad_fw_mic_det_thr(struct snd_soc_codec *codec, u32 val)
 501{
 502        switch (val) {
 503        case 200:
 504                return DA7219_AAD_MIC_DET_THR_200_OHMS;
 505        case 500:
 506                return DA7219_AAD_MIC_DET_THR_500_OHMS;
 507        case 750:
 508                return DA7219_AAD_MIC_DET_THR_750_OHMS;
 509        case 1000:
 510                return DA7219_AAD_MIC_DET_THR_1000_OHMS;
 511        default:
 512                dev_warn(codec->dev, "Invalid mic detect threshold");
 513                return DA7219_AAD_MIC_DET_THR_500_OHMS;
 514        }
 515}
 516
 517static enum da7219_aad_jack_ins_deb
 518        da7219_aad_fw_jack_ins_deb(struct snd_soc_codec *codec, u32 val)
 519{
 520        switch (val) {
 521        case 5:
 522                return DA7219_AAD_JACK_INS_DEB_5MS;
 523        case 10:
 524                return DA7219_AAD_JACK_INS_DEB_10MS;
 525        case 20:
 526                return DA7219_AAD_JACK_INS_DEB_20MS;
 527        case 50:
 528                return DA7219_AAD_JACK_INS_DEB_50MS;
 529        case 100:
 530                return DA7219_AAD_JACK_INS_DEB_100MS;
 531        case 200:
 532                return DA7219_AAD_JACK_INS_DEB_200MS;
 533        case 500:
 534                return DA7219_AAD_JACK_INS_DEB_500MS;
 535        case 1000:
 536                return DA7219_AAD_JACK_INS_DEB_1S;
 537        default:
 538                dev_warn(codec->dev, "Invalid jack insert debounce");
 539                return DA7219_AAD_JACK_INS_DEB_20MS;
 540        }
 541}
 542
 543static enum da7219_aad_jack_det_rate
 544        da7219_aad_fw_jack_det_rate(struct snd_soc_codec *codec, const char *str)
 545{
 546        if (!strcmp(str, "32ms_64ms")) {
 547                return DA7219_AAD_JACK_DET_RATE_32_64MS;
 548        } else if (!strcmp(str, "64ms_128ms")) {
 549                return DA7219_AAD_JACK_DET_RATE_64_128MS;
 550        } else if (!strcmp(str, "128ms_256ms")) {
 551                return DA7219_AAD_JACK_DET_RATE_128_256MS;
 552        } else if (!strcmp(str, "256ms_512ms")) {
 553                return DA7219_AAD_JACK_DET_RATE_256_512MS;
 554        } else {
 555                dev_warn(codec->dev, "Invalid jack detect rate");
 556                return DA7219_AAD_JACK_DET_RATE_256_512MS;
 557        }
 558}
 559
 560static enum da7219_aad_jack_rem_deb
 561        da7219_aad_fw_jack_rem_deb(struct snd_soc_codec *codec, u32 val)
 562{
 563        switch (val) {
 564        case 1:
 565                return DA7219_AAD_JACK_REM_DEB_1MS;
 566        case 5:
 567                return DA7219_AAD_JACK_REM_DEB_5MS;
 568        case 10:
 569                return DA7219_AAD_JACK_REM_DEB_10MS;
 570        case 20:
 571                return DA7219_AAD_JACK_REM_DEB_20MS;
 572        default:
 573                dev_warn(codec->dev, "Invalid jack removal debounce");
 574                return DA7219_AAD_JACK_REM_DEB_1MS;
 575        }
 576}
 577
 578static enum da7219_aad_btn_avg
 579        da7219_aad_fw_btn_avg(struct snd_soc_codec *codec, u32 val)
 580{
 581        switch (val) {
 582        case 1:
 583                return DA7219_AAD_BTN_AVG_1;
 584        case 2:
 585                return DA7219_AAD_BTN_AVG_2;
 586        case 4:
 587                return DA7219_AAD_BTN_AVG_4;
 588        case 8:
 589                return DA7219_AAD_BTN_AVG_8;
 590        default:
 591                dev_warn(codec->dev, "Invalid button average value");
 592                return DA7219_AAD_BTN_AVG_2;
 593        }
 594}
 595
 596static enum da7219_aad_adc_1bit_rpt
 597        da7219_aad_fw_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val)
 598{
 599        switch (val) {
 600        case 1:
 601                return DA7219_AAD_ADC_1BIT_RPT_1;
 602        case 2:
 603                return DA7219_AAD_ADC_1BIT_RPT_2;
 604        case 4:
 605                return DA7219_AAD_ADC_1BIT_RPT_4;
 606        case 8:
 607                return DA7219_AAD_ADC_1BIT_RPT_8;
 608        default:
 609                dev_warn(codec->dev, "Invalid ADC 1-bit repeat value");
 610                return DA7219_AAD_ADC_1BIT_RPT_1;
 611        }
 612}
 613
 614static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *codec)
 615{
 616        struct device *dev = codec->dev;
 617        struct i2c_client *i2c = to_i2c_client(dev);
 618        struct fwnode_handle *aad_np;
 619        struct da7219_aad_pdata *aad_pdata;
 620        const char *fw_str;
 621        u32 fw_val32;
 622
 623        aad_np = device_get_named_child_node(dev, "da7219_aad");
 624        if (!aad_np)
 625                return NULL;
 626
 627        aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL);
 628        if (!aad_pdata)
 629                return NULL;
 630
 631        aad_pdata->irq = i2c->irq;
 632
 633        if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
 634                                     &fw_val32) >= 0)
 635                aad_pdata->micbias_pulse_lvl =
 636                        da7219_aad_fw_micbias_pulse_lvl(codec, fw_val32);
 637        else
 638                aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
 639
 640        if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time",
 641                                     &fw_val32) >= 0)
 642                aad_pdata->micbias_pulse_time = fw_val32;
 643
 644        if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)
 645                aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(codec, fw_val32);
 646        else
 647                aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
 648
 649        if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)
 650                aad_pdata->mic_det_thr =
 651                        da7219_aad_fw_mic_det_thr(codec, fw_val32);
 652        else
 653                aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
 654
 655        if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
 656                aad_pdata->jack_ins_deb =
 657                        da7219_aad_fw_jack_ins_deb(codec, fw_val32);
 658        else
 659                aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
 660
 661        if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
 662                aad_pdata->jack_det_rate =
 663                        da7219_aad_fw_jack_det_rate(codec, fw_str);
 664        else
 665                aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
 666
 667        if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)
 668                aad_pdata->jack_rem_deb =
 669                        da7219_aad_fw_jack_rem_deb(codec, fw_val32);
 670        else
 671                aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
 672
 673        if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0)
 674                aad_pdata->a_d_btn_thr = (u8) fw_val32;
 675        else
 676                aad_pdata->a_d_btn_thr = 0xA;
 677
 678        if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0)
 679                aad_pdata->d_b_btn_thr = (u8) fw_val32;
 680        else
 681                aad_pdata->d_b_btn_thr = 0x16;
 682
 683        if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0)
 684                aad_pdata->b_c_btn_thr = (u8) fw_val32;
 685        else
 686                aad_pdata->b_c_btn_thr = 0x21;
 687
 688        if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0)
 689                aad_pdata->c_mic_btn_thr = (u8) fw_val32;
 690        else
 691                aad_pdata->c_mic_btn_thr = 0x3E;
 692
 693        if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)
 694                aad_pdata->btn_avg = da7219_aad_fw_btn_avg(codec, fw_val32);
 695        else
 696                aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
 697
 698        if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)
 699                aad_pdata->adc_1bit_rpt =
 700                        da7219_aad_fw_adc_1bit_rpt(codec, fw_val32);
 701        else
 702                aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
 703
 704        return aad_pdata;
 705}
 706
 707static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
 708{
 709        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 710        struct da7219_aad_priv *da7219_aad = da7219->aad;
 711        struct da7219_pdata *pdata = da7219->pdata;
 712
 713        if ((pdata) && (pdata->aad_pdata)) {
 714                struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;
 715                u8 cfg, mask;
 716
 717                da7219_aad->irq = aad_pdata->irq;
 718
 719                switch (aad_pdata->micbias_pulse_lvl) {
 720                case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:
 721                case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:
 722                        da7219_aad->micbias_pulse_lvl =
 723                                (aad_pdata->micbias_pulse_lvl <<
 724                                 DA7219_MICBIAS1_LEVEL_SHIFT);
 725                        break;
 726                default:
 727                        break;
 728                }
 729
 730                da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;
 731
 732                switch (aad_pdata->btn_cfg) {
 733                case DA7219_AAD_BTN_CFG_2MS:
 734                case DA7219_AAD_BTN_CFG_5MS:
 735                case DA7219_AAD_BTN_CFG_10MS:
 736                case DA7219_AAD_BTN_CFG_50MS:
 737                case DA7219_AAD_BTN_CFG_100MS:
 738                case DA7219_AAD_BTN_CFG_200MS:
 739                case DA7219_AAD_BTN_CFG_500MS:
 740                        da7219_aad->btn_cfg  = (aad_pdata->btn_cfg <<
 741                                                DA7219_BUTTON_CONFIG_SHIFT);
 742                }
 743
 744                cfg = 0;
 745                mask = 0;
 746                switch (aad_pdata->mic_det_thr) {
 747                case DA7219_AAD_MIC_DET_THR_200_OHMS:
 748                case DA7219_AAD_MIC_DET_THR_500_OHMS:
 749                case DA7219_AAD_MIC_DET_THR_750_OHMS:
 750                case DA7219_AAD_MIC_DET_THR_1000_OHMS:
 751                        cfg |= (aad_pdata->mic_det_thr <<
 752                                DA7219_MIC_DET_THRESH_SHIFT);
 753                        mask |= DA7219_MIC_DET_THRESH_MASK;
 754                }
 755                snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, mask, cfg);
 756
 757                cfg = 0;
 758                mask = 0;
 759                switch (aad_pdata->jack_ins_deb) {
 760                case DA7219_AAD_JACK_INS_DEB_5MS:
 761                case DA7219_AAD_JACK_INS_DEB_10MS:
 762                case DA7219_AAD_JACK_INS_DEB_20MS:
 763                case DA7219_AAD_JACK_INS_DEB_50MS:
 764                case DA7219_AAD_JACK_INS_DEB_100MS:
 765                case DA7219_AAD_JACK_INS_DEB_200MS:
 766                case DA7219_AAD_JACK_INS_DEB_500MS:
 767                case DA7219_AAD_JACK_INS_DEB_1S:
 768                        cfg |= (aad_pdata->jack_ins_deb <<
 769                                DA7219_JACKDET_DEBOUNCE_SHIFT);
 770                        mask |= DA7219_JACKDET_DEBOUNCE_MASK;
 771                }
 772                switch (aad_pdata->jack_det_rate) {
 773                case DA7219_AAD_JACK_DET_RATE_32_64MS:
 774                case DA7219_AAD_JACK_DET_RATE_64_128MS:
 775                case DA7219_AAD_JACK_DET_RATE_128_256MS:
 776                case DA7219_AAD_JACK_DET_RATE_256_512MS:
 777                        cfg |= (aad_pdata->jack_det_rate <<
 778                                DA7219_JACK_DETECT_RATE_SHIFT);
 779                        mask |= DA7219_JACK_DETECT_RATE_MASK;
 780                }
 781                switch (aad_pdata->jack_rem_deb) {
 782                case DA7219_AAD_JACK_REM_DEB_1MS:
 783                case DA7219_AAD_JACK_REM_DEB_5MS:
 784                case DA7219_AAD_JACK_REM_DEB_10MS:
 785                case DA7219_AAD_JACK_REM_DEB_20MS:
 786                        cfg |= (aad_pdata->jack_rem_deb <<
 787                                DA7219_JACKDET_REM_DEB_SHIFT);
 788                        mask |= DA7219_JACKDET_REM_DEB_MASK;
 789                }
 790                snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_2, mask, cfg);
 791
 792                snd_soc_write(codec, DA7219_ACCDET_CONFIG_3,
 793                              aad_pdata->a_d_btn_thr);
 794                snd_soc_write(codec, DA7219_ACCDET_CONFIG_4,
 795                              aad_pdata->d_b_btn_thr);
 796                snd_soc_write(codec, DA7219_ACCDET_CONFIG_5,
 797                              aad_pdata->b_c_btn_thr);
 798                snd_soc_write(codec, DA7219_ACCDET_CONFIG_6,
 799                              aad_pdata->c_mic_btn_thr);
 800
 801                cfg = 0;
 802                mask = 0;
 803                switch (aad_pdata->btn_avg) {
 804                case DA7219_AAD_BTN_AVG_1:
 805                case DA7219_AAD_BTN_AVG_2:
 806                case DA7219_AAD_BTN_AVG_4:
 807                case DA7219_AAD_BTN_AVG_8:
 808                        cfg |= (aad_pdata->btn_avg <<
 809                                DA7219_BUTTON_AVERAGE_SHIFT);
 810                        mask |= DA7219_BUTTON_AVERAGE_MASK;
 811                }
 812                switch (aad_pdata->adc_1bit_rpt) {
 813                case DA7219_AAD_ADC_1BIT_RPT_1:
 814                case DA7219_AAD_ADC_1BIT_RPT_2:
 815                case DA7219_AAD_ADC_1BIT_RPT_4:
 816                case DA7219_AAD_ADC_1BIT_RPT_8:
 817                        cfg |= (aad_pdata->adc_1bit_rpt <<
 818                               DA7219_ADC_1_BIT_REPEAT_SHIFT);
 819                        mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
 820                }
 821                snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_7, mask, cfg);
 822        }
 823}
 824
 825
 826/*
 827 * Suspend/Resume
 828 */
 829
 830void da7219_aad_suspend(struct snd_soc_codec *codec)
 831{
 832        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 833        struct da7219_aad_priv *da7219_aad = da7219->aad;
 834        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 835        u8 micbias_ctrl;
 836
 837        if (da7219_aad->jack) {
 838                /* Disable jack detection during suspend */
 839                snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
 840                                    DA7219_ACCDET_EN_MASK, 0);
 841
 842                /*
 843                 * If we have a 4-pole jack inserted, then micbias will be
 844                 * enabled. We can disable micbias here, and keep a note to
 845                 * re-enable it on resume. If jack removal occurred during
 846                 * suspend then this will be dealt with through the IRQ handler.
 847                 */
 848                if (da7219_aad->jack_inserted) {
 849                        micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
 850                        if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
 851                                snd_soc_dapm_disable_pin(dapm, "Mic Bias");
 852                                snd_soc_dapm_sync(dapm);
 853                                da7219_aad->micbias_resume_enable = true;
 854                        }
 855                }
 856        }
 857}
 858
 859void da7219_aad_resume(struct snd_soc_codec *codec)
 860{
 861        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 862        struct da7219_aad_priv *da7219_aad = da7219->aad;
 863        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 864
 865        if (da7219_aad->jack) {
 866                /* Re-enable micbias if previously enabled for 4-pole jack */
 867                if (da7219_aad->jack_inserted &&
 868                    da7219_aad->micbias_resume_enable) {
 869                        snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
 870                        snd_soc_dapm_sync(dapm);
 871                        da7219_aad->micbias_resume_enable = false;
 872                }
 873
 874                /* Re-enable jack detection */
 875                snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
 876                                    DA7219_ACCDET_EN_MASK,
 877                                    DA7219_ACCDET_EN_MASK);
 878        }
 879}
 880
 881
 882/*
 883 * Init/Exit
 884 */
 885
 886int da7219_aad_init(struct snd_soc_codec *codec)
 887{
 888        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 889        struct da7219_aad_priv *da7219_aad;
 890        u8 mask[DA7219_AAD_IRQ_REG_MAX];
 891        int ret;
 892
 893        da7219_aad = devm_kzalloc(codec->dev, sizeof(*da7219_aad), GFP_KERNEL);
 894        if (!da7219_aad)
 895                return -ENOMEM;
 896
 897        da7219->aad = da7219_aad;
 898        da7219_aad->codec = codec;
 899
 900        /* Handle any DT/ACPI/platform data */
 901        if (da7219->pdata && !da7219->pdata->aad_pdata)
 902                da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(codec);
 903
 904        da7219_aad_handle_pdata(codec);
 905
 906        /* Disable button detection */
 907        snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
 908                            DA7219_BUTTON_CONFIG_MASK, 0);
 909
 910        INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
 911        INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
 912
 913        ret = request_threaded_irq(da7219_aad->irq, NULL,
 914                                   da7219_aad_irq_thread,
 915                                   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 916                                   "da7219-aad", da7219_aad);
 917        if (ret) {
 918                dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
 919                return ret;
 920        }
 921
 922        /* Unmask AAD IRQs */
 923        memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);
 924        regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
 925                          &mask, DA7219_AAD_IRQ_REG_MAX);
 926
 927        return 0;
 928}
 929EXPORT_SYMBOL_GPL(da7219_aad_init);
 930
 931void da7219_aad_exit(struct snd_soc_codec *codec)
 932{
 933        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 934        struct da7219_aad_priv *da7219_aad = da7219->aad;
 935        u8 mask[DA7219_AAD_IRQ_REG_MAX];
 936
 937        /* Mask off AAD IRQs */
 938        memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);
 939        regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
 940                          mask, DA7219_AAD_IRQ_REG_MAX);
 941
 942        free_irq(da7219_aad->irq, da7219_aad);
 943
 944        cancel_work_sync(&da7219_aad->btn_det_work);
 945        cancel_work_sync(&da7219_aad->hptest_work);
 946}
 947EXPORT_SYMBOL_GPL(da7219_aad_exit);
 948
 949MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
 950MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
 951MODULE_LICENSE("GPL");
 952