Merge remote-tracking branches 'asoc/topic/adau1977', 'asoc/topic/ak4642', 'asoc...
authorMark Brown <broonie@linaro.org>
Mon, 4 Aug 2014 15:31:23 +0000 (16:31 +0100)
committerMark Brown <broonie@linaro.org>
Mon, 4 Aug 2014 15:31:23 +0000 (16:31 +0100)
1  2  3  4  5 
include/linux/mfd/arizona/core.h
sound/soc/codecs/arizona.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8996.c

index 6d9371f88875d49c223f07f42401b1d1ed6f4bde,6d9371f88875d49c223f07f42401b1d1ed6f4bde,6d9371f88875d49c223f07f42401b1d1ed6f4bde,6d9371f88875d49c223f07f42401b1d1ed6f4bde,55926517d50bfd17436334192c3b7b423cdd4125..a614b33d0a3943906c50c608e2046b65a00d7f04
@@@@@@ -110,6 -110,6 -110,6 -110,6 -110,12 +110,12 @@@@@@ struct arizona 
        int clk32k_ref;
     
        struct snd_soc_dapm_context *dapm;
++++ 
++++    int tdm_width[ARIZONA_MAX_AIF];
++++    int tdm_slots[ARIZONA_MAX_AIF];
++++ 
++++    uint16_t dac_comp_coeff;
++++    uint8_t dac_comp_enabled;
     };
     
     int arizona_clk32k_enable(struct arizona *arizona);
@@@@@@ -124,7 -124,7 -124,7 -124,7 -130,4 +130,7 @@@@@@ int wm5102_patch(struct arizona *arizon
     int wm5110_patch(struct arizona *arizona);
     int wm8997_patch(struct arizona *arizona);
     
    +extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
    +                                bool mandatory);
    +
     #endif
index 747c71e59c04ff5811fac358a7b1ee57a0235200,29e198f57d4cd711f56c90fa640c807edbee414a,29e198f57d4cd711f56c90fa640c807edbee414a,29e198f57d4cd711f56c90fa640c807edbee414a,9a730689a0ac4f2a1e7b5d507799a38b189c6d29..2f2e91ac690f683c6f87347b34d4b9cbe11c8038
@@@@@@ -243,31 -243,6 -243,6 -243,6 -243,6 +243,31 @@@@@@ int arizona_init_spk(struct snd_soc_cod
     }
     EXPORT_SYMBOL_GPL(arizona_init_spk);
     
 ++++static const struct snd_soc_dapm_route arizona_mono_routes[] = {
 ++++   { "OUT1R", NULL, "OUT1L" },
 ++++   { "OUT2R", NULL, "OUT2L" },
 ++++   { "OUT3R", NULL, "OUT3L" },
 ++++   { "OUT4R", NULL, "OUT4L" },
 ++++   { "OUT5R", NULL, "OUT5L" },
 ++++   { "OUT6R", NULL, "OUT6L" },
 ++++};
 ++++
 ++++int arizona_init_mono(struct snd_soc_codec *codec)
 ++++{
 ++++   struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 ++++   struct arizona *arizona = priv->arizona;
 ++++   int i;
 ++++
 ++++   for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
 ++++           if (arizona->pdata.out_mono[i])
 ++++                   snd_soc_dapm_add_routes(&codec->dapm,
 ++++                                           &arizona_mono_routes[i], 1);
 ++++   }
 ++++
 ++++   return 0;
 ++++}
 ++++EXPORT_SYMBOL_GPL(arizona_init_mono);
 ++++
     int arizona_init_gpio(struct snd_soc_codec *codec)
     {
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
@@@@@@ -1152,6 -1127,6 -1127,6 -1127,6 -1127,31 +1152,31 @@@@@@ static int arizona_startup(struct snd_p
                                          constraint);
     }
     
