Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/sound/soc/codecs/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 132 kB image not shown  

Quelle  wm8994.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * wm8994.c  --  WM8994 ALSA SoC Audio driver
 *
 * Copyright 2009-12 Wolfson Microelectronics plc
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 */


#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <trace/events/asoc.h>

#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/mfd/wm8994/pdata.h>
#include <linux/mfd/wm8994/gpio.h>

#include "wm8994.h"
#include "wm_hubs.h"

#define WM1811_JACKDET_MODE_NONE  0x0000
#define WM1811_JACKDET_MODE_JACK  0x0100
#define WM1811_JACKDET_MODE_MIC   0x0080
#define WM1811_JACKDET_MODE_AUDIO 0x0180

#define WM8994_NUM_DRC 3
#define WM8994_NUM_EQ  3

struct wm8994_reg_mask {
 unsigned int reg;
 unsigned int mask;
};

static struct wm8994_reg_mask wm8994_vu_bits[] = {
 { WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU },
 { WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU },
 { WM8994_LEFT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU },
 { WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU },
 { WM8994_SPEAKER_VOLUME_LEFT, WM8994_SPKOUT_VU },
 { WM8994_SPEAKER_VOLUME_RIGHT, WM8994_SPKOUT_VU },
 { WM8994_LEFT_OUTPUT_VOLUME, WM8994_HPOUT1_VU },
 { WM8994_RIGHT_OUTPUT_VOLUME, WM8994_HPOUT1_VU },
 { WM8994_LEFT_OPGA_VOLUME, WM8994_MIXOUT_VU },
 { WM8994_RIGHT_OPGA_VOLUME, WM8994_MIXOUT_VU },

 { WM8994_AIF1_DAC1_LEFT_VOLUME, WM8994_AIF1DAC1_VU },
 { WM8994_AIF1_DAC1_RIGHT_VOLUME, WM8994_AIF1DAC1_VU },
 { WM8994_AIF2_DAC_LEFT_VOLUME, WM8994_AIF2DAC_VU },
 { WM8994_AIF2_DAC_RIGHT_VOLUME, WM8994_AIF2DAC_VU },
 { WM8994_AIF1_ADC1_LEFT_VOLUME, WM8994_AIF1ADC1_VU },
 { WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1ADC1_VU },
 { WM8994_AIF2_ADC_LEFT_VOLUME, WM8994_AIF2ADC_VU },
 { WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
 { WM8994_DAC1_LEFT_VOLUME, WM8994_DAC1_VU },
 { WM8994_DAC1_RIGHT_VOLUME, WM8994_DAC1_VU },
 { WM8994_DAC2_LEFT_VOLUME, WM8994_DAC2_VU },
 { WM8994_DAC2_RIGHT_VOLUME, WM8994_DAC2_VU },
};

/* VU bitfields for ADC2, DAC2 not available on WM1811 */
static struct wm8994_reg_mask wm8994_adc2_dac2_vu_bits[] = {
 { WM8994_AIF1_DAC2_LEFT_VOLUME, WM8994_AIF1DAC2_VU },
 { WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU },
 { WM8994_AIF1_ADC2_LEFT_VOLUME, WM8994_AIF1ADC2_VU },
 { WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
};

static int wm8994_drc_base[] = {
 WM8994_AIF1_DRC1_1,
 WM8994_AIF1_DRC2_1,
 WM8994_AIF2_DRC_1,
};

static int wm8994_retune_mobile_base[] = {
 WM8994_AIF1_DAC1_EQ_GAINS_1,
 WM8994_AIF1_DAC2_EQ_GAINS_1,
 WM8994_AIF2_EQ_GAINS_1,
};

static const struct wm8958_micd_rate micdet_rates[] = {
 { 32768,       true,  1, 4 },
 { 32768,       false, 1, 1 },
 { 44100 * 256, true,  7, 10 },
 { 44100 * 256, false, 7, 10 },
};

static const struct wm8958_micd_rate jackdet_rates[] = {
 { 32768,       true,  0, 1 },
 { 32768,       false, 0, 1 },
 { 44100 * 256, true,  10, 10 },
 { 44100 * 256, false, 7, 8 },
};

static void wm8958_micd_set_rate(struct snd_soc_component *component)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 int best, i, sysclk, val;
 bool idle;
 const struct wm8958_micd_rate *rates;
 int num_rates;

 idle = !wm8994->jack_mic;

 sysclk = snd_soc_component_read(component, WM8994_CLOCKING_1);
 if (sysclk & WM8994_SYSCLK_SRC)
  sysclk = wm8994->aifclk[1];
 else
  sysclk = wm8994->aifclk[0];

 if (control->pdata.micd_rates) {
  rates = control->pdata.micd_rates;
  num_rates = control->pdata.num_micd_rates;
 } else if (wm8994->jackdet) {
  rates = jackdet_rates;
  num_rates = ARRAY_SIZE(jackdet_rates);
 } else {
  rates = micdet_rates;
  num_rates = ARRAY_SIZE(micdet_rates);
 }

 best = 0;
 for (i = 0; i < num_rates; i++) {
  if (rates[i].idle != idle)
   continue;
  if (abs(rates[i].sysclk - sysclk) <
      abs(rates[best].sysclk - sysclk))
   best = i;
  else if (rates[best].idle != idle)
   best = i;
 }

 val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
  | rates[best].rate << WM8958_MICD_RATE_SHIFT;

 dev_dbg(component->dev, "MICD rate %d,%d for %dHz %s\n",
  rates[best].start, rates[best].rate, sysclk,
  idle ? "idle" : "active");

 snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
       WM8958_MICD_BIAS_STARTTIME_MASK |
       WM8958_MICD_RATE_MASK, val);
}

static int configure_aif_clock(struct snd_soc_component *component, int aif)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 int rate;
 int reg1 = 0;
 int offset;

 if (aif)
  offset = 4;
 else
  offset = 0;

 switch (wm8994->sysclk[aif]) {
 case WM8994_SYSCLK_MCLK1:
  rate = wm8994->mclk_rate[0];
  break;

 case WM8994_SYSCLK_MCLK2:
  reg1 |= 0x8;
  rate = wm8994->mclk_rate[1];
  break;

 case WM8994_SYSCLK_FLL1:
  reg1 |= 0x10;
  rate = wm8994->fll[0].out;
  break;

 case WM8994_SYSCLK_FLL2:
  reg1 |= 0x18;
  rate = wm8994->fll[1].out;
  break;

 default:
  return -EINVAL;
 }

 if (rate >= 13500000) {
  rate /= 2;
  reg1 |= WM8994_AIF1CLK_DIV;

  dev_dbg(component->dev, "Dividing AIF%d clock to %dHz\n",
   aif + 1, rate);
 }

 wm8994->aifclk[aif] = rate;

 snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1 + offset,
       WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
       reg1);

 return 0;
}

static int configure_clock(struct snd_soc_component *component)
{
 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 int change, new;

 /* Bring up the AIF clocks first */
 configure_aif_clock(component, 0);
 configure_aif_clock(component, 1);

 /* Then switch CLK_SYS over to the higher of them; a change
 * can only happen as a result of a clocking change which can
 * only be made outside of DAPM so we can safely redo the
 * clocking.
 */


 /* If they're equal it doesn't matter which is used */
 if (wm8994->aifclk[0] == wm8994->aifclk[1]) {
  wm8958_micd_set_rate(component);
  return 0;
 }

 if (wm8994->aifclk[0] < wm8994->aifclk[1])
  new = WM8994_SYSCLK_SRC;
 else
  new = 0;

 change = snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
         WM8994_SYSCLK_SRC, new);
 if (change)
  snd_soc_dapm_sync(dapm);

 wm8958_micd_set_rate(component);

 return 0;
}

