From 8afd0ef2639ea2b7bc1b3a0f927ab14e0df034df Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Dec 2012 17:10:05 +0900 Subject: ASoC: wm8994: Fix variable double use Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 82411009d401..f2e63acb2674 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3721,7 +3721,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; struct snd_soc_codec *codec = wm8994->hubs.codec; - int reg, count; + int reg, count, ret; /* * Jack detection may have detected a removal simulataneously @@ -3767,11 +3767,11 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) /* Avoid a transient report when the accessory is being removed */ if (wm8994->jackdet) { - reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); - if (reg < 0) { + ret = snd_soc_read(codec, WM1811_JACKDET_CTRL); + if (ret < 0) { dev_err(codec->dev, "Failed to read jack status: %d\n", - reg); - } else if (!(reg & WM1811_JACKDET_LVL)) { + ret); + } else if (!(ret & WM1811_JACKDET_LVL)) { dev_dbg(codec->dev, "Ignoring removed jack\n"); return IRQ_HANDLED; } -- cgit v1.2.3 From a10807aef5cab5568e70a2d1597305999d93f85d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 11 Feb 2013 13:39:08 -0200 Subject: ASoC: fsl: imx-audmux: Fix sparse warning Fix the following sparse warning: sound/soc/fsl/imx-audmux.c:182:3: warning: symbol 'audmux_type' was not declared. Should it be static? Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 251f4d981e0c..fab912ea7a50 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -176,7 +176,7 @@ static inline void audmux_debugfs_remove(void) } #endif -enum imx_audmux_type { +static enum imx_audmux_type { IMX21_AUDMUX, IMX31_AUDMUX, } audmux_type; -- cgit v1.2.3 From 41c4d554e75ccbdb043878049cf2671dd49598a5 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Mon, 11 Feb 2013 14:02:42 +0100 Subject: ASoC: omap-mcpdm: Remove useless ressource get. Remove unused memory ressource get from McPDM driver. Signed-off-by: Sebastien Guiriec Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 2fe8be209452..5ca11bdac21e 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -449,10 +449,6 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA; omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) - return -ENOMEM; - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link"); if (!res) return -ENODEV; -- cgit v1.2.3 From 43cd8bf1c8d8f6e897ed0f2c4bd50a4266b5c36e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Feb 2013 16:57:29 +0000 Subject: ASoC: arizona: Automatically manage input mutes For optimal performance the inputs should be kept muted until after power up. Since there are few use cases for muting inputs during capture move the mutes to automatic control. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 17 +++++++++++++++++ sound/soc/codecs/wm5102.c | 13 ------------- sound/soc/codecs/wm5110.c | 17 ----------------- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index d824c984c8a4..ac948a671ea6 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -335,6 +335,23 @@ EXPORT_SYMBOL_GPL(arizona_ng_hold); int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + unsigned int reg; + + if (w->shift % 2) + reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8); + else + reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, + ARIZONA_IN1L_MUTE); + break; + } + return 0; } EXPORT_SYMBOL_GPL(arizona_in_ev); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 5e85b645f2eb..ab69c83626cd 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -636,19 +636,6 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL, SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE("IN1L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_IN1L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN1R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_IN1R_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN2L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_IN2L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN2R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_IN2R_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN3L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_IN3L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN3R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_IN3R_MUTE_SHIFT, 1, 1), - SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 23199372d518..a1631320b448 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -80,23 +80,6 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL, SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), -SOC_SINGLE("IN1L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_IN1L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN1R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_IN1R_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN2L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_IN2L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN2R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_IN2R_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN3L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_IN3L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN3R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_IN3R_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN4L Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4L, - ARIZONA_IN4L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("IN4R Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4R, - ARIZONA_IN4R_MUTE_SHIFT, 1, 1), - SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, -- cgit v1.2.3 From ef5c2eba2412596f1a022c11caf74428bffd9abe Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2013 12:02:51 +0000 Subject: ASoC: codecs: Add da7213 codec This patch adds support for the Dialog DA7213 audio codec. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- include/sound/da7213.h | 52 ++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/da7213.c | 1599 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/da7213.h | 523 +++++++++++++++ 5 files changed, 2180 insertions(+) create mode 100644 include/sound/da7213.h create mode 100644 sound/soc/codecs/da7213.c create mode 100644 sound/soc/codecs/da7213.h diff --git a/include/sound/da7213.h b/include/sound/da7213.h new file mode 100644 index 000000000000..673f5c39cbf2 --- /dev/null +++ b/include/sound/da7213.h @@ -0,0 +1,52 @@ +/* + * da7213.h - DA7213 ASoC Codec Driver Platform Data + * + * Copyright (c) 2013 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DA7213_PDATA_H +#define _DA7213_PDATA_H + +enum da7213_micbias_voltage { + DA7213_MICBIAS_1_6V = 0, + DA7213_MICBIAS_2_2V = 1, + DA7213_MICBIAS_2_5V = 2, + DA7213_MICBIAS_3_0V = 3, +}; + +enum da7213_dmic_data_sel { + DA7213_DMIC_DATA_LRISE_RFALL = 0, + DA7213_DMIC_DATA_LFALL_RRISE = 1, +}; + +enum da7213_dmic_samplephase { + DA7213_DMIC_SAMPLE_ON_CLKEDGE = 0, + DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE = 1, +}; + +enum da7213_dmic_clk_rate { + DA7213_DMIC_CLK_3_0MHZ = 0, + DA7213_DMIC_CLK_1_5MHZ = 1, +}; + +struct da7213_platform_data { + /* Mic Bias voltage */ + enum da7213_micbias_voltage micbias1_lvl; + enum da7213_micbias_voltage micbias2_lvl; + + /* DMIC config */ + enum da7213_dmic_data_sel dmic_data_sel; + enum da7213_dmic_samplephase dmic_samplephase; + enum da7213_dmic_clk_rate dmic_clk_rate; + + /* MCLK squaring config */ + bool mclk_squaring; +}; + +#endif /* _DA7213_PDATA_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3a847828932a..751476aa7814 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CX20442 select SND_SOC_DA7210 if I2C + select SND_SOC_DA7213 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_DFBMCS320 @@ -247,6 +248,9 @@ config SND_SOC_L3 config SND_SOC_DA7210 tristate +config SND_SOC_DA7213 + tristate + config SND_SOC_DA732X tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f6e8e36cceb7..6a3b3c3b8b41 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -23,6 +23,7 @@ snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o +snd-soc-da7213-objs := da7213.o snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-dfbmcs320-objs := dfbmcs320.o @@ -147,6 +148,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o +obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c new file mode 100644 index 000000000000..41230ad1c3e0 --- /dev/null +++ b/sound/soc/codecs/da7213.c @@ -0,0 +1,1599 @@ +/* + * DA7213 ALSA SoC Codec Driver + * + * Copyright (c) 2013 Dialog Semiconductor + * + * Author: Adam Thomson + * Based on DA9055 ALSA SoC codec driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "da7213.h" + + +/* Gain and Volume */ +static const unsigned int aux_vol_tlv[] = { + TLV_DB_RANGE_HEAD(2), + /* -54dB */ + 0x0, 0x11, TLV_DB_SCALE_ITEM(-5400, 0, 0), + /* -52.5dB to 15dB */ + 0x12, 0x3f, TLV_DB_SCALE_ITEM(-5250, 150, 0) +}; + +static const unsigned int digital_gain_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + /* -78dB to 12dB */ + 0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0) +}; + +static const unsigned int alc_analog_gain_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + /* 0dB to 36dB */ + 0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0) +}; + +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0); +static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0); +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0); +static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0); + +/* ADC and DAC voice mode (8kHz) high pass cutoff value */ +static const char * const da7213_voice_hpf_corner_txt[] = { + "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" +}; + +static const struct soc_enum da7213_dac_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, + DA7213_VOICE_HPF_CORNER_MAX, + da7213_voice_hpf_corner_txt); + +static const struct soc_enum da7213_adc_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, + DA7213_VOICE_HPF_CORNER_MAX, + da7213_voice_hpf_corner_txt); + +/* ADC and DAC high pass filter cutoff value */ +static const char * const da7213_audio_hpf_corner_txt[] = { + "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" +}; + +static const struct soc_enum da7213_dac_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, + DA7213_AUDIO_HPF_CORNER_MAX, + da7213_audio_hpf_corner_txt); + +static const struct soc_enum da7213_adc_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, + DA7213_AUDIO_HPF_CORNER_MAX, + da7213_audio_hpf_corner_txt); + +/* Gain ramping rate value */ +static const char * const da7213_gain_ramp_rate_txt[] = { + "nominal rate * 8", "nominal rate * 16", "nominal rate / 16", + "nominal rate / 32" +}; + +static const struct soc_enum da7213_gain_ramp_rate = + SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT, + DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt); + +/* DAC noise gate setup time value */ +static const char * const da7213_dac_ng_setup_time_txt[] = { + "256 samples", "512 samples", "1024 samples", "2048 samples" +}; + +static const struct soc_enum da7213_dac_ng_setup_time = + SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_SETUP_TIME_SHIFT, + DA7213_DAC_NG_SETUP_TIME_MAX, + da7213_dac_ng_setup_time_txt); + +/* DAC noise gate rampup rate value */ +static const char * const da7213_dac_ng_rampup_txt[] = { + "0.02 ms/dB", "0.16 ms/dB" +}; + +static const struct soc_enum da7213_dac_ng_rampup_rate = + SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_RAMPUP_RATE_SHIFT, + DA7213_DAC_NG_RAMP_RATE_MAX, + da7213_dac_ng_rampup_txt); + +/* DAC noise gate rampdown rate value */ +static const char * const da7213_dac_ng_rampdown_txt[] = { + "0.64 ms/dB", "20.48 ms/dB" +}; + +static const struct soc_enum da7213_dac_ng_rampdown_rate = + SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_RAMPDN_RATE_SHIFT, + DA7213_DAC_NG_RAMP_RATE_MAX, + da7213_dac_ng_rampdown_txt); + +/* DAC soft mute rate value */ +static const char * const da7213_dac_soft_mute_rate_txt[] = { + "1", "2", "4", "8", "16", "32", "64" +}; + +static const struct soc_enum da7213_dac_soft_mute_rate = + SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT, + DA7213_DAC_SOFTMUTE_RATE_MAX, + da7213_dac_soft_mute_rate_txt); + +/* ALC Attack Rate select */ +static const char * const da7213_alc_attack_rate_txt[] = { + "44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", + "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" +}; + +static const struct soc_enum da7213_alc_attack_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT, + DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt); + +/* ALC Release Rate select */ +static const char * const da7213_alc_release_rate_txt[] = { + "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs", + "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" +}; + +static const struct soc_enum da7213_alc_release_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT, + DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt); + +/* ALC Hold Time select */ +static const char * const da7213_alc_hold_time_txt[] = { + "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs", + "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs", + "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" +}; + +static const struct soc_enum da7213_alc_hold_time = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT, + DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt); + +/* ALC Input Signal Tracking rate select */ +static const char * const da7213_alc_integ_rate_txt[] = { + "1/4", "1/16", "1/256", "1/65536" +}; + +static const struct soc_enum da7213_alc_integ_attack_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT, + DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); + +static const struct soc_enum da7213_alc_integ_release_rate = + SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT, + DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); + + +/* + * Control Functions + */ + +static int da7213_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) +{ + int mid_data, top_data; + int sum = 0; + u8 iteration; + + for (iteration = 0; iteration < DA7213_ALC_AVG_ITERATIONS; + iteration++) { + /* Select the left or right channel and capture data */ + snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, reg_val); + + /* Select middle 8 bits for read back from data register */ + snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, + reg_val | DA7213_ALC_DATA_MIDDLE); + mid_data = snd_soc_read(codec, DA7213_ALC_CIC_OP_LVL_DATA); + + /* Select top 8 bits for read back from data register */ + snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, + reg_val | DA7213_ALC_DATA_TOP); + top_data = snd_soc_read(codec, DA7213_ALC_CIC_OP_LVL_DATA); + + sum += ((mid_data << 8) | (top_data << 16)); + } + + return sum / DA7213_ALC_AVG_ITERATIONS; +} + +static void da7213_alc_calib_man(struct snd_soc_codec *codec) +{ + u8 reg_val; + int avg_left_data, avg_right_data, offset_l, offset_r; + + /* Calculate average for Left and Right data */ + /* Left Data */ + avg_left_data = da7213_get_alc_data(codec, + DA7213_ALC_CIC_OP_CHANNEL_LEFT); + /* Right Data */ + avg_right_data = da7213_get_alc_data(codec, + DA7213_ALC_CIC_OP_CHANNEL_RIGHT); + + /* Calculate DC offset */ + offset_l = -avg_left_data; + offset_r = -avg_right_data; + + reg_val = (offset_l & DA7213_ALC_OFFSET_15_8) >> 8; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_M_L, reg_val); + reg_val = (offset_l & DA7213_ALC_OFFSET_19_16) >> 16; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_U_L, reg_val); + + reg_val = (offset_r & DA7213_ALC_OFFSET_15_8) >> 8; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_M_R, reg_val); + reg_val = (offset_r & DA7213_ALC_OFFSET_19_16) >> 16; + snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_U_R, reg_val); + + /* Enable analog/digital gain mode & offset cancellation */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE); +} + +static void da7213_alc_calib_auto(struct snd_soc_codec *codec) +{ + u8 alc_ctrl1; + + /* Begin auto calibration and wait for completion */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, DA7213_ALC_AUTO_CALIB_EN, + DA7213_ALC_AUTO_CALIB_EN); + do { + alc_ctrl1 = snd_soc_read(codec, DA7213_ALC_CTRL1); + } while (alc_ctrl1 & DA7213_ALC_AUTO_CALIB_EN); + + /* If auto calibration fails, fall back to digital gain only mode */ + if (alc_ctrl1 & DA7213_ALC_CALIB_OVERFLOW) { + dev_warn(codec->dev, + "ALC auto calibration failed with overflow\n"); + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE, + 0); + } else { + /* Enable analog/digital gain mode & offset cancellation */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE, + DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE); + } + +} + +static void da7213_alc_calib(struct snd_soc_codec *codec) +{ + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + u8 adc_l_ctrl, adc_r_ctrl; + u8 mixin_l_sel, mixin_r_sel; + u8 mic_1_ctrl, mic_2_ctrl; + + /* Save current values from ADC control registers */ + adc_l_ctrl = snd_soc_read(codec, DA7213_ADC_L_CTRL); + adc_r_ctrl = snd_soc_read(codec, DA7213_ADC_R_CTRL); + + /* Save current values from MIXIN_L/R_SELECT registers */ + mixin_l_sel = snd_soc_read(codec, DA7213_MIXIN_L_SELECT); + mixin_r_sel = snd_soc_read(codec, DA7213_MIXIN_R_SELECT); + + /* Save current values from MIC control registers */ + mic_1_ctrl = snd_soc_read(codec, DA7213_MIC_1_CTRL); + mic_2_ctrl = snd_soc_read(codec, DA7213_MIC_2_CTRL); + + /* Enable ADC Left and Right */ + snd_soc_update_bits(codec, DA7213_ADC_L_CTRL, DA7213_ADC_EN, + DA7213_ADC_EN); + snd_soc_update_bits(codec, DA7213_ADC_R_CTRL, DA7213_ADC_EN, + DA7213_ADC_EN); + + /* Enable MIC paths */ + snd_soc_update_bits(codec, DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIC_1 | + DA7213_MIXIN_L_MIX_SELECT_MIC_2, + DA7213_MIXIN_L_MIX_SELECT_MIC_1 | + DA7213_MIXIN_L_MIX_SELECT_MIC_2); + snd_soc_update_bits(codec, DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIC_2 | + DA7213_MIXIN_R_MIX_SELECT_MIC_1, + DA7213_MIXIN_R_MIX_SELECT_MIC_2 | + DA7213_MIXIN_R_MIX_SELECT_MIC_1); + + /* Mute MIC PGAs */ + snd_soc_update_bits(codec, DA7213_MIC_1_CTRL, DA7213_MUTE_EN, + DA7213_MUTE_EN); + snd_soc_update_bits(codec, DA7213_MIC_2_CTRL, DA7213_MUTE_EN, + DA7213_MUTE_EN); + + /* Perform calibration */ + if (da7213->alc_calib_auto) + da7213_alc_calib_auto(codec); + else + da7213_alc_calib_man(codec); + + /* Restore MIXIN_L/R_SELECT registers to their original states */ + snd_soc_write(codec, DA7213_MIXIN_L_SELECT, mixin_l_sel); + snd_soc_write(codec, DA7213_MIXIN_R_SELECT, mixin_r_sel); + + /* Restore ADC control registers to their original states */ + snd_soc_write(codec, DA7213_ADC_L_CTRL, adc_l_ctrl); + snd_soc_write(codec, DA7213_ADC_R_CTRL, adc_r_ctrl); + + /* Restore original values of MIC control registers */ + snd_soc_write(codec, DA7213_MIC_1_CTRL, mic_1_ctrl); + snd_soc_write(codec, DA7213_MIC_2_CTRL, mic_2_ctrl); +} + +static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + + /* If ALC in operation, make sure calibrated offsets are updated */ + if ((!ret) && (da7213->alc_en)) + da7213_alc_calib(codec); + + return ret; +} + +static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + + /* Force ALC offset calibration if enabling ALC */ + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) { + if (!da7213->alc_en) { + da7213_alc_calib(codec); + da7213->alc_en = true; + } + } else { + da7213->alc_en = false; + } + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + + +/* + * KControls + */ + +static const struct snd_kcontrol_new da7213_snd_controls[] = { + + /* Volume controls */ + SOC_SINGLE_TLV("Mic 1 Volume", DA7213_MIC_1_GAIN, + DA7213_MIC_AMP_GAIN_SHIFT, DA7213_MIC_AMP_GAIN_MAX, + DA7213_NO_INVERT, mic_vol_tlv), + SOC_SINGLE_TLV("Mic 2 Volume", DA7213_MIC_2_GAIN, + DA7213_MIC_AMP_GAIN_SHIFT, DA7213_MIC_AMP_GAIN_MAX, + DA7213_NO_INVERT, mic_vol_tlv), + SOC_DOUBLE_R_TLV("Aux Volume", DA7213_AUX_L_GAIN, DA7213_AUX_R_GAIN, + DA7213_AUX_AMP_GAIN_SHIFT, DA7213_AUX_AMP_GAIN_MAX, + DA7213_NO_INVERT, aux_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("Mixin PGA Volume", DA7213_MIXIN_L_GAIN, + DA7213_MIXIN_R_GAIN, DA7213_MIXIN_AMP_GAIN_SHIFT, + DA7213_MIXIN_AMP_GAIN_MAX, DA7213_NO_INVERT, + snd_soc_get_volsw_2r, da7213_put_mixin_gain, + mixin_gain_tlv), + SOC_DOUBLE_R_TLV("ADC Volume", DA7213_ADC_L_GAIN, DA7213_ADC_R_GAIN, + DA7213_ADC_AMP_GAIN_SHIFT, DA7213_ADC_AMP_GAIN_MAX, + DA7213_NO_INVERT, digital_gain_tlv), + SOC_DOUBLE_R_TLV("DAC Volume", DA7213_DAC_L_GAIN, DA7213_DAC_R_GAIN, + DA7213_DAC_AMP_GAIN_SHIFT, DA7213_DAC_AMP_GAIN_MAX, + DA7213_NO_INVERT, digital_gain_tlv), + SOC_DOUBLE_R_TLV("Headphone Volume", DA7213_HP_L_GAIN, DA7213_HP_R_GAIN, + DA7213_HP_AMP_GAIN_SHIFT, DA7213_HP_AMP_GAIN_MAX, + DA7213_NO_INVERT, hp_vol_tlv), + SOC_SINGLE_TLV("Lineout Volume", DA7213_LINE_GAIN, + DA7213_LINE_AMP_GAIN_SHIFT, DA7213_LINE_AMP_GAIN_MAX, + DA7213_NO_INVERT, lineout_vol_tlv), + + /* DAC Equalizer controls */ + SOC_SINGLE("DAC EQ Switch", DA7213_DAC_FILTERS4, DA7213_DAC_EQ_EN_SHIFT, + DA7213_DAC_EQ_EN_MAX, DA7213_NO_INVERT), + SOC_SINGLE_TLV("DAC EQ1 Volume", DA7213_DAC_FILTERS2, + DA7213_DAC_EQ_BAND1_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ2 Volume", DA7213_DAC_FILTERS2, + DA7213_DAC_EQ_BAND2_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ3 Volume", DA7213_DAC_FILTERS3, + DA7213_DAC_EQ_BAND3_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ4 Volume", DA7213_DAC_FILTERS3, + DA7213_DAC_EQ_BAND4_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + SOC_SINGLE_TLV("DAC EQ5 Volume", DA7213_DAC_FILTERS4, + DA7213_DAC_EQ_BAND5_SHIFT, DA7213_DAC_EQ_BAND_MAX, + DA7213_NO_INVERT, eq_gain_tlv), + + /* High Pass Filter and Voice Mode controls */ + SOC_SINGLE("ADC HPF Switch", DA7213_ADC_FILTERS1, DA7213_HPF_EN_SHIFT, + DA7213_HPF_EN_MAX, DA7213_NO_INVERT), + SOC_ENUM("ADC HPF Cutoff", da7213_adc_audio_hpf_corner), + SOC_SINGLE("ADC Voice Mode Switch", DA7213_ADC_FILTERS1, + DA7213_VOICE_EN_SHIFT, DA7213_VOICE_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("ADC Voice Cutoff", da7213_adc_voice_hpf_corner), + + SOC_SINGLE("DAC HPF Switch", DA7213_DAC_FILTERS1, DA7213_HPF_EN_SHIFT, + DA7213_HPF_EN_MAX, DA7213_NO_INVERT), + SOC_ENUM("DAC HPF Cutoff", da7213_dac_audio_hpf_corner), + SOC_SINGLE("DAC Voice Mode Switch", DA7213_DAC_FILTERS1, + DA7213_VOICE_EN_SHIFT, DA7213_VOICE_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("DAC Voice Cutoff", da7213_dac_voice_hpf_corner), + + /* Mute controls */ + SOC_SINGLE("Mic 1 Switch", DA7213_MIC_1_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_SINGLE("Mic 2 Switch", DA7213_MIC_2_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("Aux Switch", DA7213_AUX_L_CTRL, DA7213_AUX_R_CTRL, + DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("Mixin PGA Switch", DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_R_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("ADC Switch", DA7213_ADC_L_CTRL, DA7213_ADC_R_CTRL, + DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_DOUBLE_R("Headphone Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL, + DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_SINGLE("Lineout Switch", DA7213_LINE_CTRL, DA7213_MUTE_EN_SHIFT, + DA7213_MUTE_EN_MAX, DA7213_INVERT), + SOC_SINGLE("DAC Soft Mute Switch", DA7213_DAC_FILTERS5, + DA7213_DAC_SOFTMUTE_EN_SHIFT, DA7213_DAC_SOFTMUTE_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("DAC Soft Mute Rate", da7213_dac_soft_mute_rate), + + /* Zero Cross controls */ + SOC_DOUBLE_R("Aux ZC Switch", DA7213_AUX_L_CTRL, DA7213_AUX_R_CTRL, + DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("Mixin PGA ZC Switch", DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_R_CTRL, DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, + DA7213_NO_INVERT), + SOC_DOUBLE_R("Headphone ZC Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL, + DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT), + + /* Gain Ramping controls */ + SOC_DOUBLE_R("Aux Gain Ramping Switch", DA7213_AUX_L_CTRL, + DA7213_AUX_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("ADC Gain Ramping Switch", DA7213_ADC_L_CTRL, + DA7213_ADC_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("DAC Gain Ramping Switch", DA7213_DAC_L_CTRL, + DA7213_DAC_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA7213_HP_L_CTRL, + DA7213_HP_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT, + DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT), + SOC_SINGLE("Lineout Gain Ramping Switch", DA7213_LINE_CTRL, + DA7213_GAIN_RAMP_EN_SHIFT, DA7213_GAIN_RAMP_EN_MAX, + DA7213_NO_INVERT), + SOC_ENUM("Gain Ramping Rate", da7213_gain_ramp_rate), + + /* DAC Noise Gate controls */ + SOC_SINGLE("DAC NG Switch", DA7213_DAC_NG_CTRL, DA7213_DAC_NG_EN_SHIFT, + DA7213_DAC_NG_EN_MAX, DA7213_NO_INVERT), + SOC_ENUM("DAC NG Setup Time", da7213_dac_ng_setup_time), + SOC_ENUM("DAC NG Rampup Rate", da7213_dac_ng_rampup_rate), + SOC_ENUM("DAC NG Rampdown Rate", da7213_dac_ng_rampdown_rate), + SOC_SINGLE("DAC NG OFF Threshold", DA7213_DAC_NG_OFF_THRESHOLD, + DA7213_DAC_NG_THRESHOLD_SHIFT, DA7213_DAC_NG_THRESHOLD_MAX, + DA7213_NO_INVERT), + SOC_SINGLE("DAC NG ON Threshold", DA7213_DAC_NG_ON_THRESHOLD, + DA7213_DAC_NG_THRESHOLD_SHIFT, DA7213_DAC_NG_THRESHOLD_MAX, + DA7213_NO_INVERT), + + /* DAC Routing & Inversion */ + SOC_DOUBLE("DAC Mono Switch", DA7213_DIG_ROUTING_DAC, + DA7213_DAC_L_MONO_SHIFT, DA7213_DAC_R_MONO_SHIFT, + DA7213_DAC_MONO_MAX, DA7213_NO_INVERT), + SOC_DOUBLE("DAC Invert Switch", DA7213_DIG_CTRL, DA7213_DAC_L_INV_SHIFT, + DA7213_DAC_R_INV_SHIFT, DA7213_DAC_INV_MAX, + DA7213_NO_INVERT), + + /* DMIC controls */ + SOC_DOUBLE_R("DMIC Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_R_SELECT, DA7213_DMIC_EN_SHIFT, + DA7213_DMIC_EN_MAX, DA7213_NO_INVERT), + + /* ALC Controls */ + SOC_DOUBLE_EXT("ALC Switch", DA7213_ALC_CTRL1, DA7213_ALC_L_EN_SHIFT, + DA7213_ALC_R_EN_SHIFT, DA7213_ALC_EN_MAX, + DA7213_NO_INVERT, snd_soc_get_volsw, da7213_put_alc_sw), + SOC_ENUM("ALC Attack Rate", da7213_alc_attack_rate), + SOC_ENUM("ALC Release Rate", da7213_alc_release_rate), + SOC_ENUM("ALC Hold Time", da7213_alc_hold_time), + /* + * Rate at which input signal envelope is tracked as the signal gets + * larger + */ + SOC_ENUM("ALC Integ Attack Rate", da7213_alc_integ_attack_rate), + /* + * Rate at which input signal envelope is tracked as the signal gets + * smaller + */ + SOC_ENUM("ALC Integ Release Rate", da7213_alc_integ_release_rate), + SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA7213_ALC_NOISE, + DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX, + DA7213_INVERT, alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Min Threshold Volume", DA7213_ALC_TARGET_MIN, + DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX, + DA7213_INVERT, alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Threshold Volume", DA7213_ALC_TARGET_MAX, + DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX, + DA7213_INVERT, alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA7213_ALC_GAIN_LIMITS, + DA7213_ALC_ATTEN_MAX_SHIFT, + DA7213_ALC_ATTEN_GAIN_MAX_MAX, DA7213_NO_INVERT, + alc_gain_tlv), + SOC_SINGLE_TLV("ALC Max Gain Volume", DA7213_ALC_GAIN_LIMITS, + DA7213_ALC_GAIN_MAX_SHIFT, DA7213_ALC_ATTEN_GAIN_MAX_MAX, + DA7213_NO_INVERT, alc_gain_tlv), + SOC_SINGLE_TLV("ALC Min Analog Gain Volume", DA7213_ALC_ANA_GAIN_LIMITS, + DA7213_ALC_ANA_GAIN_MIN_SHIFT, DA7213_ALC_ANA_GAIN_MAX, + DA7213_NO_INVERT, alc_analog_gain_tlv), + SOC_SINGLE_TLV("ALC Max Analog Gain Volume", DA7213_ALC_ANA_GAIN_LIMITS, + DA7213_ALC_ANA_GAIN_MAX_SHIFT, DA7213_ALC_ANA_GAIN_MAX, + DA7213_NO_INVERT, alc_analog_gain_tlv), + SOC_SINGLE("ALC Anticlip Mode Switch", DA7213_ALC_ANTICLIP_CTRL, + DA7213_ALC_ANTICLIP_EN_SHIFT, DA7213_ALC_ANTICLIP_EN_MAX, + DA7213_NO_INVERT), + SOC_SINGLE("ALC Anticlip Level", DA7213_ALC_ANTICLIP_LEVEL, + DA7213_ALC_ANTICLIP_LEVEL_SHIFT, + DA7213_ALC_ANTICLIP_LEVEL_MAX, DA7213_NO_INVERT), +}; + + +/* + * DAPM + */ + +/* + * Enums + */ + +/* MIC PGA source select */ +static const char * const da7213_mic_amp_in_sel_txt[] = { + "Differential", "MIC_P", "MIC_N" +}; + +static const struct soc_enum da7213_mic_1_amp_in_sel = + SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, + DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = + SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); + +static const struct soc_enum da7213_mic_2_amp_in_sel = + SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, + DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = + SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); + +/* DAI routing select */ +static const char * const da7213_dai_src_txt[] = { + "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" +}; + +static const struct soc_enum da7213_dai_l_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT, + DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static const struct snd_kcontrol_new da7213_dai_l_src_mux = + SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); + +static const struct soc_enum da7213_dai_r_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT, + DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static const struct snd_kcontrol_new da7213_dai_r_src_mux = + SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); + +/* DAC routing select */ +static const char * const da7213_dac_src_txt[] = { + "ADC Output Left", "ADC Output Right", "DAI Input Left", + "DAI Input Right" +}; + +static const struct soc_enum da7213_dac_l_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT, + DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static const struct snd_kcontrol_new da7213_dac_l_src_mux = + SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); + +static const struct soc_enum da7213_dac_r_src = + SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT, + DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static const struct snd_kcontrol_new da7213_dac_r_src_mux = + SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); + +/* + * Mixer Controls + */ + +/* Mixin Left */ +static const struct snd_kcontrol_new da7213_dapm_mixinl_controls[] = { + SOC_DAPM_SINGLE("Aux Left Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 1 Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 2 Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXIN_L_SELECT, + DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT, + DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + +/* Mixin Right */ +static const struct snd_kcontrol_new da7213_dapm_mixinr_controls[] = { + SOC_DAPM_SINGLE("Aux Right Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 2 Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mic 1 Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXIN_R_SELECT, + DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT, + DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + +/* Mixout Left */ +static const struct snd_kcontrol_new da7213_dapm_mixoutl_controls[] = { + SOC_DAPM_SINGLE("Aux Left Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("DAC Left Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Aux Left Invert Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA7213_MIXOUT_L_SELECT, + DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT, + DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + +/* Mixout Right */ +static const struct snd_kcontrol_new da7213_dapm_mixoutr_controls[] = { + SOC_DAPM_SINGLE("Aux Right Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("DAC Right Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Aux Right Invert Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), + SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA7213_MIXOUT_R_SELECT, + DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT, + DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT), +}; + + +/* + * DAPM widgets + */ + +static const struct snd_soc_dapm_widget da7213_dapm_widgets[] = { + /* + * Input & Output + */ + + /* Use a supply here as this controls both input & output DAIs */ + SND_SOC_DAPM_SUPPLY("DAI", DA7213_DAI_CTRL, DA7213_DAI_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + + /* + * Input + */ + + /* Input Lines */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("AUXL"), + SND_SOC_DAPM_INPUT("AUXR"), + + /* MUXs for Mic PGA source selection */ + SND_SOC_DAPM_MUX("Mic 1 Amp Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_mic_1_amp_in_sel_mux), + SND_SOC_DAPM_MUX("Mic 2 Amp Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_mic_2_amp_in_sel_mux), + + /* Input PGAs */ + SND_SOC_DAPM_PGA("Mic 1 PGA", DA7213_MIC_1_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mic 2 PGA", DA7213_MIC_2_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Aux Left PGA", DA7213_AUX_L_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Aux Right PGA", DA7213_AUX_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mixin Left PGA", DA7213_MIXIN_L_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mixin Right PGA", DA7213_MIXIN_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + + /* Mic Biases */ + SND_SOC_DAPM_SUPPLY("Mic Bias 1", DA7213_MICBIAS_CTRL, + DA7213_MICBIAS1_EN_SHIFT, DA7213_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias 2", DA7213_MICBIAS_CTRL, + DA7213_MICBIAS2_EN_SHIFT, DA7213_NO_INVERT, + NULL, 0), + + /* Input Mixers */ + SND_SOC_DAPM_MIXER("Mixin Left", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixinl_controls[0], + ARRAY_SIZE(da7213_dapm_mixinl_controls)), + SND_SOC_DAPM_MIXER("Mixin Right", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixinr_controls[0], + ARRAY_SIZE(da7213_dapm_mixinr_controls)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC Left", NULL, DA7213_ADC_L_CTRL, + DA7213_ADC_EN_SHIFT, DA7213_NO_INVERT), + SND_SOC_DAPM_ADC("ADC Right", NULL, DA7213_ADC_R_CTRL, + DA7213_ADC_EN_SHIFT, DA7213_NO_INVERT), + + /* DAI */ + SND_SOC_DAPM_MUX("DAI Left Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dai_l_src_mux), + SND_SOC_DAPM_MUX("DAI Right Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dai_r_src_mux), + SND_SOC_DAPM_AIF_OUT("DAIOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DAIOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), + + /* + * Output + */ + + /* DAI */ + SND_SOC_DAPM_AIF_IN("DAIINL", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DAIINR", "Playback", 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("DAC Left Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dac_l_src_mux), + SND_SOC_DAPM_MUX("DAC Right Source MUX", SND_SOC_NOPM, 0, 0, + &da7213_dac_r_src_mux), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC Left", NULL, DA7213_DAC_L_CTRL, + DA7213_DAC_EN_SHIFT, DA7213_NO_INVERT), + SND_SOC_DAPM_DAC("DAC Right", NULL, DA7213_DAC_R_CTRL, + DA7213_DAC_EN_SHIFT, DA7213_NO_INVERT), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("Mixout Left", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixoutl_controls[0], + ARRAY_SIZE(da7213_dapm_mixoutl_controls)), + SND_SOC_DAPM_MIXER("Mixout Right", SND_SOC_NOPM, 0, 0, + &da7213_dapm_mixoutr_controls[0], + ARRAY_SIZE(da7213_dapm_mixoutr_controls)), + + /* Output PGAs */ + SND_SOC_DAPM_PGA("Mixout Left PGA", DA7213_MIXOUT_L_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Mixout Right PGA", DA7213_MIXOUT_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Lineout PGA", DA7213_LINE_CTRL, DA7213_AMP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Headphone Left PGA", DA7213_HP_L_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA("Headphone Right PGA", DA7213_HP_R_CTRL, + DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0), + + /* Charge Pump */ + SND_SOC_DAPM_SUPPLY("Charge Pump", DA7213_CP_CTRL, DA7213_CP_EN_SHIFT, + DA7213_NO_INVERT, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + SND_SOC_DAPM_OUTPUT("LINE"), +}; + + +/* + * DAPM audio route definition + */ + +static const struct snd_soc_dapm_route da7213_audio_map[] = { + /* Dest Connecting Widget source */ + + /* Input path */ + {"MIC1", NULL, "Mic Bias 1"}, + {"MIC2", NULL, "Mic Bias 2"}, + + {"Mic 1 Amp Source MUX", "Differential", "MIC1"}, + {"Mic 1 Amp Source MUX", "MIC_P", "MIC1"}, + {"Mic 1 Amp Source MUX", "MIC_N", "MIC1"}, + + {"Mic 2 Amp Source MUX", "Differential", "MIC2"}, + {"Mic 2 Amp Source MUX", "MIC_P", "MIC2"}, + {"Mic 2 Amp Source MUX", "MIC_N", "MIC2"}, + + {"Mic 1 PGA", NULL, "Mic 1 Amp Source MUX"}, + {"Mic 2 PGA", NULL, "Mic 2 Amp Source MUX"}, + + {"Aux Left PGA", NULL, "AUXL"}, + {"Aux Right PGA", NULL, "AUXR"}, + + {"Mixin Left", "Aux Left Switch", "Aux Left PGA"}, + {"Mixin Left", "Mic 1 Switch", "Mic 1 PGA"}, + {"Mixin Left", "Mic 2 Switch", "Mic 2 PGA"}, + {"Mixin Left", "Mixin Right Switch", "Mixin Right PGA"}, + + {"Mixin Right", "Aux Right Switch", "Aux Right PGA"}, + {"Mixin Right", "Mic 2 Switch", "Mic 2 PGA"}, + {"Mixin Right", "Mic 1 Switch", "Mic 1 PGA"}, + {"Mixin Right", "Mixin Left Switch", "Mixin Left PGA"}, + + {"Mixin Left PGA", NULL, "Mixin Left"}, + {"ADC Left", NULL, "Mixin Left PGA"}, + + {"Mixin Right PGA", NULL, "Mixin Right"}, + {"ADC Right", NULL, "Mixin Right PGA"}, + + {"DAI Left Source MUX", "ADC Left", "ADC Left"}, + {"DAI Left Source MUX", "ADC Right", "ADC Right"}, + {"DAI Left Source MUX", "DAI Input Left", "DAIINL"}, + {"DAI Left Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAI Right Source MUX", "ADC Left", "ADC Left"}, + {"DAI Right Source MUX", "ADC Right", "ADC Right"}, + {"DAI Right Source MUX", "DAI Input Left", "DAIINL"}, + {"DAI Right Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAIOUTL", NULL, "DAI Left Source MUX"}, + {"DAIOUTR", NULL, "DAI Right Source MUX"}, + + {"DAIOUTL", NULL, "DAI"}, + {"DAIOUTR", NULL, "DAI"}, + + /* Output path */ + {"DAIINL", NULL, "DAI"}, + {"DAIINR", NULL, "DAI"}, + + {"DAC Left Source MUX", "ADC Output Left", "ADC Left"}, + {"DAC Left Source MUX", "ADC Output Right", "ADC Right"}, + {"DAC Left Source MUX", "DAI Input Left", "DAIINL"}, + {"DAC Left Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAC Right Source MUX", "ADC Output Left", "ADC Left"}, + {"DAC Right Source MUX", "ADC Output Right", "ADC Right"}, + {"DAC Right Source MUX", "DAI Input Left", "DAIINL"}, + {"DAC Right Source MUX", "DAI Input Right", "DAIINR"}, + + {"DAC Left", NULL, "DAC Left Source MUX"}, + {"DAC Right", NULL, "DAC Right Source MUX"}, + + {"Mixout Left", "Aux Left Switch", "Aux Left PGA"}, + {"Mixout Left", "Mixin Left Switch", "Mixin Left PGA"}, + {"Mixout Left", "Mixin Right Switch", "Mixin Right PGA"}, + {"Mixout Left", "DAC Left Switch", "DAC Left"}, + {"Mixout Left", "Aux Left Invert Switch", "Aux Left PGA"}, + {"Mixout Left", "Mixin Left Invert Switch", "Mixin Left PGA"}, + {"Mixout Left", "Mixin Right Invert Switch", "Mixin Right PGA"}, + + {"Mixout Right", "Aux Right Switch", "Aux Right PGA"}, + {"Mixout Right", "Mixin Right Switch", "Mixin Right PGA"}, + {"Mixout Right", "Mixin Left Switch", "Mixin Left PGA"}, + {"Mixout Right", "DAC Right Switch", "DAC Right"}, + {"Mixout Right", "Aux Right Invert Switch", "Aux Right PGA"}, + {"Mixout Right", "Mixin Right Invert Switch", "Mixin Right PGA"}, + {"Mixout Right", "Mixin Left Invert Switch", "Mixin Left PGA"}, + + {"Mixout Left PGA", NULL, "Mixout Left"}, + {"Mixout Right PGA", NULL, "Mixout Right"}, + + {"Headphone Left PGA", NULL, "Mixout Left PGA"}, + {"Headphone Left PGA", NULL, "Charge Pump"}, + {"HPL", NULL, "Headphone Left PGA"}, + + {"Headphone Right PGA", NULL, "Mixout Right PGA"}, + {"Headphone Right PGA", NULL, "Charge Pump"}, + {"HPR", NULL, "Headphone Right PGA"}, + + {"Lineout PGA", NULL, "Mixout Right PGA"}, + {"LINE", NULL, "Lineout PGA"}, +}; + +static struct reg_default da7213_reg_defaults[] = { + { DA7213_DIG_ROUTING_DAI, 0x10 }, + { DA7213_SR, 0x0A }, + { DA7213_REFERENCES, 0x80 }, + { DA7213_PLL_FRAC_TOP, 0x00 }, + { DA7213_PLL_FRAC_BOT, 0x00 }, + { DA7213_PLL_INTEGER, 0x20 }, + { DA7213_PLL_CTRL, 0x0C }, + { DA7213_DAI_CLK_MODE, 0x01 }, + { DA7213_DAI_CTRL, 0x08 }, + { DA7213_DIG_ROUTING_DAC, 0x32 }, + { DA7213_AUX_L_GAIN, 0x35 }, + { DA7213_AUX_R_GAIN, 0x35 }, + { DA7213_MIXIN_L_SELECT, 0x00 }, + { DA7213_MIXIN_R_SELECT, 0x00 }, + { DA7213_MIXIN_L_GAIN, 0x03 }, + { DA7213_MIXIN_R_GAIN, 0x03 }, + { DA7213_ADC_L_GAIN, 0x6F }, + { DA7213_ADC_R_GAIN, 0x6F }, + { DA7213_ADC_FILTERS1, 0x80 }, + { DA7213_MIC_1_GAIN, 0x01 }, + { DA7213_MIC_2_GAIN, 0x01 }, + { DA7213_DAC_FILTERS5, 0x00 }, + { DA7213_DAC_FILTERS2, 0x88 }, + { DA7213_DAC_FILTERS3, 0x88 }, + { DA7213_DAC_FILTERS4, 0x08 }, + { DA7213_DAC_FILTERS1, 0x80 }, + { DA7213_DAC_L_GAIN, 0x6F }, + { DA7213_DAC_R_GAIN, 0x6F }, + { DA7213_CP_CTRL, 0x61 }, + { DA7213_HP_L_GAIN, 0x39 }, + { DA7213_HP_R_GAIN, 0x39 }, + { DA7213_LINE_GAIN, 0x30 }, + { DA7213_MIXOUT_L_SELECT, 0x00 }, + { DA7213_MIXOUT_R_SELECT, 0x00 }, + { DA7213_SYSTEM_MODES_INPUT, 0x00 }, + { DA7213_SYSTEM_MODES_OUTPUT, 0x00 }, + { DA7213_AUX_L_CTRL, 0x44 }, + { DA7213_AUX_R_CTRL, 0x44 }, + { DA7213_MICBIAS_CTRL, 0x11 }, + { DA7213_MIC_1_CTRL, 0x40 }, + { DA7213_MIC_2_CTRL, 0x40 }, + { DA7213_MIXIN_L_CTRL, 0x40 }, + { DA7213_MIXIN_R_CTRL, 0x40 }, + { DA7213_ADC_L_CTRL, 0x40 }, + { DA7213_ADC_R_CTRL, 0x40 }, + { DA7213_DAC_L_CTRL, 0x48 }, + { DA7213_DAC_R_CTRL, 0x40 }, + { DA7213_HP_L_CTRL, 0x41 }, + { DA7213_HP_R_CTRL, 0x40 }, + { DA7213_LINE_CTRL, 0x40 }, + { DA7213_MIXOUT_L_CTRL, 0x10 }, + { DA7213_MIXOUT_R_CTRL, 0x10 }, + { DA7213_LDO_CTRL, 0x00 }, + { DA7213_IO_CTRL, 0x00 }, + { DA7213_GAIN_RAMP_CTRL, 0x00}, + { DA7213_MIC_CONFIG, 0x00 }, + { DA7213_PC_COUNT, 0x00 }, + { DA7213_CP_VOL_THRESHOLD1, 0x32 }, + { DA7213_CP_DELAY, 0x95 }, + { DA7213_CP_DETECTOR, 0x00 }, + { DA7213_DAI_OFFSET, 0x00 }, + { DA7213_DIG_CTRL, 0x00 }, + { DA7213_ALC_CTRL2, 0x00 }, + { DA7213_ALC_CTRL3, 0x00 }, + { DA7213_ALC_NOISE, 0x3F }, + { DA7213_ALC_TARGET_MIN, 0x3F }, + { DA7213_ALC_TARGET_MAX, 0x00 }, + { DA7213_ALC_GAIN_LIMITS, 0xFF }, + { DA7213_ALC_ANA_GAIN_LIMITS, 0x71 }, + { DA7213_ALC_ANTICLIP_CTRL, 0x00 }, + { DA7213_ALC_ANTICLIP_LEVEL, 0x00 }, + { DA7213_ALC_OFFSET_MAN_M_L, 0x00 }, + { DA7213_ALC_OFFSET_MAN_U_L, 0x00 }, + { DA7213_ALC_OFFSET_MAN_M_R, 0x00 }, + { DA7213_ALC_OFFSET_MAN_U_R, 0x00 }, + { DA7213_ALC_CIC_OP_LVL_CTRL, 0x00 }, + { DA7213_DAC_NG_SETUP_TIME, 0x00 }, + { DA7213_DAC_NG_OFF_THRESHOLD, 0x00 }, + { DA7213_DAC_NG_ON_THRESHOLD, 0x00 }, + { DA7213_DAC_NG_CTRL, 0x00 }, +}; + +static bool da7213_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7213_STATUS1: + case DA7213_PLL_STATUS: + case DA7213_AUX_L_GAIN_STATUS: + case DA7213_AUX_R_GAIN_STATUS: + case DA7213_MIC_1_GAIN_STATUS: + case DA7213_MIC_2_GAIN_STATUS: + case DA7213_MIXIN_L_GAIN_STATUS: + case DA7213_MIXIN_R_GAIN_STATUS: + case DA7213_ADC_L_GAIN_STATUS: + case DA7213_ADC_R_GAIN_STATUS: + case DA7213_DAC_L_GAIN_STATUS: + case DA7213_DAC_R_GAIN_STATUS: + case DA7213_HP_L_GAIN_STATUS: + case DA7213_HP_R_GAIN_STATUS: + case DA7213_LINE_GAIN_STATUS: + case DA7213_ALC_CTRL1: + case DA7213_ALC_OFFSET_AUTO_M_L: + case DA7213_ALC_OFFSET_AUTO_U_L: + case DA7213_ALC_OFFSET_AUTO_M_R: + case DA7213_ALC_OFFSET_AUTO_U_R: + case DA7213_ALC_CIC_OP_LVL_DATA: + return 1; + default: + return 0; + } +} + +static int da7213_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + u8 dai_ctrl = 0; + u8 fs; + + /* Set DAI format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S24_LE; + break; + case SNDRV_PCM_FORMAT_S32_LE: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S32_LE; + break; + default: + return -EINVAL; + } + + /* Set sampling rate */ + switch (params_rate(params)) { + case 8000: + fs = DA7213_SR_8000; + break; + case 11025: + fs = DA7213_SR_11025; + break; + case 12000: + fs = DA7213_SR_12000; + break; + case 16000: + fs = DA7213_SR_16000; + break; + case 22050: + fs = DA7213_SR_22050; + break; + case 32000: + fs = DA7213_SR_32000; + break; + case 44100: + fs = DA7213_SR_44100; + break; + case 48000: + fs = DA7213_SR_48000; + break; + case 88200: + fs = DA7213_SR_88200; + break; + case 96000: + fs = DA7213_SR_96000; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_WORD_LENGTH_MASK, + dai_ctrl); + snd_soc_write(codec, DA7213_SR, fs); + + return 0; +} + +static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + u8 dai_clk_mode = 0, dai_ctrl = 0; + + /* Set master/slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + dai_clk_mode |= DA7213_DAI_CLK_EN_MASTER_MODE; + da7213->master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + dai_clk_mode |= DA7213_DAI_CLK_EN_SLAVE_MODE; + da7213->master = false; + break; + default: + return -EINVAL; + } + + /* Set clock normal/inverted */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7213_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7213_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7213_DAI_WCLK_POL_INV | DA7213_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } + + /* Only I2S is supported */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dai_ctrl |= DA7213_DAI_FORMAT_I2S_MODE; + break; + case SND_SOC_DAIFMT_LEFT_J: + dai_ctrl |= DA7213_DAI_FORMAT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dai_ctrl |= DA7213_DAI_FORMAT_RIGHT_J; + break; + default: + return -EINVAL; + } + + /* By default only 32 BCLK per WCLK is supported */ + dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_32; + + snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode); + snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK, + dai_ctrl); + + return 0; +} + +static int da7213_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + snd_soc_update_bits(codec, DA7213_DAC_L_CTRL, + DA7213_MUTE_EN, DA7213_MUTE_EN); + snd_soc_update_bits(codec, DA7213_DAC_R_CTRL, + DA7213_MUTE_EN, DA7213_MUTE_EN); + } else { + snd_soc_update_bits(codec, DA7213_DAC_L_CTRL, + DA7213_MUTE_EN, 0); + snd_soc_update_bits(codec, DA7213_DAC_R_CTRL, + DA7213_MUTE_EN, 0); + } + + return 0; +} + +#define DA7213_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case DA7213_CLKSRC_MCLK: + if ((freq == 32768) || + ((freq >= 5000000) && (freq <= 54000000))) { + da7213->mclk_rate = freq; + return 0; + } else { + dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", + freq); + return -EINVAL; + } + break; + default: + dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + return -EINVAL; + } +} + +/* Supported PLL input frequencies are 5MHz - 54MHz. */ +static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + + u8 pll_ctrl, indiv_bits, indiv; + u8 pll_frac_top, pll_frac_bot, pll_integer; + u32 freq_ref; + u64 frac_div; + + /* Reset PLL configuration */ + snd_soc_write(codec, DA7213_PLL_CTRL, 0); + + pll_ctrl = 0; + + /* Workout input divider based on MCLK rate */ + if ((da7213->mclk_rate == 32768) && (source == DA7213_SYSCLK_PLL)) { + /* 32KHz PLL Mode */ + indiv_bits = DA7213_PLL_INDIV_10_20_MHZ; + indiv = DA7213_PLL_INDIV_10_20_MHZ_VAL; + freq_ref = 3750000; + pll_ctrl |= DA7213_PLL_32K_MODE; + } else { + /* 5 - 54MHz MCLK */ + if (da7213->mclk_rate < 5000000) { + goto pll_err; + } else if (da7213->mclk_rate <= 10000000) { + indiv_bits = DA7213_PLL_INDIV_5_10_MHZ; + indiv = DA7213_PLL_INDIV_5_10_MHZ_VAL; + } else if (da7213->mclk_rate <= 20000000) { + indiv_bits = DA7213_PLL_INDIV_10_20_MHZ; + indiv = DA7213_PLL_INDIV_10_20_MHZ_VAL; + } else if (da7213->mclk_rate <= 40000000) { + indiv_bits = DA7213_PLL_INDIV_20_40_MHZ; + indiv = DA7213_PLL_INDIV_20_40_MHZ_VAL; + } else if (da7213->mclk_rate <= 54000000) { + indiv_bits = DA7213_PLL_INDIV_40_54_MHZ; + indiv = DA7213_PLL_INDIV_40_54_MHZ_VAL; + } else { + goto pll_err; + } + freq_ref = (da7213->mclk_rate / indiv); + } + + pll_ctrl |= indiv_bits; + + /* PLL Bypass mode */ + if (source == DA7213_SYSCLK_MCLK) { + snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + return 0; + } + + /* + * If Codec is slave and SRM enabled, + * freq_out is (98304000 + 90316800)/2 = 94310400 + */ + if (!da7213->master && da7213->srm_en) { + fout = DA7213_PLL_FREQ_OUT_94310400; + pll_ctrl |= DA7213_PLL_SRM_EN; + } + + /* Enable MCLK squarer if required */ + if (da7213->mclk_squarer_en) + pll_ctrl |= DA7213_PLL_MCLK_SQR_EN; + + /* Calculate dividers for PLL */ + pll_integer = fout / freq_ref; + frac_div = (u64)(fout % freq_ref) * 8192ULL; + do_div(frac_div, freq_ref); + pll_frac_top = (frac_div >> DA7213_BYTE_SHIFT) & DA7213_BYTE_MASK; + pll_frac_bot = (frac_div) & DA7213_BYTE_MASK; + + /* Write PLL dividers */ + snd_soc_write(codec, DA7213_PLL_FRAC_TOP, pll_frac_top); + snd_soc_write(codec, DA7213_PLL_FRAC_BOT, pll_frac_bot); + snd_soc_write(codec, DA7213_PLL_INTEGER, pll_integer); + + /* Enable PLL */ + pll_ctrl |= DA7213_PLL_EN; + snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + + return 0; + +pll_err: + dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", + da7213->mclk_rate); + return -EINVAL; +} + +/* DAI operations */ +static const struct snd_soc_dai_ops da7213_dai_ops = { + .hw_params = da7213_hw_params, + .set_fmt = da7213_set_dai_fmt, + .set_sysclk = da7213_set_dai_sysclk, + .set_pll = da7213_set_dai_pll, + .digital_mute = da7213_mute, +}; + +static struct snd_soc_dai_driver da7213_dai = { + .name = "da7213-hifi", + /* Playback Capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7213_FORMATS, + }, + /* Capture Capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7213_FORMATS, + }, + .ops = &da7213_dai_ops, + .symmetric_rates = 1, +}; + +static int da7213_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + /* Enable VMID reference & master bias */ + snd_soc_update_bits(codec, DA7213_REFERENCES, + DA7213_VMID_EN | DA7213_BIAS_EN, + DA7213_VMID_EN | DA7213_BIAS_EN); + } + break; + case SND_SOC_BIAS_OFF: + /* Disable VMID reference & master bias */ + snd_soc_update_bits(codec, DA7213_REFERENCES, + DA7213_VMID_EN | DA7213_BIAS_EN, 0); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static int da7213_probe(struct snd_soc_codec *codec) +{ + int ret; + struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); + struct da7213_platform_data *pdata = da7213->pdata; + + codec->control_data = da7213->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + /* Default to using ALC auto offset calibration mode. */ + snd_soc_update_bits(codec, DA7213_ALC_CTRL1, + DA7213_ALC_CALIB_MODE_MAN, 0); + da7213->alc_calib_auto = true; + + /* Default to using SRM for slave mode */ + da7213->srm_en = true; + + /* Enable all Gain Ramps */ + snd_soc_update_bits(codec, DA7213_AUX_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_AUX_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_MIXIN_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_MIXIN_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_ADC_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_ADC_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_DAC_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_DAC_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_HP_L_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_HP_R_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + snd_soc_update_bits(codec, DA7213_LINE_CTRL, + DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); + + /* + * There are two separate control bits for input and output mixers as + * well as headphone and line outs. + * One to enable corresponding amplifier and other to enable its + * output. As amplifier bits are related to power control, they are + * being managed by DAPM while other (non power related) bits are + * enabled here + */ + snd_soc_update_bits(codec, DA7213_MIXIN_L_CTRL, + DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN); + snd_soc_update_bits(codec, DA7213_MIXIN_R_CTRL, + DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN); + + snd_soc_update_bits(codec, DA7213_MIXOUT_L_CTRL, + DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN); + snd_soc_update_bits(codec, DA7213_MIXOUT_R_CTRL, + DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN); + + snd_soc_update_bits(codec, DA7213_HP_L_CTRL, + DA7213_HP_AMP_OE, DA7213_HP_AMP_OE); + snd_soc_update_bits(codec, DA7213_HP_R_CTRL, + DA7213_HP_AMP_OE, DA7213_HP_AMP_OE); + + snd_soc_update_bits(codec, DA7213_LINE_CTRL, + DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE); + + /* Set platform data values */ + if (da7213->pdata) { + u8 micbias_lvl = 0, dmic_cfg = 0; + + /* Set Mic Bias voltages */ + switch (pdata->micbias1_lvl) { + case DA7213_MICBIAS_1_6V: + case DA7213_MICBIAS_2_2V: + case DA7213_MICBIAS_2_5V: + case DA7213_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias1_lvl << + DA7213_MICBIAS1_LEVEL_SHIFT); + break; + } + switch (pdata->micbias2_lvl) { + case DA7213_MICBIAS_1_6V: + case DA7213_MICBIAS_2_2V: + case DA7213_MICBIAS_2_5V: + case DA7213_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias2_lvl << + DA7213_MICBIAS2_LEVEL_SHIFT); + break; + } + snd_soc_update_bits(codec, DA7213_MICBIAS_CTRL, + DA7213_MICBIAS1_LEVEL_MASK | + DA7213_MICBIAS2_LEVEL_MASK, micbias_lvl); + + /* Set DMIC configuration */ + switch (pdata->dmic_data_sel) { + case DA7213_DMIC_DATA_LFALL_RRISE: + case DA7213_DMIC_DATA_LRISE_RFALL: + dmic_cfg |= (pdata->dmic_data_sel << + DA7213_DMIC_DATA_SEL_SHIFT); + break; + } + switch (pdata->dmic_data_sel) { + case DA7213_DMIC_SAMPLE_ON_CLKEDGE: + case DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE: + dmic_cfg |= (pdata->dmic_data_sel << + DA7213_DMIC_SAMPLEPHASE_SHIFT); + break; + } + switch (pdata->dmic_data_sel) { + case DA7213_DMIC_CLK_3_0MHZ: + case DA7213_DMIC_CLK_1_5MHZ: + dmic_cfg |= (pdata->dmic_data_sel << + DA7213_DMIC_CLK_RATE_SHIFT); + break; + } + snd_soc_update_bits(codec, DA7213_MIC_CONFIG, + DA7213_DMIC_DATA_SEL_MASK | + DA7213_DMIC_SAMPLEPHASE_MASK | + DA7213_DMIC_CLK_RATE_MASK, dmic_cfg); + + /* Set MCLK squaring */ + da7213->mclk_squarer_en = pdata->mclk_squaring; + } + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_da7213 = { + .probe = da7213_probe, + .set_bias_level = da7213_set_bias_level, + + .controls = da7213_snd_controls, + .num_controls = ARRAY_SIZE(da7213_snd_controls), + + .dapm_widgets = da7213_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets), + .dapm_routes = da7213_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), +}; + +static const struct regmap_config da7213_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = da7213_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults), + .volatile_reg = da7213_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int da7213_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da7213_priv *da7213; + struct da7213_platform_data *pdata = dev_get_platdata(&i2c->dev); + int ret; + + da7213 = devm_kzalloc(&i2c->dev, sizeof(struct da7213_priv), + GFP_KERNEL); + if (!da7213) + return -ENOMEM; + + if (pdata) + da7213->pdata = pdata; + + i2c_set_clientdata(i2c, da7213); + + da7213->regmap = devm_regmap_init_i2c(i2c, &da7213_regmap_config); + if (IS_ERR(da7213->regmap)) { + ret = PTR_ERR(da7213->regmap); + dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_da7213, &da7213_dai, 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register da7213 codec: %d\n", + ret); + } + return ret; +} + +static int da7213_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id da7213_i2c_id[] = { + { "da7213", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, da7213_i2c_id); + +/* I2C codec control layer */ +static struct i2c_driver da7213_i2c_driver = { + .driver = { + .name = "da7213", + .owner = THIS_MODULE, + }, + .probe = da7213_i2c_probe, + .remove = da7213_remove, + .id_table = da7213_i2c_id, +}; + +module_i2c_driver(da7213_i2c_driver); + +MODULE_DESCRIPTION("ASoC DA7213 Codec driver"); +MODULE_AUTHOR("Adam Thomson "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h new file mode 100644 index 000000000000..9cb9ddd01282 --- /dev/null +++ b/sound/soc/codecs/da7213.h @@ -0,0 +1,523 @@ +/* + * da7213.h - DA7213 ASoC Codec Driver + * + * Copyright (c) 2013 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DA7213_H +#define _DA7213_H + +#include +#include + +/* + * Registers + */ + +/* Status Registers */ +#define DA7213_STATUS1 0x02 +#define DA7213_PLL_STATUS 0x03 +#define DA7213_AUX_L_GAIN_STATUS 0x04 +#define DA7213_AUX_R_GAIN_STATUS 0x05 +#define DA7213_MIC_1_GAIN_STATUS 0x06 +#define DA7213_MIC_2_GAIN_STATUS 0x07 +#define DA7213_MIXIN_L_GAIN_STATUS 0x08 +#define DA7213_MIXIN_R_GAIN_STATUS 0x09 +#define DA7213_ADC_L_GAIN_STATUS 0x0A +#define DA7213_ADC_R_GAIN_STATUS 0x0B +#define DA7213_DAC_L_GAIN_STATUS 0x0C +#define DA7213_DAC_R_GAIN_STATUS 0x0D +#define DA7213_HP_L_GAIN_STATUS 0x0E +#define DA7213_HP_R_GAIN_STATUS 0x0F +#define DA7213_LINE_GAIN_STATUS 0x10 + +/* System Initialisation Registers */ +#define DA7213_DIG_ROUTING_DAI 0x21 +#define DA7213_SR 0x22 +#define DA7213_REFERENCES 0x23 +#define DA7213_PLL_FRAC_TOP 0x24 +#define DA7213_PLL_FRAC_BOT 0x25 +#define DA7213_PLL_INTEGER 0x26 +#define DA7213_PLL_CTRL 0x27 +#define DA7213_DAI_CLK_MODE 0x28 +#define DA7213_DAI_CTRL 0x29 +#define DA7213_DIG_ROUTING_DAC 0x2A +#define DA7213_ALC_CTRL1 0x2B + +/* Input - Gain, Select and Filter Registers */ +#define DA7213_AUX_L_GAIN 0x30 +#define DA7213_AUX_R_GAIN 0x31 +#define DA7213_MIXIN_L_SELECT 0x32 +#define DA7213_MIXIN_R_SELECT 0x33 +#define DA7213_MIXIN_L_GAIN 0x34 +#define DA7213_MIXIN_R_GAIN 0x35 +#define DA7213_ADC_L_GAIN 0x36 +#define DA7213_ADC_R_GAIN 0x37 +#define DA7213_ADC_FILTERS1 0x38 +#define DA7213_MIC_1_GAIN 0x39 +#define DA7213_MIC_2_GAIN 0x3A + +/* Output - Gain, Select and Filter Registers */ +#define DA7213_DAC_FILTERS5 0x40 +#define DA7213_DAC_FILTERS2 0x41 +#define DA7213_DAC_FILTERS3 0x42 +#define DA7213_DAC_FILTERS4 0x43 +#define DA7213_DAC_FILTERS1 0x44 +#define DA7213_DAC_L_GAIN 0x45 +#define DA7213_DAC_R_GAIN 0x46 +#define DA7213_CP_CTRL 0x47 +#define DA7213_HP_L_GAIN 0x48 +#define DA7213_HP_R_GAIN 0x49 +#define DA7213_LINE_GAIN 0x4A +#define DA7213_MIXOUT_L_SELECT 0x4B +#define DA7213_MIXOUT_R_SELECT 0x4C + +/* System Controller Registers */ +#define DA7213_SYSTEM_MODES_INPUT 0x50 +#define DA7213_SYSTEM_MODES_OUTPUT 0x51 + +/* Control Registers */ +#define DA7213_AUX_L_CTRL 0x60 +#define DA7213_AUX_R_CTRL 0x61 +#define DA7213_MICBIAS_CTRL 0x62 +#define DA7213_MIC_1_CTRL 0x63 +#define DA7213_MIC_2_CTRL 0x64 +#define DA7213_MIXIN_L_CTRL 0x65 +#define DA7213_MIXIN_R_CTRL 0x66 +#define DA7213_ADC_L_CTRL 0x67 +#define DA7213_ADC_R_CTRL 0x68 +#define DA7213_DAC_L_CTRL 0x69 +#define DA7213_DAC_R_CTRL 0x6A +#define DA7213_HP_L_CTRL 0x6B +#define DA7213_HP_R_CTRL 0x6C +#define DA7213_LINE_CTRL 0x6D +#define DA7213_MIXOUT_L_CTRL 0x6E +#define DA7213_MIXOUT_R_CTRL 0x6F + +/* Configuration Registers */ +#define DA7213_LDO_CTRL 0x90 +#define DA7213_IO_CTRL 0x91 +#define DA7213_GAIN_RAMP_CTRL 0x92 +#define DA7213_MIC_CONFIG 0x93 +#define DA7213_PC_COUNT 0x94 +#define DA7213_CP_VOL_THRESHOLD1 0x95 +#define DA7213_CP_DELAY 0x96 +#define DA7213_CP_DETECTOR 0x97 +#define DA7213_DAI_OFFSET 0x98 +#define DA7213_DIG_CTRL 0x99 +#define DA7213_ALC_CTRL2 0x9A +#define DA7213_ALC_CTRL3 0x9B +#define DA7213_ALC_NOISE 0x9C +#define DA7213_ALC_TARGET_MIN 0x9D +#define DA7213_ALC_TARGET_MAX 0x9E +#define DA7213_ALC_GAIN_LIMITS 0x9F +#define DA7213_ALC_ANA_GAIN_LIMITS 0xA0 +#define DA7213_ALC_ANTICLIP_CTRL 0xA1 +#define DA7213_ALC_ANTICLIP_LEVEL 0xA2 + +#define DA7213_ALC_OFFSET_AUTO_M_L 0xA3 +#define DA7213_ALC_OFFSET_AUTO_U_L 0xA4 +#define DA7213_ALC_OFFSET_MAN_M_L 0xA6 +#define DA7213_ALC_OFFSET_MAN_U_L 0xA7 +#define DA7213_ALC_OFFSET_AUTO_M_R 0xA8 +#define DA7213_ALC_OFFSET_AUTO_U_R 0xA9 +#define DA7213_ALC_OFFSET_MAN_M_R 0xAB +#define DA7213_ALC_OFFSET_MAN_U_R 0xAC +#define DA7213_ALC_CIC_OP_LVL_CTRL 0xAD +#define DA7213_ALC_CIC_OP_LVL_DATA 0xAE +#define DA7213_DAC_NG_SETUP_TIME 0xAF +#define DA7213_DAC_NG_OFF_THRESHOLD 0xB0 +#define DA7213_DAC_NG_ON_THRESHOLD 0xB1 +#define DA7213_DAC_NG_CTRL 0xB2 + + +/* + * Bit fields + */ + +/* DA7213_SR = 0x22 */ +#define DA7213_SR_8000 (0x1 << 0) +#define DA7213_SR_11025 (0x2 << 0) +#define DA7213_SR_12000 (0x3 << 0) +#define DA7213_SR_16000 (0x5 << 0) +#define DA7213_SR_22050 (0x6 << 0) +#define DA7213_SR_24000 (0x7 << 0) +#define DA7213_SR_32000 (0x9 << 0) +#define DA7213_SR_44100 (0xA << 0) +#define DA7213_SR_48000 (0xB << 0) +#define DA7213_SR_88200 (0xE << 0) +#define DA7213_SR_96000 (0xF << 0) + +/* DA7213_REFERENCES = 0x23 */ +#define DA7213_BIAS_EN (0x1 << 3) +#define DA7213_VMID_EN (0x1 << 7) + +/* DA7213_PLL_CTRL = 0x27 */ +#define DA7213_PLL_INDIV_5_10_MHZ (0x0 << 2) +#define DA7213_PLL_INDIV_10_20_MHZ (0x1 << 2) +#define DA7213_PLL_INDIV_20_40_MHZ (0x2 << 2) +#define DA7213_PLL_INDIV_40_54_MHZ (0x3 << 2) +#define DA7213_PLL_INDIV_MASK (0x3 << 2) +#define DA7213_PLL_MCLK_SQR_EN (0x1 << 4) +#define DA7213_PLL_32K_MODE (0x1 << 5) +#define DA7213_PLL_SRM_EN (0x1 << 6) +#define DA7213_PLL_EN (0x1 << 7) + +/* DA7213_DAI_CLK_MODE = 0x28 */ +#define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_64 (0x1 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_128 (0x2 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0) +#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) +#define DA7213_DAI_CLK_POL_INV (0x1 << 2) +#define DA7213_DAI_WCLK_POL_INV (0x1 << 3) +#define DA7213_DAI_CLK_EN_SLAVE_MODE (0x0 << 7) +#define DA7213_DAI_CLK_EN_MASTER_MODE (0x1 << 7) +#define DA7213_DAI_CLK_EN_MASK (0x1 << 7) + +/* DA7213_DAI_CTRL = 0x29 */ +#define DA7213_DAI_FORMAT_I2S_MODE (0x0 << 0) +#define DA7213_DAI_FORMAT_LEFT_J (0x1 << 0) +#define DA7213_DAI_FORMAT_RIGHT_J (0x2 << 0) +#define DA7213_DAI_FORMAT_MASK (0x3 << 0) +#define DA7213_DAI_WORD_LENGTH_S16_LE (0x0 << 2) +#define DA7213_DAI_WORD_LENGTH_S20_LE (0x1 << 2) +#define DA7213_DAI_WORD_LENGTH_S24_LE (0x2 << 2) +#define DA7213_DAI_WORD_LENGTH_S32_LE (0x3 << 2) +#define DA7213_DAI_WORD_LENGTH_MASK (0x3 << 2) +#define DA7213_DAI_EN_SHIFT 7 + +/* DA7213_DIG_ROUTING_DAI = 0x21 */ +#define DA7213_DAI_L_SRC_SHIFT 0 +#define DA7213_DAI_R_SRC_SHIFT 4 +#define DA7213_DAI_SRC_MAX 4 + +/* DA7213_DIG_ROUTING_DAC = 0x2A */ +#define DA7213_DAC_L_SRC_SHIFT 0 +#define DA7213_DAC_L_MONO_SHIFT 3 +#define DA7213_DAC_R_SRC_SHIFT 4 +#define DA7213_DAC_R_MONO_SHIFT 7 +#define DA7213_DAC_SRC_MAX 4 +#define DA7213_DAC_MONO_MAX 0x1 + +/* DA7213_ALC_CTRL1 = 0x2B */ +#define DA7213_ALC_OFFSET_EN_SHIFT 0 +#define DA7213_ALC_OFFSET_EN_MAX 0x1 +#define DA7213_ALC_OFFSET_EN (0x1 << 0) +#define DA7213_ALC_SYNC_MODE (0x1 << 1) +#define DA7213_ALC_CALIB_MODE_MAN (0x1 << 2) +#define DA7213_ALC_L_EN_SHIFT 3 +#define DA7213_ALC_AUTO_CALIB_EN (0x1 << 4) +#define DA7213_ALC_CALIB_OVERFLOW (0x1 << 5) +#define DA7213_ALC_R_EN_SHIFT 7 +#define DA7213_ALC_EN_MAX 0x1 + +/* DA7213_AUX_L/R_GAIN = 0x30/0x31 */ +#define DA7213_AUX_AMP_GAIN_SHIFT 0 +#define DA7213_AUX_AMP_GAIN_MAX 0x3F + +/* DA7213_MIXIN_L/R_SELECT = 0x32/0x33 */ +#define DA7213_DMIC_EN_SHIFT 7 +#define DA7213_DMIC_EN_MAX 0x1 + +/* DA7213_MIXIN_L_SELECT = 0x32 */ +#define DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT 0 +#define DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT 1 +#define DA7213_MIXIN_L_MIX_SELECT_MIC_1 (0x1 << 1) +#define DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT 2 +#define DA7213_MIXIN_L_MIX_SELECT_MIC_2 (0x1 << 2) +#define DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT 3 +#define DA7213_MIXIN_L_MIX_SELECT_MAX 0x1 + +/* DA7213_MIXIN_R_SELECT = 0x33 */ +#define DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT 0 +#define DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT 1 +#define DA7213_MIXIN_R_MIX_SELECT_MIC_2 (0x1 << 1) +#define DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT 2 +#define DA7213_MIXIN_R_MIX_SELECT_MIC_1 (0x1 << 2) +#define DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT 3 +#define DA7213_MIXIN_R_MIX_SELECT_MAX 0x1 +#define DA7213_MIC_BIAS_OUTPUT_SELECT_2 (0x1 << 6) + +/* DA7213_MIXIN_L/R_GAIN = 0x34/0x35 */ +#define DA7213_MIXIN_AMP_GAIN_SHIFT 0 +#define DA7213_MIXIN_AMP_GAIN_MAX 0xF + +/* DA7213_ADC_L/R_GAIN = 0x36/0x37 */ +#define DA7213_ADC_AMP_GAIN_SHIFT 0 +#define DA7213_ADC_AMP_GAIN_MAX 0x7F + +/* DA7213_ADC/DAC_FILTERS1 = 0x38/0x44 */ +#define DA7213_VOICE_HPF_CORNER_SHIFT 0 +#define DA7213_VOICE_HPF_CORNER_MAX 8 +#define DA7213_VOICE_EN_SHIFT 3 +#define DA7213_VOICE_EN_MAX 0x1 +#define DA7213_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7213_AUDIO_HPF_CORNER_MAX 4 +#define DA7213_HPF_EN_SHIFT 7 +#define DA7213_HPF_EN_MAX 0x1 + +/* DA7213_MIC_1/2_GAIN = 0x39/0x3A */ +#define DA7213_MIC_AMP_GAIN_SHIFT 0 +#define DA7213_MIC_AMP_GAIN_MAX 0x7 + +/* DA7213_DAC_FILTERS5 = 0x40 */ +#define DA7213_DAC_SOFTMUTE_EN_SHIFT 7 +#define DA7213_DAC_SOFTMUTE_EN_MAX 0x1 +#define DA7213_DAC_SOFTMUTE_RATE_SHIFT 4 +#define DA7213_DAC_SOFTMUTE_RATE_MAX 7 + +/* DA7213_DAC_FILTERS2/3/4 = 0x41/0x42/0x43 */ +#define DA7213_DAC_EQ_BAND_MAX 0xF + +/* DA7213_DAC_FILTERS2 = 0x41 */ +#define DA7213_DAC_EQ_BAND1_SHIFT 0 +#define DA7213_DAC_EQ_BAND2_SHIFT 4 + +/* DA7213_DAC_FILTERS2 = 0x42 */ +#define DA7213_DAC_EQ_BAND3_SHIFT 0 +#define DA7213_DAC_EQ_BAND4_SHIFT 4 + +/* DA7213_DAC_FILTERS4 = 0x43 */ +#define DA7213_DAC_EQ_BAND5_SHIFT 0 +#define DA7213_DAC_EQ_EN_SHIFT 7 +#define DA7213_DAC_EQ_EN_MAX 0x1 + +/* DA7213_DAC_L/R_GAIN = 0x45/0x46 */ +#define DA7213_DAC_AMP_GAIN_SHIFT 0 +#define DA7213_DAC_AMP_GAIN_MAX 0x7F + +/* DA7213_HP_L/R_GAIN = 0x45/0x46 */ +#define DA7213_HP_AMP_GAIN_SHIFT 0 +#define DA7213_HP_AMP_GAIN_MAX 0x3F + +/* DA7213_CP_CTRL = 0x47 */ +#define DA7213_CP_EN_SHIFT 7 + +/* DA7213_LINE_GAIN = 0x4A */ +#define DA7213_LINE_AMP_GAIN_SHIFT 0 +#define DA7213_LINE_AMP_GAIN_MAX 0x3F + +/* DA7213_MIXOUT_L_SELECT = 0x4B */ +#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT 0 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT 1 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT 2 +#define DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT 3 +#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT 4 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 5 +#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 6 +#define DA7213_MIXOUT_L_MIX_SELECT_MAX 0x1 + +/* DA7213_MIXOUT_R_SELECT = 0x4C */ +#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT 0 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT 1 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT 2 +#define DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT 3 +#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT 4 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 5 +#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 6 +#define DA7213_MIXOUT_R_MIX_SELECT_MAX 0x1 + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIC_1/2_CTRL = 0x63/0x64, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_ADC_L/R_CTRL = 0x65/0x66, + * DA7213_DAC_L/R_CTRL = 0x69/0x6A, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_MUTE_EN_SHIFT 6 +#define DA7213_MUTE_EN_MAX 0x1 +#define DA7213_MUTE_EN (0x1 << 6) + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_ADC_L/R_CTRL = 0x65/0x66, + * DA7213_DAC_L/R_CTRL = 0x69/0x6A, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_GAIN_RAMP_EN_SHIFT 5 +#define DA7213_GAIN_RAMP_EN_MAX 0x1 +#define DA7213_GAIN_RAMP_EN (0x1 << 5) + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_ZC_EN_SHIFT 4 +#define DA7213_ZC_EN_MAX 0x1 + +/* + * DA7213_AUX_L/R_CTRL = 0x60/0x61, + * DA7213_MIC_1/2_CTRL = 0x63/0x64, + * DA7213_MIXIN_L/R_CTRL = 0x65/0x66, + * DA7213_HP_L/R_CTRL = 0x6B/0x6C, + * DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F, + * DA7213_LINE_CTRL = 0x6D + */ +#define DA7213_AMP_EN_SHIFT 7 + +/* DA7213_MIC_1/2_CTRL = 0x63/0x64 */ +#define DA7213_MIC_AMP_IN_SEL_SHIFT 2 +#define DA7213_MIC_AMP_IN_SEL_MAX 3 + +/* DA7213_MICBIAS_CTRL = 0x62 */ +#define DA7213_MICBIAS1_LEVEL_SHIFT 0 +#define DA7213_MICBIAS1_LEVEL_MASK (0x3 << 0) +#define DA7213_MICBIAS1_EN_SHIFT 3 +#define DA7213_MICBIAS2_LEVEL_SHIFT 4 +#define DA7213_MICBIAS2_LEVEL_MASK (0x3 << 4) +#define DA7213_MICBIAS2_EN_SHIFT 7 + +/* DA7213_MIXIN_L/R_CTRL = 0x65/0x66 */ +#define DA7213_MIXIN_MIX_EN (0x1 << 3) + +/* DA7213_ADC_L/R_CTRL = 0x67/0x68 */ +#define DA7213_ADC_EN_SHIFT 7 +#define DA7213_ADC_EN (0x1 << 7) + +/* DA7213_DAC_L/R_CTRL = 0x69/0x6A*/ +#define DA7213_DAC_EN_SHIFT 7 + +/* DA7213_HP_L/R_CTRL = 0x6B/0x6C */ +#define DA7213_HP_AMP_OE (0x1 << 3) + +/* DA7213_LINE_CTRL = 0x6D */ +#define DA7213_LINE_AMP_OE (0x1 << 3) + +/* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F */ +#define DA7213_MIXOUT_MIX_EN (0x1 << 3) + +/* DA7213_GAIN_RAMP_CTRL = 0x92 */ +#define DA7213_GAIN_RAMP_RATE_SHIFT 0 +#define DA7213_GAIN_RAMP_RATE_MAX 4 + +/* DA7213_MIC_CONFIG = 0x93 */ +#define DA7213_DMIC_DATA_SEL_SHIFT 0 +#define DA7213_DMIC_DATA_SEL_MASK (0x1 << 0) +#define DA7213_DMIC_SAMPLEPHASE_SHIFT 1 +#define DA7213_DMIC_SAMPLEPHASE_MASK (0x1 << 1) +#define DA7213_DMIC_CLK_RATE_SHIFT 2 +#define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2) + +/* DA7213_DIG_CTRL = 0x99 */ +#define DA7213_DAC_L_INV_SHIFT 3 +#define DA7213_DAC_R_INV_SHIFT 7 +#define DA7213_DAC_INV_MAX 0x1 + +/* DA7213_ALC_CTRL2 = 0x9A */ +#define DA7213_ALC_ATTACK_SHIFT 0 +#define DA7213_ALC_ATTACK_MAX 13 +#define DA7213_ALC_RELEASE_SHIFT 4 +#define DA7213_ALC_RELEASE_MAX 11 + +/* DA7213_ALC_CTRL3 = 0x9B */ +#define DA7213_ALC_HOLD_SHIFT 0 +#define DA7213_ALC_HOLD_MAX 16 +#define DA7213_ALC_INTEG_ATTACK_SHIFT 4 +#define DA7213_ALC_INTEG_RELEASE_SHIFT 6 +#define DA7213_ALC_INTEG_MAX 4 + +/* + * DA7213_ALC_NOISE = 0x9C, + * DA7213_ALC_TARGET_MIN/MAX = 0x9D/0x9E + */ +#define DA7213_ALC_THRESHOLD_SHIFT 0 +#define DA7213_ALC_THRESHOLD_MAX 0x3F + +/* DA7213_ALC_GAIN_LIMITS = 0x9F */ +#define DA7213_ALC_ATTEN_MAX_SHIFT 0 +#define DA7213_ALC_GAIN_MAX_SHIFT 4 +#define DA7213_ALC_ATTEN_GAIN_MAX_MAX 0xF + +/* DA7213_ALC_ANA_GAIN_LIMITS = 0xA0 */ +#define DA7213_ALC_ANA_GAIN_MIN_SHIFT 0 +#define DA7213_ALC_ANA_GAIN_MAX_SHIFT 4 +#define DA7213_ALC_ANA_GAIN_MAX 0x7 + +/* DA7213_ALC_ANTICLIP_CTRL = 0xA1 */ +#define DA7213_ALC_ANTICLIP_EN_SHIFT 7 +#define DA7213_ALC_ANTICLIP_EN_MAX 0x1 + +/* DA7213_ALC_ANTICLIP_LEVEL = 0xA2 */ +#define DA7213_ALC_ANTICLIP_LEVEL_SHIFT 0 +#define DA7213_ALC_ANTICLIP_LEVEL_MAX 0x7F + +/* DA7213_ALC_CIC_OP_LVL_CTRL = 0xAD */ +#define DA7213_ALC_DATA_MIDDLE (0x2 << 0) +#define DA7213_ALC_DATA_TOP (0x3 << 0) +#define DA7213_ALC_CIC_OP_CHANNEL_LEFT (0x0 << 7) +#define DA7213_ALC_CIC_OP_CHANNEL_RIGHT (0x1 << 7) + +/* DA7213_DAC_NG_SETUP_TIME = 0xAF */ +#define DA7213_DAC_NG_SETUP_TIME_SHIFT 0 +#define DA7213_DAC_NG_SETUP_TIME_MAX 4 +#define DA7213_DAC_NG_RAMPUP_RATE_SHIFT 2 +#define DA7213_DAC_NG_RAMPDN_RATE_SHIFT 3 +#define DA7213_DAC_NG_RAMP_RATE_MAX 2 + +/* DA7213_DAC_NG_OFF/ON_THRESH = 0xB0/0xB1 */ +#define DA7213_DAC_NG_THRESHOLD_SHIFT 0 +#define DA7213_DAC_NG_THRESHOLD_MAX 0x7 + +/* DA7213_DAC_NG_CTRL = 0xB2 */ +#define DA7213_DAC_NG_EN_SHIFT 7 +#define DA7213_DAC_NG_EN_MAX 0x1 + + +/* + * General defines + */ + +/* Register inversion */ +#define DA7213_NO_INVERT 0 +#define DA7213_INVERT 1 + +/* Byte related defines */ +#define DA7213_BYTE_SHIFT 8 +#define DA7213_BYTE_MASK 0xFF + +/* ALC related */ +#define DA7213_ALC_OFFSET_15_8 0x00FF00 +#define DA7213_ALC_OFFSET_19_16 0x0F0000 +#define DA7213_ALC_AVG_ITERATIONS 5 + +/* PLL related */ +#define DA7213_SYSCLK_MCLK 0 +#define DA7213_SYSCLK_PLL 1 +#define DA7213_PLL_FREQ_OUT_90316800 90316800 +#define DA7213_PLL_FREQ_OUT_98304000 98304000 +#define DA7213_PLL_FREQ_OUT_94310400 94310400 +#define DA7213_PLL_INDIV_5_10_MHZ_VAL 2 +#define DA7213_PLL_INDIV_10_20_MHZ_VAL 4 +#define DA7213_PLL_INDIV_20_40_MHZ_VAL 8 +#define DA7213_PLL_INDIV_40_54_MHZ_VAL 16 + +enum clk_src { + DA7213_CLKSRC_MCLK +}; + +/* Codec private data */ +struct da7213_priv { + struct regmap *regmap; + unsigned int mclk_rate; + bool master; + bool mclk_squarer_en; + bool srm_en; + bool alc_calib_auto; + bool alc_en; + struct da7213_platform_data *pdata; +}; + +#endif /* _DA7213_H */ -- cgit v1.2.3