++++ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
++++                                    unsigned int rate)
++++ {
++++    struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
++++    struct arizona *arizona = priv->arizona;
++++    struct reg_default dac_comp[] = {
++++            { 0x80, 0x3 },
++++            { ARIZONA_DAC_COMP_1, 0 },
++++            { ARIZONA_DAC_COMP_2, 0 },
++++            { 0x80, 0x0 },
++++    };
++++ 
++++    mutex_lock(&codec->mutex);
++++ 
++++    dac_comp[1].def = arizona->dac_comp_coeff;
++++    if (rate >= 176400)
++++            dac_comp[2].def = arizona->dac_comp_enabled;
++++ 
++++    mutex_unlock(&codec->mutex);
++++ 
++++    regmap_multi_reg_write(arizona->regmap,
++++                           dac_comp,
++++                           ARRAY_SIZE(dac_comp));
++++ }
++++ 
     static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
     
        switch (dai_priv->clk) {
        case ARIZONA_CLK_SYSCLK:
++++            switch (priv->arizona->type) {
++++            case WM5102:
++++                    arizona_wm5102_set_dac_comp(codec,
++++                                                params_rate(params));
++++                    break;
++++            default:
++++                    break;
++++            }
++++ 
                snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
                                    ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
                if (base)
        return 0;
     }
     
++++ static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
++++                                int base, int bclk, int lrclk, int frame)
++++ {
++++    int val;
++++ 
++++    val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
++++    if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
++++            return true;
++++ 
++++    val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
++++    if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
++++            return true;
++++ 
++++    val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
++++    if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
++++                         ARIZONA_AIF1TX_SLOT_LEN_MASK)))
++++            return true;
++++ 
++++    return false;
++++ }
++++ 
     static int arizona_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params,
                             struct snd_soc_dai *dai)
        int base = dai->driver->base;
        const int *rates;
        int i, ret, val;
++++    int channels = params_channels(params);
        int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
++++    int tdm_width = arizona->tdm_width[dai->id - 1];
++++    int tdm_slots = arizona->tdm_slots[dai->id - 1];
        int bclk, lrclk, wl, frame, bclk_target;
++++    bool reconfig;
++++    unsigned int aif_tx_state, aif_rx_state;
     
        if (params_rate(params) % 8000)
                rates = &arizona_44k1_bclk_rates[0];
        else
                rates = &arizona_48k_bclk_rates[0];
     
----    bclk_target = snd_soc_params_to_bclk(params);
----    if (chan_limit && chan_limit < params_channels(params)) {
++++    if (tdm_slots) {
++++            arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
++++                            tdm_slots, tdm_width);
++++            bclk_target = tdm_slots * tdm_width * params_rate(params);
++++            channels = tdm_slots;
++++    } else {
++++            bclk_target = snd_soc_params_to_bclk(params);
++++    }
++++ 
++++    if (chan_limit && chan_limit < channels) {
                arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
----            bclk_target /= params_channels(params);
++++            bclk_target /= channels;
                bclk_target *= chan_limit;
        }
     
----    /* Force stereo for I2S mode */
++++    /* Force multiple of 2 channels for I2S mode */
        val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
----    if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
++++    if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) {
                arizona_aif_dbg(dai, "Forcing stereo mode\n");
----            bclk_target *= 2;
++++            bclk_target /= channels;
++++            bclk_target *= channels + 1;
        }
     
        for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
        wl = snd_pcm_format_width(params_format(params));
        frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
     