static int check_clk_sys(struct snd_soc_dapm_widget *source,
    struct snd_soc_dapm_widget *sink)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 int reg = snd_soc_component_read(component, WM8994_CLOCKING_1);
 const char *clk;

 /* Check what we're currently using for CLK_SYS */
 if (reg & WM8994_SYSCLK_SRC)
  clk = "AIF2CLK";
 else
  clk = "AIF1CLK";

 return snd_soc_dapm_widget_name_cmp(source, clk) == 0;
}

static const char *sidetone_hpf_text[] = {
 "2.7kHz""1.35kHz""675Hz""370Hz""180Hz""90Hz""45Hz"
};

static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
       WM8994_SIDETONE, 7, sidetone_hpf_text);

static const char *adc_hpf_text[] = {
 "HiFi""Voice 1""Voice 2""Voice 3"
};

static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf,
       WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text);

static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf,
       WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text);

static SOC_ENUM_SINGLE_DECL(aif2adc_hpf,
       WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);

static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);

#define WM8994_DRC_SWITCH(xname, reg, shift) \
 SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \
  snd_soc_get_volsw, wm8994_put_drc_sw)

static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
{
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;
 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 int mask, ret;

 /* Can't enable both ADC and DAC paths simultaneously */
 if (mc->shift == WM8994_AIF1DAC1_DRC_ENA_SHIFT)
  mask = WM8994_AIF1ADC1L_DRC_ENA_MASK |
   WM8994_AIF1ADC1R_DRC_ENA_MASK;
 else
  mask = WM8994_AIF1DAC1_DRC_ENA_MASK;

 ret = snd_soc_component_read(component, mc->reg);
 if (ret < 0)
  return ret;
 if (ret & mask)
  return -EINVAL;

 return snd_soc_put_volsw(kcontrol, ucontrol);
}

static void wm8994_set_drc(struct snd_soc_component *component, int drc)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 struct wm8994_pdata *pdata = &control->pdata;
 int base = wm8994_drc_base[drc];
 int cfg = wm8994->drc_cfg[drc];
 int save, i;

 /* Save any enables; the configuration should clear them. */
 save = snd_soc_component_read(component, base);
 save &= WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
  WM8994_AIF1ADC1R_DRC_ENA;

 for (i = 0; i < WM8994_DRC_REGS; i++)
  snd_soc_component_update_bits(component, base + i, 0xffff,
        pdata->drc_cfgs[cfg].regs[i]);

 snd_soc_component_update_bits(component, base, WM8994_AIF1DAC1_DRC_ENA |
        WM8994_AIF1ADC1L_DRC_ENA |
        WM8994_AIF1ADC1R_DRC_ENA, save);
}

/* Icky as hell but saves code duplication */
static int wm8994_get_drc(const char *name)
{
 if (strcmp(name, "AIF1DRC1 Mode") == 0)
  return 0;
 if (strcmp(name, "AIF1DRC2 Mode") == 0)
  return 1;
 if (strcmp(name, "AIF2DRC Mode") == 0)
  return 2;
 return -EINVAL;
}

static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
          struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 struct wm8994_pdata *pdata = &control->pdata;
 int drc = wm8994_get_drc(kcontrol->id.name);
 int value = ucontrol->value.enumerated.item[0];

 if (drc < 0)
  return drc;

 if (value >= pdata->num_drc_cfgs)
  return -EINVAL;

 wm8994->drc_cfg[drc] = value;

 wm8994_set_drc(component, drc);

 return 0;
}

static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
          struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 int drc = wm8994_get_drc(kcontrol->id.name);

 if (drc < 0)
  return drc;
 ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc];

 return 0;
}

static void wm8994_set_retune_mobile(struct snd_soc_component *component, int block)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 struct wm8994_pdata *pdata = &control->pdata;
 int base = wm8994_retune_mobile_base[block];
 int iface, best, best_val, save, i, cfg;

 if (!pdata || !wm8994->num_retune_mobile_texts)
  return;

 switch (block) {
 case 0:
 case 1:
  iface = 0;
  break;
 case 2:
  iface = 1;
  break;
 default:
  return;
 }

 /* Find the version of the currently selected configuration
 * with the nearest sample rate. */

 cfg = wm8994->retune_mobile_cfg[block];
 best = 0;
 best_val = INT_MAX;
 for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
  if (strcmp(pdata->retune_mobile_cfgs[i].name,
      wm8994->retune_mobile_texts[cfg]) == 0 &&
      abs(pdata->retune_mobile_cfgs[i].rate
   - wm8994->dac_rates[iface]) < best_val) {
   best = i;
   best_val = abs(pdata->retune_mobile_cfgs[i].rate
           - wm8994->dac_rates[iface]);
  }
 }

 dev_dbg(component->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
  block,
  pdata->retune_mobile_cfgs[best].name,
  pdata->retune_mobile_cfgs[best].rate,
  wm8994->dac_rates[iface]);

 /* The EQ will be disabled while reconfiguring it, remember the
 * current configuration.
 */

 save = snd_soc_component_read(component, base);
 save &= WM8994_AIF1DAC1_EQ_ENA;

 for (i = 0; i < WM8994_EQ_REGS; i++)
  snd_soc_component_update_bits(component, base + i, 0xffff,
    pdata->retune_mobile_cfgs[best].regs[i]);

 snd_soc_component_update_bits(component, base, WM8994_AIF1DAC1_EQ_ENA, save);
}

/* Icky as hell but saves code duplication */
static int wm8994_get_retune_mobile_block(const char *name)
{
 if (strcmp(name, "AIF1.1 EQ Mode") == 0)
  return 0;
 if (strcmp(name, "AIF1.2 EQ Mode") == 0)
  return 1;
 if (strcmp(name, "AIF2 EQ Mode") == 0)
  return 2;
 return -EINVAL;
}

static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
      struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 struct wm8994_pdata *pdata = &control->pdata;
 int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
 int value = ucontrol->value.enumerated.item[0];

 if (block < 0)
  return block;

 if (value >= pdata->num_retune_mobile_cfgs)
  return -EINVAL;

 wm8994->retune_mobile_cfg[block] = value;

 wm8994_set_retune_mobile(component, block);

 return 0;
}

static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
      struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 int block = wm8994_get_retune_mobile_block(kcontrol->id.name);

 if (block < 0)
  return block;

 ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];

 return 0;
}

static const char *aif_chan_src_text[] = {
 "Left""Right"
};

static SOC_ENUM_SINGLE_DECL(aif1adcl_src,
       WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif1adcr_src,
       WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2adcl_src,
       WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2adcr_src,
       WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif1dacl_src,
       WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif1dacr_src,
       WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2dacl_src,
       WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2dacr_src,
       WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);

static const char *osr_text[] = {
 "Low Power""High Performance",
};

static SOC_ENUM_SINGLE_DECL(dac_osr,
       WM8994_OVERSAMPLING, 0, osr_text);

static SOC_ENUM_SINGLE_DECL(adc_osr,
       WM8994_OVERSAMPLING, 1, osr_text);

static const struct snd_kcontrol_new wm8994_common_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
   WM8994_AIF1_ADC1_RIGHT_VOLUME,
   1, 119, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
   WM8994_AIF2_ADC_RIGHT_VOLUME,
   1, 119, 0, digital_tlv),

SOC_ENUM("AIF1ADCL Source", aif1adcl_src),
SOC_ENUM("AIF1ADCR Source", aif1adcr_src),
SOC_ENUM("AIF2ADCL Source", aif2adcl_src),
SOC_ENUM("AIF2ADCR Source", aif2adcr_src),