++++    reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
++++ 
++++    if (reconfig) {
++++            /* Save AIF TX/RX state */
++++            aif_tx_state = snd_soc_read(codec,
++++                                        base + ARIZONA_AIF_TX_ENABLES);
++++            aif_rx_state = snd_soc_read(codec,
++++                                        base + ARIZONA_AIF_RX_ENABLES);
++++            /* Disable AIF TX/RX before reconfiguring it */
++++            regmap_update_bits_async(arizona->regmap,
++++                                base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
++++            regmap_update_bits(arizona->regmap,
++++                                base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
++++    }
++++ 
        ret = arizona_hw_params_rate(substream, params, dai);
        if (ret != 0)
----            return ret;
++++            goto restore_aif;
     
----    regmap_update_bits_async(arizona->regmap,
----                             base + ARIZONA_AIF_BCLK_CTRL,
----                             ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
----    regmap_update_bits_async(arizona->regmap,
----                             base + ARIZONA_AIF_TX_BCLK_RATE,
----                             ARIZONA_AIF1TX_BCPF_MASK, lrclk);
----    regmap_update_bits_async(arizona->regmap,
----                             base + ARIZONA_AIF_RX_BCLK_RATE,
----                             ARIZONA_AIF1RX_BCPF_MASK, lrclk);
----    regmap_update_bits_async(arizona->regmap,
----                             base + ARIZONA_AIF_FRAME_CTRL_1,
----                             ARIZONA_AIF1TX_WL_MASK |
----                             ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
----    regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
----                       ARIZONA_AIF1RX_WL_MASK |
----                       ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
++++    if (reconfig) {
++++            regmap_update_bits_async(arizona->regmap,
++++                                     base + ARIZONA_AIF_BCLK_CTRL,
++++                                     ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
++++            regmap_update_bits_async(arizona->regmap,
++++                                     base + ARIZONA_AIF_TX_BCLK_RATE,
++++                                     ARIZONA_AIF1TX_BCPF_MASK, lrclk);
++++            regmap_update_bits_async(arizona->regmap,
++++                                     base + ARIZONA_AIF_RX_BCLK_RATE,
++++                                     ARIZONA_AIF1RX_BCPF_MASK, lrclk);
++++            regmap_update_bits_async(arizona->regmap,
++++                                     base + ARIZONA_AIF_FRAME_CTRL_1,
++++                                     ARIZONA_AIF1TX_WL_MASK |
++++                                     ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
++++            regmap_update_bits(arizona->regmap,
++++                               base + ARIZONA_AIF_FRAME_CTRL_2,
++++                               ARIZONA_AIF1RX_WL_MASK |
++++                               ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
++++    }
     
----    return 0;
++++ restore_aif:
++++    if (reconfig) {
++++            /* Restore AIF TX/RX state */
++++            regmap_update_bits_async(arizona->regmap,
++++                                     base + ARIZONA_AIF_TX_ENABLES,
++++                                     0xff, aif_tx_state);
++++            regmap_update_bits(arizona->regmap,
++++                               base + ARIZONA_AIF_RX_ENABLES,
++++                               0xff, aif_rx_state);
++++    }
++++    return ret;
     }
     
     static const char *arizona_dai_clk_str(int clk_id)
@@@@@@ -1349,9 -1324,9 -1324,9 -1324,9 -1421,63 +1446,63 @@@@@@ static int arizona_set_tristate(struct 
                                   ARIZONA_AIF1_TRI, reg);
     }
     
++++ static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
++++                                     unsigned int base,
++++                                     int channels, unsigned int mask)
++++ {
++++    struct snd_soc_codec *codec = dai->codec;
++++    struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
++++    struct arizona *arizona = priv->arizona;
++++    int slot, i;
++++ 
++++    for (i = 0; i < channels; ++i) {
++++            slot = ffs(mask) - 1;
++++            if (slot < 0)
++++                    return;
++++ 
++++            regmap_write(arizona->regmap, base + i, slot);
++++ 
++++            mask &= ~(1 << slot);
++++    }
++++ 
++++    if (mask)
++++            arizona_aif_warn(dai, "Too many channels in TDM mask\n");
++++ }
++++ 
++++ static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
++++                            unsigned int rx_mask, int slots, int slot_width)
++++ {
++++    struct snd_soc_codec *codec = dai->codec;
++++    struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
++++    struct arizona *arizona = priv->arizona;
++++    int base = dai->driver->base;
++++    int rx_max_chan = dai->driver->playback.channels_max;
++++    int tx_max_chan = dai->driver->capture.channels_max;
++++ 
++++    /* Only support TDM for the physical AIFs */
++++    if (dai->id > ARIZONA_MAX_AIF)
++++            return -ENOTSUPP;
++++ 
++++    if (slots == 0) {
++++            tx_mask = (1 << tx_max_chan) - 1;
++++            rx_mask = (1 << rx_max_chan) - 1;
++++    }
++++ 
++++    arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
++++                                 tx_max_chan, tx_mask);
++++    arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
++++                                 rx_max_chan, rx_mask);
++++ 
++++    arizona->tdm_width[dai->id - 1] = slot_width;
++++    arizona->tdm_slots[dai->id - 1] = slots;
++++ 
++++    return 0;
++++ }
++++ 
     const struct snd_soc_dai_ops arizona_dai_ops = {
        .startup = arizona_startup,
        .set_fmt = arizona_set_fmt,
++++    .set_tdm_slot = arizona_set_tdm_slot,
        .hw_params = arizona_hw_params,
        .set_sysclk = arizona_dai_set_sysclk,
        .set_tristate = arizona_set_tristate,
@@@@@@ -1425,6 -1400,6 -1400,6 -1400,6 -1551,12 +1576,12 @@@@@@ static int arizona_validate_fll(struct 
     {
        unsigned int Fvco_min;
     
++++    if (fll->fout && Fout != fll->fout) {
++++            arizona_fll_err(fll,
++++                            "Can't change output on active FLL\n");
++++            return -EINVAL;
++++    }
++++ 
        if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
                arizona_fll_err(fll,
                                "Can't scale %dMHz in to <=13.5MHz\n",
@@@@@@ -1503,6 -1478,6 -1478,6 -1478,6 -1635,10 +1660,10 @@@@@@ static int arizona_calc_fratio(struct a
        while (div <= ARIZONA_FLL_MAX_REFDIV) {
                for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
                     ratio++) {
++++                    if ((ARIZONA_FLL_VCO_CORNER / 2) /
++++                        (fll->vco_mult * ratio) < Fref)
++++                            break;
++++ 
                        if (target % (ratio * Fref)) {
                                cfg->refdiv = refdiv;
                                cfg->fratio = ratio - 1;
                        }
                }
     
----            for (ratio = init_ratio - 1; ratio >= 0; ratio--) {
----                    if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) <
----                        Fref)
----                            break;
---- 
++++            for (ratio = init_ratio - 1; ratio > 0; ratio--) {
                        if (target % (ratio * Fref)) {
                                cfg->refdiv = refdiv;
                                cfg->fratio = ratio - 1;
@@@@@@ -1641,7 -1616,7 -1616,7 -1616,7 -1773,7 +1798,7 @@@@@@ static void arizona_apply_fll(struct ar
                                 ARIZONA_FLL1_CTRL_UPD | cfg->n);
     }
     
---- static bool arizona_is_enabled_fll(struct arizona_fll *fll)
++++ static int arizona_is_enabled_fll(struct arizona_fll *fll)
     {
        struct arizona *arizona = fll->arizona;
        unsigned int reg;
        return reg & ARIZONA_FLL1_ENA;
     }
     
---- static void arizona_enable_fll(struct arizona_fll *fll)
++++ static int arizona_enable_fll(struct arizona_fll *fll)
     {
        struct arizona *arizona = fll->arizona;
        int ret;
        bool use_sync = false;
++++    int already_enabled = arizona_is_enabled_fll(fll);
        struct arizona_fll_cfg cfg;
     
++++    if (already_enabled < 0)
++++            return already_enabled;
++++ 
++++    if (already_enabled) {
++++            /* Facilitate smooth refclk across the transition */
++++            regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
++++                                     ARIZONA_FLL1_GAIN_MASK, 0);
++++            regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
++++                                     ARIZONA_FLL1_FREERUN,
++++                                     ARIZONA_FLL1_FREERUN);
++++    }
++++ 
        /*
         * If we have both REFCLK and SYNCCLK then enable both,
         * otherwise apply the SYNCCLK settings to REFCLK.
                                         ARIZONA_FLL1_SYNC_ENA, 0);
        } else {
                arizona_fll_err(fll, "No clocks provided\n");
----            return;
++++            return -EINVAL;
        }
     
        /*
                                         ARIZONA_FLL1_SYNC_BW,
                                         ARIZONA_FLL1_SYNC_BW);
     
----    if (!arizona_is_enabled_fll(fll))
++++    if (!already_enabled)
                pm_runtime_get(arizona->dev);
     
        /* Clear any pending completions */
        try_wait_for_completion(&fll->ok);
     
----    regmap_update_bits_async(arizona->regmap, fll->base + 1,
----                             ARIZONA_FLL1_FREERUN, 0);
        regmap_update_bits_async(arizona->regmap, fll->base + 1,
                                 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
        if (use_sync)
                                         ARIZONA_FLL1_SYNC_ENA,
                                         ARIZONA_FLL1_SYNC_ENA);
     
++++    if (already_enabled)
++++            regmap_update_bits_async(arizona->regmap, fll->base + 1,
++++                                     ARIZONA_FLL1_FREERUN, 0);
++++ 
        ret = wait_for_completion_timeout(&fll->ok,
                                          msecs_to_jiffies(250));
        if (ret == 0)
                arizona_fll_warn(fll, "Timed out waiting for lock\n");
++++ 
++++    return 0;
     }
     
     static void arizona_disable_fll(struct arizona_fll *fll)
                                 ARIZONA_FLL1_ENA, 0, &change);
        regmap_update_bits(arizona->regmap, fll->base + 0x11,
                           ARIZONA_FLL1_SYNC_ENA, 0);
++++    regmap_update_bits_async(arizona->regmap, fll->base + 1,
++++                             ARIZONA_FLL1_FREERUN, 0);
     
        if (change)
                pm_runtime_put_autosuspend(arizona->dev);
     int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
                           unsigned int Fref, unsigned int Fout)
     {
----    int ret;
++++    int ret = 0;
     
        if (fll->ref_src == source && fll->ref_freq == Fref)
                return 0;
        fll->ref_freq = Fref;
     
        if (fll->fout && Fref > 0) {
----            arizona_enable_fll(fll);
++++            ret = arizona_enable_fll(fll);
        }
     
----    return 0;
++++    return ret;
     }
     EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
     
     int arizona_set_fll(struct arizona_fll *fll, int source,
                    unsigned int Fref, unsigned int Fout)
     {
----    int ret;
++++    int ret = 0;
     
        if (fll->sync_src == source &&
            fll->sync_freq == Fref && fll->fout == Fout)
        fll->sync_freq = Fref;
        fll->fout = Fout;
     
----    if (Fout) {
----            arizona_enable_fll(fll);
----    } else {
++++    if (Fout)
++++            ret = arizona_enable_fll(fll);
++++    else
                arizona_disable_fll(fll);
----    }
     
----    return 0;
++++    return ret;
     }
     EXPORT_SYMBOL_GPL(arizona_set_fll);
     
index 91a9ea2a205679e451ab4ddf9258404a54322a2a,91a9ea2a205679e451ab4ddf9258404a54322a2a,91a9ea2a205679e451ab4ddf9258404a54322a2a,91a9ea2a205679e451ab4ddf9258404a54322a2a,42a3ff3a1b68e4117dc7b3479d6ac480466b64e3..7bb0d36d4c5485b703d2e7cd0adede1e732446b0
@@@@@@ -390,7 -390,7 -390,7 -390,7 -390,7 +390,7 @@@@@@ static int wm5100_mixer_values[] = 
     
     #define WM5100_MUX_CTL_DECL(name) \
        const struct snd_kcontrol_new name##_mux =      \
    -           SOC_DAPM_VALUE_ENUM("Route", name##_enum)
    +           SOC_DAPM_ENUM("Route", name##_enum)
     
     #define WM5100_MIXER_ENUMS(name, base_reg) \
        static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg);      \
@@@@@@ -448,7 -448,7 -448,7 -448,7 -448,7 +448,7 @@@@@@ WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3M
     WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);
     
     #define WM5100_MUX(name, ctrl) \
    -   SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
    +   SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
     
     #define WM5100_MIXER_WIDGETS(name, name_str)       \
        WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
@@@@@@ -735,8 -735,8 -735,8 -735,8 -735,7 +735,7 @@@@@@ WM5100_MIXER_CONTROLS("LHPF4", WM5100_H
     static void wm5100_seq_notifier(struct snd_soc_dapm_context *dapm,
                                enum snd_soc_dapm_type event, int subseq)
     {
----    struct snd_soc_codec *codec = container_of(dapm,
----                                               struct snd_soc_codec, dapm);
++++    struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
        u16 val, expect, i;
     
index 2e96d6e0e13e2a2c57d085da3d157ec475a578eb,289b64d89abd464b562d7dbd56756169ddebaba4,289b64d89abd464b562d7dbd56756169ddebaba4,289b64d89abd464b562d7dbd56756169ddebaba4,58913580cc5a8d3baca458d0c63c0cb50b046bd9..f602349625278fb7c9717990f07c739276109130
@@@@@@ -612,6 -612,6 -612,6 -612,6 -612,62 +612,62 @@@@@@ static int wm5102_sysclk_ev(struct snd_
        return 0;
     }
     
++++ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
++++                                 struct snd_ctl_elem_value *ucontrol)
++++ {
++++    struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
++++    struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
++++    uint16_t data;
++++ 
++++    mutex_lock(&codec->mutex);
++++    data = cpu_to_be16(arizona->dac_comp_coeff);
++++    memcpy(ucontrol->value.bytes.data, &data, sizeof(data));
++++    mutex_unlock(&codec->mutex);
++++ 
++++    return 0;
++++ }
++++ 
++++ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
++++                                 struct snd_ctl_elem_value *ucontrol)
++++ {
++++    struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
++++    struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
++++ 
++++    mutex_lock(&codec->mutex);
++++    memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
++++           sizeof(arizona->dac_comp_coeff));
++++    arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff);
++++    mutex_unlock(&codec->mutex);
++++ 
++++    return 0;
++++ }
++++ 
++++ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
++++                                  struct snd_ctl_elem_value *ucontrol)
++++ {
++++    struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
++++    struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
++++ 
++++    mutex_lock(&codec->mutex);
++++    ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
++++    mutex_unlock(&codec->mutex);
++++ 
++++    return 0;
++++ }
++++ 
++++ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
++++                                  struct snd_ctl_elem_value *ucontrol)
++++ {
++++    struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
++++    struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
++++ 
++++    mutex_lock(&codec->mutex);
++++    arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
++++    mutex_unlock(&codec->mutex);
++++ 
++++    return 0;
++++ }
++++ 
     static const char *wm5102_osr_text[] = {
        "Low power", "Normal", "High performance",
     };