SOC_ENUM("AIF1DACL Source", aif1dacl_src),
SOC_ENUM("AIF1DACR Source", aif1dacr_src),
SOC_ENUM("AIF2DACL Source", aif2dacl_src),
SOC_ENUM("AIF2DACR Source", aif2dacr_src),

SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
   WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME,
   WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv),

SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv),
SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv),

SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0),
SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0),

WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2),
WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1),
WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0),

WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2),
WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1),
WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0),

SOC_SINGLE_TLV("DAC1 Right Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES,
        5, 12, 0, st_tlv),
SOC_SINGLE_TLV("DAC1 Left Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES,
        0, 12, 0, st_tlv),
SOC_SINGLE_TLV("DAC2 Right Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
        5, 12, 0, st_tlv),
SOC_SINGLE_TLV("DAC2 Left Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
        0, 12, 0, st_tlv),
SOC_ENUM("Sidetone HPF Mux", sidetone_hpf),
SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),

SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf),
SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0),

SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),

SOC_ENUM("ADC OSR", adc_osr),
SOC_ENUM("DAC OSR", dac_osr),

SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME,
   WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME,
      WM8994_DAC1_RIGHT_VOLUME, 9, 1, 1),

SOC_DOUBLE_R_TLV("DAC2 Volume", WM8994_DAC2_LEFT_VOLUME,
   WM8994_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R("DAC2 Switch", WM8994_DAC2_LEFT_VOLUME,
      WM8994_DAC2_RIGHT_VOLUME, 9, 1, 1),

SOC_SINGLE_TLV("SPKL DAC2 Volume", WM8994_SPKMIXL_ATTENUATION,
        6, 1, 1, wm_hubs_spkmix_tlv),
SOC_SINGLE_TLV("SPKL DAC1 Volume", WM8994_SPKMIXL_ATTENUATION,
        2, 1, 1, wm_hubs_spkmix_tlv),

SOC_SINGLE_TLV("SPKR DAC2 Volume", WM8994_SPKMIXR_ATTENUATION,
        6, 1, 1, wm_hubs_spkmix_tlv),
SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION,
        2, 1, 1, wm_hubs_spkmix_tlv),

SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
        10, 15, 0, wm8994_3d_tlv),
SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC1_FILTERS_2,
    8, 1, 0),
SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2,
        10, 15, 0, wm8994_3d_tlv),
SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
    8, 1, 0),
SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF2_DAC_FILTERS_2,
        10, 15, 0, wm8994_3d_tlv),
SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
    8, 1, 0),
};

/* Controls not available on WM1811 */
static const struct snd_kcontrol_new wm8994_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
   WM8994_AIF1_ADC2_RIGHT_VOLUME,
   1, 119, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
   WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),

SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),

WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),

SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
};

static const struct snd_kcontrol_new wm8994_eq_controls[] = {
SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC1 EQ2 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 6, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC1 EQ3 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 1, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC1 EQ4 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 11, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC1 EQ5 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 6, 31, 0,
        eq_tlv),

SOC_SINGLE_TLV("AIF1DAC2 EQ1 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 11, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC2 EQ2 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 6, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC2 EQ3 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 1, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC2 EQ4 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 11, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF1DAC2 EQ5 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 6, 31, 0,
        eq_tlv),

SOC_SINGLE_TLV("AIF2 EQ1 Volume", WM8994_AIF2_EQ_GAINS_1, 11, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF2 EQ2 Volume", WM8994_AIF2_EQ_GAINS_1, 6, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF2 EQ3 Volume", WM8994_AIF2_EQ_GAINS_1, 1, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF2 EQ4 Volume", WM8994_AIF2_EQ_GAINS_2, 11, 31, 0,
        eq_tlv),
SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
        eq_tlv),
};

static const struct snd_kcontrol_new wm8994_drc_controls[] = {
SND_SOC_BYTES_MASK("AIF1.1 DRC", WM8994_AIF1_DRC1_1, 5,
     WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
     WM8994_AIF1ADC1R_DRC_ENA),
SND_SOC_BYTES_MASK("AIF1.2 DRC", WM8994_AIF1_DRC2_1, 5,
     WM8994_AIF1DAC2_DRC_ENA | WM8994_AIF1ADC2L_DRC_ENA |
     WM8994_AIF1ADC2R_DRC_ENA),
SND_SOC_BYTES_MASK("AIF2 DRC", WM8994_AIF2_DRC_1, 5,
     WM8994_AIF2DAC_DRC_ENA | WM8994_AIF2ADCL_DRC_ENA |
     WM8994_AIF2ADCR_DRC_ENA),
};

static const char *wm8958_ng_text[] = {
 "30ms""125ms""250ms""500ms",
};

static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold,
       WM8958_AIF1_DAC1_NOISE_GATE,
       WM8958_AIF1DAC1_NG_THR_SHIFT,
       wm8958_ng_text);

static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold,
       WM8958_AIF1_DAC2_NOISE_GATE,
       WM8958_AIF1DAC2_NG_THR_SHIFT,
       wm8958_ng_text);

static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold,
       WM8958_AIF2_DAC_NOISE_GATE,
       WM8958_AIF2DAC_NG_THR_SHIFT,
       wm8958_ng_text);

static const struct snd_kcontrol_new wm8958_snd_controls[] = {
SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),

SOC_SINGLE("AIF1DAC1 Noise Gate Switch", WM8958_AIF1_DAC1_NOISE_GATE,
    WM8958_AIF1DAC1_NG_ENA_SHIFT, 1, 0),
SOC_ENUM("AIF1DAC1 Noise Gate Hold Time", wm8958_aif1dac1_ng_hold),
SOC_SINGLE_TLV("AIF1DAC1 Noise Gate Threshold Volume",
        WM8958_AIF1_DAC1_NOISE_GATE, WM8958_AIF1DAC1_NG_THR_SHIFT,
        7, 1, ng_tlv),

SOC_SINGLE("AIF1DAC2 Noise Gate Switch", WM8958_AIF1_DAC2_NOISE_GATE,
    WM8958_AIF1DAC2_NG_ENA_SHIFT, 1, 0),
SOC_ENUM("AIF1DAC2 Noise Gate Hold Time", wm8958_aif1dac2_ng_hold),
SOC_SINGLE_TLV("AIF1DAC2 Noise Gate Threshold Volume",
        WM8958_AIF1_DAC2_NOISE_GATE, WM8958_AIF1DAC2_NG_THR_SHIFT,
        7, 1, ng_tlv),

SOC_SINGLE("AIF2DAC Noise Gate Switch", WM8958_AIF2_DAC_NOISE_GATE,
    WM8958_AIF2DAC_NG_ENA_SHIFT, 1, 0),
SOC_ENUM("AIF2DAC Noise Gate Hold Time", wm8958_aif2dac_ng_hold),
SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume",
        WM8958_AIF2_DAC_NOISE_GATE, WM8958_AIF2DAC_NG_THR_SHIFT,
        7, 1, ng_tlv),
};

/* We run all mode setting through a function to enforce audio mode */
static void wm1811_jackdet_set_mode(struct snd_soc_component *component, u16 mode)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 if (!wm8994->jackdet || !wm8994->micdet[0].jack)
  return;

 if (wm8994->active_refcount)
  mode = WM1811_JACKDET_MODE_AUDIO;

 if (mode == wm8994->jackdet_mode)
  return;

 wm8994->jackdet_mode = mode;

 /* Always use audio mode to detect while the system is active */
 if (mode != WM1811_JACKDET_MODE_NONE)
  mode = WM1811_JACKDET_MODE_AUDIO;

 snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
       WM1811_JACKDET_MODE_MASK, mode);
}

static void active_reference(struct snd_soc_component *component)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 mutex_lock(&wm8994->accdet_lock);

 wm8994->active_refcount++;

 dev_dbg(component->dev, "Active refcount incremented, now %d\n",
  wm8994->active_refcount);

 /* If we're using jack detection go into audio mode */
 wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO);

 mutex_unlock(&wm8994->accdet_lock);
}

static void active_dereference(struct snd_soc_component *component)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 u16 mode;

 mutex_lock(&wm8994->accdet_lock);

 wm8994->active_refcount--;

 dev_dbg(component->dev, "Active refcount decremented, now %d\n",
  wm8994->active_refcount);

 if (wm8994->active_refcount == 0) {
  /* Go into appropriate detection only mode */
  if (wm8994->jack_mic || wm8994->mic_detecting)
   mode = WM1811_JACKDET_MODE_MIC;
  else
   mode = WM1811_JACKDET_MODE_JACK;

  wm1811_jackdet_set_mode(component, mode);
 }

 mutex_unlock(&wm8994->accdet_lock);
}

static int clk_sys_event(struct snd_soc_dapm_widget *w,
    struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  return configure_clock(component);

 case SND_SOC_DAPM_POST_PMU:
  /*
 * JACKDET won't run until we start the clock and it
 * only reports deltas, make sure we notify the state
 * up the stack on startup.  Use a *very* generous
 * timeout for paranoia, there's no urgency and we
 * don't want false reports.
 */

  if (wm8994->jackdet && !wm8994->clk_has_run) {
   queue_delayed_work(system_power_efficient_wq,
        &wm8994->jackdet_bootstrap,
        msecs_to_jiffies(1000));
   wm8994->clk_has_run = true;
  }
  break;

 case SND_SOC_DAPM_POST_PMD:
  configure_clock(component);
  break;
 }

 return 0;
}

static void vmid_reference(struct snd_soc_component *component)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 pm_runtime_get_sync(component->dev);

 wm8994->vmid_refcount++;

 dev_dbg(component->dev, "Referencing VMID, refcount is now %d\n",
  wm8994->vmid_refcount);

 if (wm8994->vmid_refcount == 1) {
  snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
        WM8994_LINEOUT1_DISCH |
        WM8994_LINEOUT2_DISCH, 0);

  wm_hubs_vmid_ena(component);

  switch (wm8994->vmid_mode) {
  default:
   WARN_ON(NULL == "Invalid VMID mode");
   fallthrough;
  case WM8994_VMID_NORMAL:
   /* Startup bias, VMID ramp & buffer */
   snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
         WM8994_BIAS_SRC |
         WM8994_VMID_DISCH |
         WM8994_STARTUP_BIAS_ENA |
         WM8994_VMID_BUF_ENA |
         WM8994_VMID_RAMP_MASK,
         WM8994_BIAS_SRC |
         WM8994_STARTUP_BIAS_ENA |
         WM8994_VMID_BUF_ENA |
         (0x2 << WM8994_VMID_RAMP_SHIFT));

   /* Main bias enable, VMID=2x40k */
   snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
         WM8994_BIAS_ENA |
         WM8994_VMID_SEL_MASK,
         WM8994_BIAS_ENA | 0x2);

   msleep(300);

   snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
         WM8994_VMID_RAMP_MASK |
         WM8994_BIAS_SRC,
         0);
   break;

  case WM8994_VMID_FORCE:
   /* Startup bias, slow VMID ramp & buffer */
   snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
         WM8994_BIAS_SRC |
         WM8994_VMID_DISCH |
         WM8994_STARTUP_BIAS_ENA |
         WM8994_VMID_BUF_ENA |
         WM8994_VMID_RAMP_MASK,
         WM8994_BIAS_SRC |
         WM8994_STARTUP_BIAS_ENA |
         WM8994_VMID_BUF_ENA |
         (0x2 << WM8994_VMID_RAMP_SHIFT));

   /* Main bias enable, VMID=2x40k */
   snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
         WM8994_BIAS_ENA |
         WM8994_VMID_SEL_MASK,
         WM8994_BIAS_ENA | 0x2);

   msleep(400);

   snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
         WM8994_VMID_RAMP_MASK |
         WM8994_BIAS_SRC,
         0);
   break;
  }
 }
}

static void vmid_dereference(struct snd_soc_component *component)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 wm8994->vmid_refcount--;

 dev_dbg(component->dev, "Dereferencing VMID, refcount is now %d\n",
  wm8994->vmid_refcount);

 if (wm8994->vmid_refcount == 0) {
  if (wm8994->hubs.lineout1_se)
   snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
         WM8994_LINEOUT1N_ENA |
         WM8994_LINEOUT1P_ENA,
         WM8994_LINEOUT1N_ENA |
         WM8994_LINEOUT1P_ENA);

  if (wm8994->hubs.lineout2_se)
   snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
         WM8994_LINEOUT2N_ENA |
         WM8994_LINEOUT2P_ENA,
         WM8994_LINEOUT2N_ENA |
         WM8994_LINEOUT2P_ENA);

  /* Start discharging VMID */
  snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
        WM8994_BIAS_SRC |
        WM8994_VMID_DISCH,
        WM8994_BIAS_SRC |
        WM8994_VMID_DISCH);

  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
        WM8994_VMID_SEL_MASK, 0);

  msleep(400);

  /* Active discharge */
  snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
        WM8994_LINEOUT1_DISCH |
        WM8994_LINEOUT2_DISCH,
        WM8994_LINEOUT1_DISCH |
        WM8994_LINEOUT2_DISCH);

  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
        WM8994_LINEOUT1N_ENA |
        WM8994_LINEOUT1P_ENA |
        WM8994_LINEOUT2N_ENA |
        WM8994_LINEOUT2P_ENA, 0);

  /* Switch off startup biases */
  snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
        WM8994_BIAS_SRC |
        WM8994_STARTUP_BIAS_ENA |
        WM8994_VMID_BUF_ENA |
        WM8994_VMID_RAMP_MASK, 0);

  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
        WM8994_VMID_SEL_MASK, 0);
 }

 pm_runtime_put(component->dev);
}

static int vmid_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  vmid_reference(component);
  break;

 case SND_SOC_DAPM_POST_PMD:
  vmid_dereference(component);
  break;
 }

 return 0;
}

static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
{
 int source = 0;  /* GCC flow analysis can't track enable */
 int reg, reg_r;

 /* We also need the same AIF source for L/R and only one path */
 reg = snd_soc_component_read(component, WM8994_DAC1_LEFT_MIXER_ROUTING);
 switch (reg) {
 case WM8994_AIF2DACL_TO_DAC1L:
  dev_vdbg(component->dev, "Class W source AIF2DAC\n");
  source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT;
  break;
 case WM8994_AIF1DAC2L_TO_DAC1L:
  dev_vdbg(component->dev, "Class W source AIF1DAC2\n");
  source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT;
  break;
 case WM8994_AIF1DAC1L_TO_DAC1L:
  dev_vdbg(component->dev, "Class W source AIF1DAC1\n");
  source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT;
  break;
 default:
  dev_vdbg(component->dev, "DAC mixer setting: %x\n", reg);
  return false;
 }

 reg_r = snd_soc_component_read(component, WM8994_DAC1_RIGHT_MIXER_ROUTING);
 if (reg_r != reg) {
  dev_vdbg(component->dev, "Left and right DAC mixers different\n");
  return false;
 }

 /* Set the source up */
 snd_soc_component_update_bits(component, WM8994_CLASS_W_1,
       WM8994_CP_DYN_SRC_SEL_MASK, source);

 return true;
}