@@@@@@ -764,8 -764,8 -764,8 -764,8 -820,8 +820,8 @@@@@@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mo
     SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
     SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
     
    -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
    -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
    +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
    +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
     
     ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
     ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
@@@@@@ -814,9 -814,9 -814,9 -814,9 -870,9 +870,9 @@@@@@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volum
                 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
                 0xbf, 0, digital_tlv),
     
    -SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
    -SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
    -SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
    +SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
    +SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
    +SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
     
     SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
           ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
@@@@@@ -843,6 -843,6 -843,6 -843,6 -899,12 +899,12 @@@@@@ SOC_SINGLE_TLV("Noise Gate Threshold Vo
               ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
     SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
     
++++ SND_SOC_BYTES_EXT("Output Compensation Coefficient", 2,
++++              wm5102_out_comp_coeff_get, wm5102_out_comp_coeff_put),
++++ 
++++ SOC_SINGLE_EXT("Output Compensation Switch", 0, 0, 1, 0,
++++           wm5102_out_comp_switch_get, wm5102_out_comp_switch_put),
++++ 
     WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
     WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
     WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
@@@@@@ -970,7 -970,7 -970,7 -970,7 -1032,7 +1032,7 @@@@@@ static const struct soc_enum wm5102_aec
                              wm5102_aec_loopback_values);
     
     static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
    -   SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback);
    +   SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback);
     
     static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
     SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@@@@@ -1204,7 -1204,7 -1204,7 -1204,7 -1266,7 +1266,7 @@@@@@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0
     
     ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
     
    -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
    +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
                       &wm5102_aec_loopback_mux),
     