static void wm8994_update_vu_bits(struct snd_soc_component *component)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 int i;

 for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
  snd_soc_component_write(component, wm8994_vu_bits[i].reg,
     snd_soc_component_read(component,
             wm8994_vu_bits[i].reg));
 if (control->type == WM1811)
  return;

 for (i = 0; i < ARRAY_SIZE(wm8994_adc2_dac2_vu_bits); i++)
  snd_soc_component_write(component,
    wm8994_adc2_dac2_vu_bits[i].reg,
    snd_soc_component_read(component,
     wm8994_adc2_dac2_vu_bits[i].reg));
}

static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enable)
{
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 unsigned int offset, val, clk_idx;
 int ret;

 if (aif)
  offset = 4;
 else
  offset = 0;

 val = snd_soc_component_read(component, WM8994_AIF1_CLOCKING_1 + offset);
 val &= WM8994_AIF1CLK_SRC_MASK;

 switch (val) {
 case 0:
  clk_idx = WM8994_MCLK1;
  break;
 case 1:
  clk_idx = WM8994_MCLK2;
  break;
 default:
  return 0;
 }

 if (enable) {
  ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
  if (ret < 0) {
   dev_err(component->dev, "Failed to enable MCLK%d\n",
    clk_idx);
   return ret;
  }
 } else {
  clk_disable_unprepare(wm8994->mclk[clk_idx].clk);
 }

 return 0;
}

static int aif1clk_ev(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 struct wm8994 *control = wm8994->wm8994;
 int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
 int ret;
 int dac;
 int adc;
 int val;

 switch (control->type) {
 case WM8994:
 case WM8958:
  mask |= WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA;
  break;
 default:
  break;
 }

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  ret = aif_mclk_set(component, 0, true);
  if (ret < 0)
   return ret;

  /* Don't enable timeslot 2 if not in use */
  if (wm8994->channels[0] <= 2)
   mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);

  val = snd_soc_component_read(component, WM8994_AIF1_CONTROL_1);
  if ((val & WM8994_AIF1ADCL_SRC) &&
      (val & WM8994_AIF1ADCR_SRC))
   adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA;
  else if (!(val & WM8994_AIF1ADCL_SRC) &&
    !(val & WM8994_AIF1ADCR_SRC))
   adc = WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;
  else
   adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA |
    WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;

  val = snd_soc_component_read(component, WM8994_AIF1_CONTROL_2);
  if ((val & WM8994_AIF1DACL_SRC) &&
      (val & WM8994_AIF1DACR_SRC))
   dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA;
  else if (!(val & WM8994_AIF1DACL_SRC) &&
    !(val & WM8994_AIF1DACR_SRC))
   dac = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;
  else
   dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA |
    WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;

  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
        mask, adc);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
        mask, dac);
  snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
        WM8994_AIF1DSPCLK_ENA |
        WM8994_SYSDSPCLK_ENA,
        WM8994_AIF1DSPCLK_ENA |
        WM8994_SYSDSPCLK_ENA);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4, mask,
        WM8994_AIF1ADC1R_ENA |
        WM8994_AIF1ADC1L_ENA |
        WM8994_AIF1ADC2R_ENA |
        WM8994_AIF1ADC2L_ENA);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5, mask,
        WM8994_AIF1DAC1R_ENA |
        WM8994_AIF1DAC1L_ENA |
        WM8994_AIF1DAC2R_ENA |
        WM8994_AIF1DAC2L_ENA);
  break;

 case SND_SOC_DAPM_POST_PMU:
  wm8994_update_vu_bits(component);
  break;

 case SND_SOC_DAPM_PRE_PMD:
 case SND_SOC_DAPM_POST_PMD:
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
        mask, 0);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
        mask, 0);

  val = snd_soc_component_read(component, WM8994_CLOCKING_1);
  if (val & WM8994_AIF2DSPCLK_ENA)
   val = WM8994_SYSDSPCLK_ENA;
  else
   val = 0;
  snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
        WM8994_SYSDSPCLK_ENA |
        WM8994_AIF1DSPCLK_ENA, val);
  break;
 }

 switch (event) {
 case SND_SOC_DAPM_POST_PMD:
  aif_mclk_set(component, 0, false);
  break;
 }

 return 0;
}

static int aif2clk_ev(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 int ret;
 int dac;
 int adc;
 int val;

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  ret = aif_mclk_set(component, 1, true);
  if (ret < 0)
   return ret;

  val = snd_soc_component_read(component, WM8994_AIF2_CONTROL_1);
  if ((val & WM8994_AIF2ADCL_SRC) &&
      (val & WM8994_AIF2ADCR_SRC))
   adc = WM8994_AIF2ADCR_ENA;
  else if (!(val & WM8994_AIF2ADCL_SRC) &&
    !(val & WM8994_AIF2ADCR_SRC))
   adc = WM8994_AIF2ADCL_ENA;
  else
   adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA;


  val = snd_soc_component_read(component, WM8994_AIF2_CONTROL_2);
  if ((val & WM8994_AIF2DACL_SRC) &&
      (val & WM8994_AIF2DACR_SRC))
   dac = WM8994_AIF2DACR_ENA;
  else if (!(val & WM8994_AIF2DACL_SRC) &&
    !(val & WM8994_AIF2DACR_SRC))
   dac = WM8994_AIF2DACL_ENA;
  else
   dac = WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA;

  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
        WM8994_AIF2ADCL_ENA |
        WM8994_AIF2ADCR_ENA, adc);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
        WM8994_AIF2DACL_ENA |
        WM8994_AIF2DACR_ENA, dac);
  snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
        WM8994_AIF2DSPCLK_ENA |
        WM8994_SYSDSPCLK_ENA,
        WM8994_AIF2DSPCLK_ENA |
        WM8994_SYSDSPCLK_ENA);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
        WM8994_AIF2ADCL_ENA |
        WM8994_AIF2ADCR_ENA,
        WM8994_AIF2ADCL_ENA |
        WM8994_AIF2ADCR_ENA);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
        WM8994_AIF2DACL_ENA |
        WM8994_AIF2DACR_ENA,
        WM8994_AIF2DACL_ENA |
        WM8994_AIF2DACR_ENA);
  break;

 case SND_SOC_DAPM_POST_PMU:
  wm8994_update_vu_bits(component);
  break;

 case SND_SOC_DAPM_PRE_PMD:
 case SND_SOC_DAPM_POST_PMD:
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
        WM8994_AIF2DACL_ENA |
        WM8994_AIF2DACR_ENA, 0);
  snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
        WM8994_AIF2ADCL_ENA |
        WM8994_AIF2ADCR_ENA, 0);

  val = snd_soc_component_read(component, WM8994_CLOCKING_1);
  if (val & WM8994_AIF1DSPCLK_ENA)
   val = WM8994_SYSDSPCLK_ENA;
  else
   val = 0;
  snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
        WM8994_SYSDSPCLK_ENA |
        WM8994_AIF2DSPCLK_ENA, val);
  break;
 }

 switch (event) {
 case SND_SOC_DAPM_POST_PMD:
  aif_mclk_set(component, 1, false);
  break;
 }

 return 0;
}

static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
      struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  wm8994->aif1clk_enable = 1;
  break;
 case SND_SOC_DAPM_POST_PMD:
  wm8994->aif1clk_disable = 1;
  break;
 }

 return 0;
}

static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
      struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  wm8994->aif2clk_enable = 1;
  break;
 case SND_SOC_DAPM_POST_PMD:
  wm8994->aif2clk_disable = 1;
  break;
 }

 return 0;
}

static int late_enable_ev(struct snd_soc_dapm_widget *w,
     struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 switch (event) {
 case SND_SOC_DAPM_PRE_PMU:
  if (wm8994->aif1clk_enable) {
   aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU);
   snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1,
         WM8994_AIF1CLK_ENA_MASK,
         WM8994_AIF1CLK_ENA);
   aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU);
   wm8994->aif1clk_enable = 0;
  }
  if (wm8994->aif2clk_enable) {
   aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU);
   snd_soc_component_update_bits(component, WM8994_AIF2_CLOCKING_1,
         WM8994_AIF2CLK_ENA_MASK,
         WM8994_AIF2CLK_ENA);
   aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU);
   wm8994->aif2clk_enable = 0;
  }
  break;
 }

 /* We may also have postponed startup of DSP, handle that. */
 wm8958_aif_ev(w, kcontrol, event);

 return 0;
}

static int late_disable_ev(struct snd_soc_dapm_widget *w,
      struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);

 switch (event) {
 case SND_SOC_DAPM_POST_PMD:
  if (wm8994->aif1clk_disable) {
   aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
   snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1,
         WM8994_AIF1CLK_ENA_MASK, 0);
   aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD);
   wm8994->aif1clk_disable = 0;
  }
  if (wm8994->aif2clk_disable) {
   aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
   snd_soc_component_update_bits(component, WM8994_AIF2_CLOCKING_1,
         WM8994_AIF2CLK_ENA_MASK, 0);
   aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD);
   wm8994->aif2clk_disable = 0;
  }
  break;
 }

 return 0;
}

static int adc_mux_ev(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
{
 late_enable_ev(w, kcontrol, event);
 return 0;
}

static int micbias_ev(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
{
 late_enable_ev(w, kcontrol, event);
 return 0;
}

static int dac_ev(struct snd_soc_dapm_widget *w,
    struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 unsigned int mask = 1 << w->shift;

 snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
       mask, mask);
 return 0;
}

static const char *adc_mux_text[] = {
 "ADC",
 "DMIC",
};

static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);

static const struct snd_kcontrol_new adcl_mux =
 SOC_DAPM_ENUM("ADCL Mux", adc_enum);

static const struct snd_kcontrol_new adcr_mux =
 SOC_DAPM_ENUM("ADCR Mux", adc_enum);

static const struct snd_kcontrol_new left_speaker_mixer[] = {
SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0),
SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 7, 1, 0),
SOC_DAPM_SINGLE("IN1LP Switch", WM8994_SPEAKER_MIXER, 5, 1, 0),
SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 3, 1, 0),
SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 1, 1, 0),
};

static const struct snd_kcontrol_new right_speaker_mixer[] = {
SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 8, 1, 0),
SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 6, 1, 0),
SOC_DAPM_SINGLE("IN1RP Switch", WM8994_SPEAKER_MIXER, 4, 1, 0),
SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 2, 1, 0),
SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
};

/* Debugging; dump chip status after DAPM transitions */
static int post_ev(struct snd_soc_dapm_widget *w,
     struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 dev_dbg(component->dev, "SRC status: %x\n",
  snd_soc_component_read(component,
        WM8994_RATE_STATUS));
 return 0;
}

static const struct snd_kcontrol_new aif1adc1l_mix[] = {
SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING,
  1, 1, 0),
SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING,
  0, 1, 0),
};

static const struct snd_kcontrol_new aif1adc1r_mix[] = {
SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
  1, 1, 0),
SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
  0, 1, 0),
};

static const struct snd_kcontrol_new aif1adc2l_mix[] = {
SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
  1, 1, 0),
SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
  0, 1, 0),
};

static const struct snd_kcontrol_new aif1adc2r_mix[] = {
SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
  1, 1, 0),
SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
  0, 1, 0),
};

static const struct snd_kcontrol_new aif2dac2l_mix[] = {
SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
  5, 1, 0),
SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
  4, 1, 0),
SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
  2, 1, 0),
SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
  1, 1, 0),
SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
  0, 1, 0),
};

static const struct snd_kcontrol_new aif2dac2r_mix[] = {
SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
  5, 1, 0),
SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
  4, 1, 0),
SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
  2, 1, 0),
SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
  1, 1, 0),
SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
  0, 1, 0),
};

#define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
 SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
  snd_soc_dapm_get_volsw, wm8994_put_class_w)

static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
         struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
 int ret;

 ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);

 wm_hubs_update_class_w(component);

 return ret;
}

static const struct snd_kcontrol_new dac1l_mix[] = {
WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
        5, 1, 0),
WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
        4, 1, 0),
WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
        2, 1, 0),
WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
        1, 1, 0),
WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
        0, 1, 0),
};

static const struct snd_kcontrol_new dac1r_mix[] = {
WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
        5, 1, 0),
WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
        4, 1, 0),
WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
        2, 1, 0),
WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
        1, 1, 0),
WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
        0, 1, 0),
};

static const char *sidetone_text[] = {
 "ADC/DMIC1""DMIC2",
};

static SOC_ENUM_SINGLE_DECL(sidetone1_enum,
       WM8994_SIDETONE, 0, sidetone_text);

static const struct snd_kcontrol_new sidetone1_mux =
 SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);

static SOC_ENUM_SINGLE_DECL(sidetone2_enum,
       WM8994_SIDETONE, 1, sidetone_text);

static const struct snd_kcontrol_new sidetone2_mux =
 SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);

static const char *aif1dac_text[] = {
 "AIF1DACDAT""AIF3DACDAT",
};

static const char *loopback_text[] = {
 "None""ADCDAT",
};

static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum,
       WM8994_AIF1_CONTROL_2,
       WM8994_AIF1_LOOPBACK_SHIFT,
       loopback_text);

static const struct snd_kcontrol_new aif1_loopback =
 SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);

static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum,
       WM8994_AIF2_CONTROL_2,
       WM8994_AIF2_LOOPBACK_SHIFT,
       loopback_text);

static const struct snd_kcontrol_new aif2_loopback =
 SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);

static SOC_ENUM_SINGLE_DECL(aif1dac_enum,
       WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);

static const struct snd_kcontrol_new aif1dac_mux =
 SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum);

static const char *aif2dac_text[] = {
 "AIF2DACDAT""AIF3DACDAT",
};

static SOC_ENUM_SINGLE_DECL(aif2dac_enum,
       WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);

static const struct snd_kcontrol_new aif2dac_mux =
 SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum);

static const char *aif2adc_text[] = {
 "AIF2ADCDAT""AIF3DACDAT",
};

static SOC_ENUM_SINGLE_DECL(aif2adc_enum,
       WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);

static const struct snd_kcontrol_new aif2adc_mux =
 SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);

static const char *aif3adc_text[] = {
 "AIF1ADCDAT""AIF2ADCDAT""AIF2DACDAT""Mono PCM",
};

static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum,
       WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);

static const struct snd_kcontrol_new wm8994_aif3adc_mux =
 SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum);

static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum,
       WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);

static const struct snd_kcontrol_new wm8958_aif3adc_mux =
 SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);

static const char *mono_pcm_out_text[] = {
 "None""AIF2ADCL""AIF2ADCR",
};

static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum,
       WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);

static const struct snd_kcontrol_new mono_pcm_out_mux =
 SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum);

static const char *aif2dac_src_text[] = {
 "AIF2""AIF3",
};

/* Note that these two control shouldn't be simultaneously switched to AIF3 */
static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum,
       WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);

static const struct snd_kcontrol_new aif2dacl_src_mux =
 SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum);

static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum,
       WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);

static const struct snd_kcontrol_new aif2dacr_src_mux =
 SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);

static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] = {
SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_late_ev,
 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_late_ev,
 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),

SND_SOC_DAPM_PGA_E("Late DAC1L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_PGA_E("Late DAC1R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0,
 late_enable_ev, SND_SOC_DAPM_PRE_PMU),

SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
       left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer),
       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
       right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux,
     late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux,
     late_enable_ev, SND_SOC_DAPM_PRE_PMU),

SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
};

static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev,
      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
      SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev,
      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
      SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
     left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
     right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
};

static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
SND_SOC_DAPM_DAC_E("DAC2L", NULL, SND_SOC_NOPM, 3, 0,
 dac_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_DAC_E("DAC2R", NULL, SND_SOC_NOPM, 2, 0,
 dac_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_DAC_E("DAC1L", NULL, SND_SOC_NOPM, 1, 0,
 dac_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_DAC_E("DAC1R", NULL, SND_SOC_NOPM, 0, 0,
 dac_ev, SND_SOC_DAPM_PRE_PMU),
};

static const struct snd_soc_dapm_widget wm8994_dac_widgets[] = {
SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0),
SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0),
SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
};

static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = {
SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
   adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
   adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
};

static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = {
SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
};

static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("DMIC1DAT"),
SND_SOC_DAPM_INPUT("DMIC2DAT"),
SND_SOC_DAPM_INPUT("Clock"),

SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev,
        SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),

SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
      SND_SOC_DAPM_PRE_PMD),

SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DSPINTCLK", SND_SOC_NOPM, 1, 0, NULL, 0),

SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL,
       0, SND_SOC_NOPM, 9, 0),
SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL,
       0, SND_SOC_NOPM, 8, 0),
SND_SOC_DAPM_AIF_IN_E("AIF1DAC1L", NULL, 0,
        SND_SOC_NOPM, 9, 0, wm8958_aif_ev,
        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_AIF_IN_E("AIF1DAC1R", NULL, 0,
        SND_SOC_NOPM, 8, 0, wm8958_aif_ev,
        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", NULL,
       0, SND_SOC_NOPM, 11, 0),
SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", NULL,
       0, SND_SOC_NOPM, 10, 0),
SND_SOC_DAPM_AIF_IN_E("AIF1DAC2L", NULL, 0,
        SND_SOC_NOPM, 11, 0, wm8958_aif_ev,
        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_AIF_IN_E("AIF1DAC2R", NULL, 0,
        SND_SOC_NOPM, 10, 0, wm8958_aif_ev,
        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
     aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)),
SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
     aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),

SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0,
     aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)),
SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0,
     aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)),

SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
     aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
     aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)),

SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux),
SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux),

SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
     dac1l_mix, ARRAY_SIZE(dac1l_mix)),
SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
     dac1r_mix, ARRAY_SIZE(dac1r_mix)),

SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0,
       SND_SOC_NOPM, 13, 0),
SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0,
       SND_SOC_NOPM, 12, 0),
SND_SOC_DAPM_AIF_IN_E("AIF2DACL", NULL, 0,
        SND_SOC_NOPM, 13, 0, wm8958_aif_ev,
        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0,
        SND_SOC_NOPM, 12, 0, wm8958_aif_ev,
        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),

SND_SOC_DAPM_AIF_IN("AIF1DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIF2DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT",  NULL, 0, SND_SOC_NOPM, 0, 0),

SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux),
SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),

SND_SOC_DAPM_AIF_IN("AIF3DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),

SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),

SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8994_POWER_MANAGEMENT_4, 5, 0),
SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8994_POWER_MANAGEMENT_4, 4, 0),
SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8994_POWER_MANAGEMENT_4, 3, 0),
SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),

/* Power is done with the muxes since the ADC power also controls the
 * downsampling chain, the chip will automatically manage the analogue
 * specific portions.
 */

SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),

SND_SOC_DAPM_MUX("AIF1 Loopback", SND_SOC_NOPM, 0, 0, &aif1_loopback),
SND_SOC_DAPM_MUX("AIF2 Loopback", SND_SOC_NOPM, 0, 0, &aif2_loopback),

SND_SOC_DAPM_POST("Debug log", post_ev),
};

static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = {
SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux),
};

static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0),
SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8958_aif3adc_mux),
};