@@@@@@ -1653,7 -1653,6 -1653,6 -1653,6 -1715,6 +1715,7 @@@@@@ static struct snd_soc_dai_driver wm5102
                 },
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
 ++++           .symmetric_samplebits = 1,
        },
        {
                .name = "wm5102-aif2",
                 },
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
 ++++           .symmetric_samplebits = 1,
        },
        {
                .name = "wm5102-aif3",
                 },
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
 ++++           .symmetric_samplebits = 1,
        },
        {
                .name = "wm5102-slim1",
@@@@@@ -1763,6 -1760,6 -1760,6 -1760,6 -1822,10 +1825,6 @@@@@@ static int wm5102_codec_probe(struct sn
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
     
    -   ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
    -   if (ret != 0)
    -           return ret;
    -
        ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
        if (ret != 0)
                return ret;
@@@@@@ -1801,17 -1798,17 -1798,17 -1798,17 -1864,9 +1863,17 @@@@@@ static unsigned int wm5102_digital_vu[
        ARIZONA_DAC_DIGITAL_VOLUME_5R,
     };
     
    +static struct regmap *wm5102_get_regmap(struct device *dev)
    +{
    +   struct wm5102_priv *priv = dev_get_drvdata(dev);
    +
    +   return priv->core.arizona->regmap;
    +}
    +
     static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
        .probe = wm5102_codec_probe,
        .remove = wm5102_codec_remove,
    +   .get_regmap = wm5102_get_regmap,
     
        .idle_bias_off = true,
     
index b84940c359a127fd1330146b21ef50cda605ac0d,b84940c359a127fd1330146b21ef50cda605ac0d,b84940c359a127fd1330146b21ef50cda605ac0d,b84940c359a127fd1330146b21ef50cda605ac0d,2116e79085ecebff1c3997178ab477ac732d19b5..ec3250daa93e43ed75dd34a729d0103abdca2557
@@@@@@ -281,8 -281,8 -281,8 -281,8 -281,7 +281,7 @@@@@@ static int wm8903_dcs_event(struct snd_
     static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
                                enum snd_soc_dapm_type event, int subseq)
     {
----    struct snd_soc_codec *codec = container_of(dapm,
----                                               struct snd_soc_codec, dapm);
++++    struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int dcs_mode = WM8903_DCS_MODE_WRITE_STOP;
        int i, val;
@@@@@@ -439,7 -439,7 -439,7 -439,7 -438,7 +438,7 @@@@@@ static int wm8903_set_deemph(struct snd
     static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
     {
    -   struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
    +   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
     
        ucontrol->value.enumerated.item[0] = wm8903->deemph;
     static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
     {
    -   struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
    +   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int deemph = ucontrol->value.enumerated.item[0];
        int ret = 0;
index 69266332760ebad71bed763449afa2f8eb8079a9,69266332760ebad71bed763449afa2f8eb8079a9,69266332760ebad71bed763449afa2f8eb8079a9,69266332760ebad71bed763449afa2f8eb8079a9,8f4d2cddb962244b9570c8a31537a0b5dcbb8e7a..9304a91b8403d642ebd5e04979fce1e6f0bcb622
@@@@@@ -412,7 -412,7 -412,7 -412,7 -412,7 +412,7 @@@@@@ static int wm8996_get_retune_mobile_blo
     static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
     {
    -   struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
    +   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        struct wm8996_pdata *pdata = &wm8996->pdata;
        int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
     static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
     {
    -   struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
    +   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
     
@@@@@@ -690,8 -690,8 -690,8 -690,8 -690,7 +690,7 @@@@@@ static void wait_for_dc_servo(struct sn
     static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
                                enum snd_soc_dapm_type event, int subseq)
     {
----    struct snd_soc_codec *codec = container_of(dapm,
----                                               struct snd_soc_codec, dapm);
++++    struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        u16 val, mask;