static const struct snd_soc_dapm_route intercon[] = {
 { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys },
 { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys },

 { "DSP1CLK", NULL, "CLK_SYS" },
 { "DSP2CLK", NULL, "CLK_SYS" },
 { "DSPINTCLK", NULL, "CLK_SYS" },

 { "AIF1ADC1L", NULL, "AIF1CLK" },
 { "AIF1ADC1L", NULL, "DSP1CLK" },
 { "AIF1ADC1R", NULL, "AIF1CLK" },
 { "AIF1ADC1R", NULL, "DSP1CLK" },
 { "AIF1ADC1R", NULL, "DSPINTCLK" },

 { "AIF1DAC1L", NULL, "AIF1CLK" },
 { "AIF1DAC1L", NULL, "DSP1CLK" },
 { "AIF1DAC1R", NULL, "AIF1CLK" },
 { "AIF1DAC1R", NULL, "DSP1CLK" },
 { "AIF1DAC1R", NULL, "DSPINTCLK" },

 { "AIF1ADC2L", NULL, "AIF1CLK" },
 { "AIF1ADC2L", NULL, "DSP1CLK" },
 { "AIF1ADC2R", NULL, "AIF1CLK" },
 { "AIF1ADC2R", NULL, "DSP1CLK" },
 { "AIF1ADC2R", NULL, "DSPINTCLK" },

 { "AIF1DAC2L", NULL, "AIF1CLK" },
 { "AIF1DAC2L", NULL, "DSP1CLK" },
 { "AIF1DAC2R", NULL, "AIF1CLK" },
 { "AIF1DAC2R", NULL, "DSP1CLK" },
 { "AIF1DAC2R", NULL, "DSPINTCLK" },

 { "AIF2ADCL", NULL, "AIF2CLK" },
 { "AIF2ADCL", NULL, "DSP2CLK" },
 { "AIF2ADCR", NULL, "AIF2CLK" },
 { "AIF2ADCR", NULL, "DSP2CLK" },
 { "AIF2ADCR", NULL, "DSPINTCLK" },

 { "AIF2DACL", NULL, "AIF2CLK" },
 { "AIF2DACL", NULL, "DSP2CLK" },
 { "AIF2DACR", NULL, "AIF2CLK" },
 { "AIF2DACR", NULL, "DSP2CLK" },
 { "AIF2DACR", NULL, "DSPINTCLK" },

 { "DMIC1L", NULL, "DMIC1DAT" },
 { "DMIC1L", NULL, "CLK_SYS" },
 { "DMIC1R", NULL, "DMIC1DAT" },
 { "DMIC1R", NULL, "CLK_SYS" },
 { "DMIC2L", NULL, "DMIC2DAT" },
 { "DMIC2L", NULL, "CLK_SYS" },
 { "DMIC2R", NULL, "DMIC2DAT" },
 { "DMIC2R", NULL, "CLK_SYS" },

 { "ADCL", NULL, "AIF1CLK" },
 { "ADCL", NULL, "DSP1CLK" },
 { "ADCL", NULL, "DSPINTCLK" },

 { "ADCR", NULL, "AIF1CLK" },
 { "ADCR", NULL, "DSP1CLK" },
 { "ADCR", NULL, "DSPINTCLK" },

 { "ADCL Mux""ADC""ADCL" },
 { "ADCL Mux""DMIC""DMIC1L" },
 { "ADCR Mux""ADC""ADCR" },
 { "ADCR Mux""DMIC""DMIC1R" },

 { "DAC1L", NULL, "AIF1CLK" },
 { "DAC1L", NULL, "DSP1CLK" },
 { "DAC1L", NULL, "DSPINTCLK" },

 { "DAC1R", NULL, "AIF1CLK" },
 { "DAC1R", NULL, "DSP1CLK" },
 { "DAC1R", NULL, "DSPINTCLK" },

 { "DAC2L", NULL, "AIF2CLK" },
 { "DAC2L", NULL, "DSP2CLK" },
 { "DAC2L", NULL, "DSPINTCLK" },

 { "DAC2R", NULL, "AIF2DACR" },
 { "DAC2R", NULL, "AIF2CLK" },
 { "DAC2R", NULL, "DSP2CLK" },
 { "DAC2R", NULL, "DSPINTCLK" },

 { "TOCLK", NULL, "CLK_SYS" },

 { "AIF1DACDAT", NULL, "AIF1 Playback" },
 { "AIF2DACDAT", NULL, "AIF2 Playback" },
 { "AIF3DACDAT", NULL, "AIF3 Playback" },

 { "AIF1 Capture", NULL, "AIF1ADCDAT" },
 { "AIF2 Capture", NULL, "AIF2ADCDAT" },
 { "AIF3 Capture", NULL, "AIF3ADCDAT" },

 /* AIF1 outputs */
 { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" },
 { "AIF1ADC1L Mixer""ADC/DMIC Switch""ADCL Mux" },
 { "AIF1ADC1L Mixer""AIF2 Switch""AIF2DACL" },

 { "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" },
 { "AIF1ADC1R Mixer""ADC/DMIC Switch""ADCR Mux" },
 { "AIF1ADC1R Mixer""AIF2 Switch""AIF2DACR" },

 { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" },
 { "AIF1ADC2L Mixer""DMIC Switch""DMIC2L" },
 { "AIF1ADC2L Mixer""AIF2 Switch""AIF2DACL" },

 { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" },
 { "AIF1ADC2R Mixer""DMIC Switch""DMIC2R" },
 { "AIF1ADC2R Mixer""AIF2 Switch""AIF2DACR" },

 /* Pin level routing for AIF3 */
 { "AIF1DAC1L", NULL, "AIF1DAC Mux" },
 { "AIF1DAC1R", NULL, "AIF1DAC Mux" },
 { "AIF1DAC2L", NULL, "AIF1DAC Mux" },
 { "AIF1DAC2R", NULL, "AIF1DAC Mux" },

 { "AIF1DAC Mux""AIF1DACDAT""AIF1 Loopback" },
 { "AIF1DAC Mux""AIF3DACDAT""AIF3DACDAT" },
 { "AIF2DAC Mux""AIF2DACDAT""AIF2 Loopback" },
 { "AIF2DAC Mux""AIF3DACDAT""AIF3DACDAT" },
 { "AIF2ADC Mux""AIF2ADCDAT""AIF2ADCL" },
 { "AIF2ADC Mux""AIF2ADCDAT""AIF2ADCR" },
 { "AIF2ADC Mux""AIF3DACDAT""AIF3ADCDAT" },

 /* DAC1 inputs */
 { "DAC1L Mixer""AIF2 Switch""AIF2DACL" },
 { "DAC1L Mixer""AIF1.2 Switch""AIF1DAC2L" },
 { "DAC1L Mixer""AIF1.1 Switch""AIF1DAC1L" },
 { "DAC1L Mixer""Left Sidetone Switch""Left Sidetone" },
 { "DAC1L Mixer""Right Sidetone Switch""Right Sidetone" },

 { "DAC1R Mixer""AIF2 Switch""AIF2DACR" },
 { "DAC1R Mixer""AIF1.2 Switch""AIF1DAC2R" },
 { "DAC1R Mixer""AIF1.1 Switch""AIF1DAC1R" },
 { "DAC1R Mixer""Left Sidetone Switch""Left Sidetone" },
 { "DAC1R Mixer""Right Sidetone Switch""Right Sidetone" },

 /* DAC2/AIF2 outputs  */
 { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" },
 { "AIF2DAC2L Mixer""AIF2 Switch""AIF2DACL" },
 { "AIF2DAC2L Mixer""AIF1.2 Switch""AIF1DAC2L" },
 { "AIF2DAC2L Mixer""AIF1.1 Switch""AIF1DAC1L" },
 { "AIF2DAC2L Mixer""Left Sidetone Switch""Left Sidetone" },
 { "AIF2DAC2L Mixer""Right Sidetone Switch""Right Sidetone" },

 { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" },
 { "AIF2DAC2R Mixer""AIF2 Switch""AIF2DACR" },
 { "AIF2DAC2R Mixer""AIF1.2 Switch""AIF1DAC2R" },
 { "AIF2DAC2R Mixer""AIF1.1 Switch""AIF1DAC1R" },
 { "AIF2DAC2R Mixer""Left Sidetone Switch""Left Sidetone" },
 { "AIF2DAC2R Mixer""Right Sidetone Switch""Right Sidetone" },

 { "AIF1ADCDAT", NULL, "AIF1ADC1L" },
 { "AIF1ADCDAT", NULL, "AIF1ADC1R" },
 { "AIF1ADCDAT", NULL, "AIF1ADC2L" },
 { "AIF1ADCDAT", NULL, "AIF1ADC2R" },

 { "AIF2ADCDAT", NULL, "AIF2ADC Mux" },

 /* AIF3 output */
 { "AIF3ADC Mux""AIF1ADCDAT""AIF1ADC1L" },
 { "AIF3ADC Mux""AIF1ADCDAT""AIF1ADC1R" },
 { "AIF3ADC Mux""AIF1ADCDAT""AIF1ADC2L" },
 { "AIF3ADC Mux""AIF1ADCDAT""AIF1ADC2R" },
 { "AIF3ADC Mux""AIF2ADCDAT""AIF2ADCL" },
 { "AIF3ADC Mux""AIF2ADCDAT""AIF2ADCR" },
 { "AIF3ADC Mux""AIF2DACDAT""AIF2DACL" },
 { "AIF3ADC Mux""AIF2DACDAT""AIF2DACR" },

 { "AIF3ADCDAT", NULL, "AIF3ADC Mux" },

 /* Loopback */
 { "AIF1 Loopback""ADCDAT""AIF1ADCDAT" },
 { "AIF1 Loopback""None""AIF1DACDAT" },
 { "AIF2 Loopback""ADCDAT""AIF2ADCDAT" },
 { "AIF2 Loopback""None""AIF2DACDAT" },

 /* Sidetone */
 { "Left Sidetone""ADC/DMIC1""ADCL Mux" },
 { "Left Sidetone""DMIC2""DMIC2L" },
 { "Right Sidetone""ADC/DMIC1""ADCR Mux" },
 { "Right Sidetone""DMIC2""DMIC2R" },

 /* Output stages */
 { "Left Output Mixer""DAC Switch""DAC1L" },
 { "Right Output Mixer""DAC Switch""DAC1R" },

 { "SPKL""DAC1 Switch""DAC1L" },
 { "SPKL""DAC2 Switch""DAC2L" },

 { "SPKR""DAC1 Switch""DAC1R" },
 { "SPKR""DAC2 Switch""DAC2R" },

 { "Left Headphone Mux""DAC""DAC1L" },
 { "Right Headphone Mux""DAC""DAC1R" },
};

static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] = {
 { "DAC1L", NULL, "Late DAC1L Enable PGA" },
 { "Late DAC1L Enable PGA", NULL, "DAC1L Mixer" },
 { "DAC1R", NULL, "Late DAC1R Enable PGA" },
 { "Late DAC1R Enable PGA", NULL, "DAC1R Mixer" },
 { "DAC2L", NULL, "Late DAC2L Enable PGA" },
 { "Late DAC2L Enable PGA", NULL, "AIF2DAC2L Mixer" },
 { "DAC2R", NULL, "Late DAC2R Enable PGA" },
 { "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" }
};

static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = {
 { "DAC1L", NULL, "DAC1L Mixer" },
 { "DAC1R", NULL, "DAC1R Mixer" },
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=99 G=98

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.