summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorKristoffer KARLSSON <kristoffer.karlsson@stericsson.com>2012-02-24 19:08:49 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:05:06 +0200
commit33fdce6d37048ac39be578523ce1677345706994 (patch)
treed994625af29c2dd9e080b024123d38f663e6a9e1 /sound
parent85d6cc09d321f313f4c10bb0011b76475cf7e407 (diff)
ASoC: Ux500: Sidetone sequence control and error handling
Implementation of sidetone write sequence control, read back and error handling in u8500 ASoC driver. ST-Ericsson Linux next: NA ST-Ericsson ID: 408244 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Iff0bef7e35876a011c1433718300d123c7a8c087 Signed-off-by: Kristoffer KARLSSON <kristoffer.karlsson@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/50478 Reviewed-by: QABUILD Reviewed-by: Ola LILJA2 <ola.o.lilja@stericsson.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/ab8500_audio.c459
-rw-r--r--sound/soc/codecs/ab8500_audio.h15
-rw-r--r--sound/soc/ux500/ux500_ab8500.c90
3 files changed, 260 insertions, 304 deletions
diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c
index d4fbaff9773..34809d0adf4 100644
--- a/sound/soc/codecs/ab8500_audio.c
+++ b/sound/soc/codecs/ab8500_audio.c
@@ -58,21 +58,9 @@
/* Nr of FIR/IIR-coeff banks in ANC-block */
#define AB8500_NR_OF_ANC_COEFF_BANKS 2
-/* Macros to simplify implementation of register write sequences and error handling */
-#define AB8500_SET_BIT_LOCKED(xreg, xbit, xerr, xerr_hdl) { \
- xerr = ab8500_codec_update_reg_audio_locked(ab8500_codec, \
- xreg, REG_MASK_NONE, BMASK(xbit)); \
- if (xerr < 0) \
- goto xerr_hdl; }
-#define AB8500_CLEAR_BIT_LOCKED(xreg, xbit, xerr, xerr_hdl) { \
- xerr = ab8500_codec_update_reg_audio_locked(ab8500_codec, \
- xreg, BMASK(xbit), REG_MASK_NONE); \
- if (xerr < 0) \
- goto xerr_hdl; }
-#define AB8500_WRITE(xreg, xvalue, xerr, xerr_hdl) { \
- xerr = ab8500_codec_write_reg_audio(ab8500_codec, xreg, xvalue); \
- if (xerr < 0) \
- goto xerr_hdl; }
+/* Minimum duration to keep ANC IIR Init bit high or
+low before proceeding with the configuration sequence */
+#define AB8500_ANC_SM_DELAY 2000
/*
* AB8500 register cache & default register settings
@@ -212,26 +200,13 @@ struct soc_smra_control {
long *values;
};
+/* Sidetone FIR-coeff cache */
+static long sid_fir_cache[REG_SID_FIR_COEFFS];
+
/* ANC FIR- & IIR-coeff caches */
static long anc_fir_cache[REG_ANC_FIR_COEFFS];
static long anc_iir_cache[REG_ANC_IIR_COEFFS];
-/* ANC states */
-enum anc_states {
- ANC_UNCONFIGURED = 0,
- ANC_CONFIGURE_FIR_IIR = 1,
- ANC_FIR_IIR_CONFIGURED = 2,
- ANC_CONFIGURE_FIR = 3,
- ANC_FIR_CONFIGURED = 4,
- ANC_CONFIGURE_IIR = 5,
- ANC_IIR_CONFIGURED = 6,
- ANC_ERROR = 7
-};
-static int ab8500_anc_status = ANC_UNCONFIGURED;
-
-/* ANC configuration lock */
-static DEFINE_MUTEX(ab8500_anc_conf_lock);
-
/* Reads an arbitrary register from the ab8500 chip.
*/
static int ab8500_codec_read_reg(struct snd_soc_codec *codec, unsigned int bank,
@@ -272,27 +247,17 @@ static int ab8500_codec_write_reg(struct snd_soc_codec *codec, unsigned int bank
return status;
}
-/* Reads an audio register from the cache.
+/* Reads an audio register from the cache or hardware.
*/
static unsigned int ab8500_codec_read_reg_audio(struct snd_soc_codec *codec,
unsigned int reg)
{
u8 *cache = codec->reg_cache;
- return cache[reg];
-}
-/* Reads an audio register from the hardware.
- */
-static int ab8500_codec_read_reg_audio_nocache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u8 *cache = codec->reg_cache;
- int value = ab8500_codec_read_reg(codec, AB8500_AUDIO, reg);
-
- if (value >= 0)
- cache[reg] = value;
+ if (reg == REG_SIDFIRCONF)
+ return ab8500_codec_read_reg(codec, AB8500_AUDIO, reg);
- return value;
+ return cache[reg];
}
/* Writes an audio register to the hardware and cache.
@@ -309,18 +274,6 @@ static int ab8500_codec_write_reg_audio(struct snd_soc_codec *codec,
return status;
}
-/* Dumps all audio registers.
- */
-static inline void ab8500_codec_dump_all_reg(struct snd_soc_codec *codec)
-{
- int i;
-
- pr_debug("%s Enter.\n", __func__);
-
- for (i = AB8500_FIRST_REG; i <= AB8500_LAST_REG; i++)
- ab8500_codec_read_reg_audio_nocache(codec, i);
-}
-
/*
* Updates an audio register.
*
@@ -342,23 +295,6 @@ static inline int ab8500_codec_update_reg_audio(struct snd_soc_codec *codec,
return (ret < 0) ? ret : 1;
}
-/*
- * Updates an audio register, and takes the codec mutex.
- *
- * Returns 1 for change, 0 for no change, or negative error code.
- */
-static int ab8500_codec_update_reg_audio_locked(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int clr, unsigned int ins)
-{
- int ret;
-
- mutex_lock(&codec->mutex);
- ret = ab8500_codec_update_reg_audio(codec, reg, clr, ins);
- mutex_unlock(&codec->mutex);
-
- return ret;
-}
-
/* Generic soc info for signed register controls. */
int snd_soc_info_s(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -505,18 +441,75 @@ int snd_soc_put_enum_strobe(struct snd_kcontrol *kcontrol,
unsigned int bit = e->shift_l;
unsigned int invert = e->shift_r != 0;
unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
- unsigned int clear_mask = (strobe ^ invert) ? REG_MASK_NONE : BMASK(bit);
+ unsigned int clr_mask = (strobe ^ invert) ? REG_MASK_NONE : BMASK(bit);
unsigned int set_mask = (strobe ^ invert) ? BMASK(bit) : REG_MASK_NONE;
- if (snd_soc_update_bits(codec, reg, clear_mask, set_mask) == 0)
+ if (snd_soc_update_bits(codec, reg, clr_mask, set_mask) == 0)
return 0;
- return snd_soc_update_bits(codec, reg, set_mask, clear_mask);
+ return snd_soc_update_bits(codec, reg, set_mask, clr_mask);
}
static const char * const enum_ena_dis[] = {"Enabled", "Disabled"};
static const char * const enum_dis_ena[] = {"Disabled", "Enabled"};
static const char * const enum_rdy_apl[] = {"Ready", "Apply"};
+/* Sidetone FIR-coefficients configuration sequence */
+static int sid_apply_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec;
+ unsigned int param, sidconf;
+ int ret = 0;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (ucontrol->value.integer.value[0] != 1) {
+ pr_err("%s: ERROR: This control supports 'Apply' only!\n",
+ __func__);
+ return ret;
+ }
+
+ codec = snd_kcontrol_chip(kcontrol);
+
+ mutex_lock(&codec->mutex);
+
+ sidconf = snd_soc_read(codec, REG_SIDFIRCONF);
+ if (((sidconf & BMASK(REG_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
+ if ((sidconf & BMASK(REG_SIDFIRCONF_ENFIRSIDS)) == 0) {
+ pr_err("%s: Sidetone busy while off. Resetting...\n",
+ __func__);
+ snd_soc_update_bits(codec, REG_SIDFIRADR,
+ REG_MASK_NONE, BMASK(REG_SIDFIRADR_FIRSIDSET));
+ snd_soc_update_bits(codec, REG_SIDFIRADR,
+ BMASK(REG_SIDFIRADR_FIRSIDSET), REG_MASK_NONE);
+ }
+ ret = -EBUSY;
+ goto out;
+ }
+
+ snd_soc_write(codec, REG_SIDFIRADR, REG_MASK_NONE);
+
+ for (param = 0; param < REG_SID_FIR_COEFFS; param++) {
+ snd_soc_write(codec, REG_SIDFIRCOEF1,
+ sid_fir_cache[param] >> 8 & REG_MASK_ALL);
+ snd_soc_write(codec, REG_SIDFIRCOEF2,
+ sid_fir_cache[param] & REG_MASK_ALL);
+ }
+
+ snd_soc_update_bits(codec, REG_SIDFIRADR,
+ REG_MASK_NONE, BMASK(REG_SIDFIRADR_FIRSIDSET));
+ snd_soc_update_bits(codec, REG_SIDFIRADR,
+ BMASK(REG_SIDFIRADR_FIRSIDSET), REG_MASK_NONE);
+
+ ret = 1;
+out:
+ mutex_unlock(&codec->mutex);
+
+ pr_debug("%s: Exit\n", __func__);
+
+ return ret;
+}
+
/* Controls - DAPM */
/* Inverted order - Ascending/Descending */
@@ -1752,8 +1745,7 @@ static SOC_ENUM_SINGLE_DECL(soc_enum_parlhf,
REG_CLASSDCONF1, REG_CLASSDCONF1_PARLHF, enum_dis_ena);
static SOC_ENUM_SINGLE_DECL(soc_enum_parlvib,
REG_CLASSDCONF1, REG_CLASSDCONF1_PARLVIB, enum_dis_ena);
-static SOC_ENUM_STROBE_DECL(soc_enum_applysidetone,
- REG_SIDFIRADR, REG_SIDFIRADR_FIRSIDSET, NORMAL, enum_rdy_apl);
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_applysidetone, enum_rdy_apl);
static struct snd_kcontrol_new ab8500_snd_controls[] = {
SOC_ENUM("Headset High Pass Playback Switch", soc_enum_hshpen),
@@ -1992,51 +1984,48 @@ static struct snd_kcontrol_new ab8500_snd_controls[] = {
REG_FIFOCONF6_BFIFOSAMPLE_MAX,
NORMAL),
- /* Sidetone */
- SOC_SINGLE("Sidetone FIR Coefficient Index",
- REG_SIDFIRADR,
- REG_SIDFIRADR_ADDRESS_SHIFT,
- REG_SIDFIRADR_ADDRESS_MAX,
- NORMAL),
- SOC_SINGLE_S2R("Sidetone FIR Coefficient Value",
- REG_SIDFIRCOEF1, REG_SIDFIRCOEF2,
- REG_SIDFIRCOEFX_VALUE_SHIFT,
- REG_SIDFIRCOEFX_VALUE_MAX,
- NORMAL),
- SOC_ENUM_STROBE("Sidetone FIR Apply Coefficients",
- soc_enum_applysidetone),
-
/* ANC */
SOC_SINGLE_S1R("ANC Warp Delay Shift",
REG_ANCCONF2,
REG_ANCCONF2_VALUE_MIN,
REG_ANCCONF2_VALUE_MAX,
- NORMAL),
+ 0),
SOC_SINGLE_S1R("ANC FIR Output Shift",
REG_ANCCONF3,
REG_ANCCONF3_VALUE_MIN,
REG_ANCCONF3_VALUE_MAX,
- NORMAL),
+ 0),
SOC_SINGLE_S1R("ANC IIR Output Shift",
REG_ANCCONF4,
REG_ANCCONF4_VALUE_MIN,
REG_ANCCONF4_VALUE_MAX,
- NORMAL),
+ 0),
SOC_SINGLE_S2R("ANC Warp Delay",
REG_ANCCONF9, REG_ANCCONF10,
REG_ANC_WARP_DELAY_MIN,
REG_ANC_WARP_DELAY_MAX,
- NORMAL),
+ 0),
SOC_MULTIPLE_SA("ANC FIR Coefficients",
anc_fir_cache,
REG_ANC_FIR_COEFF_MIN,
REG_ANC_FIR_COEFF_MAX,
- NORMAL),
+ 0),
SOC_MULTIPLE_SA("ANC IIR Coefficients",
anc_iir_cache,
REG_ANC_IIR_COEFF_MIN,
REG_ANC_IIR_COEFF_MAX,
- NORMAL),
+ 0),
+
+ /* Sidetone */
+ SOC_MULTIPLE_SA("Sidetone FIR Coefficients",
+ sid_fir_cache,
+ REG_SID_FIR_COEFF_MIN,
+ REG_SID_FIR_COEFF_MAX,
+ 0),
+ SOC_ENUM_EXT("Sidetone FIR Apply Coefficients",
+ soc_enum_applysidetone,
+ snd_soc_get_enum_double,
+ sid_apply_control_put),
};
static int ab8500_codec_set_format_if1(struct snd_soc_codec *codec, unsigned int fmt)
@@ -2335,230 +2324,143 @@ int ab8500_audio_setup_if1(struct snd_soc_codec *codec,
return 0;
}
-/* ANC block current configuration status */
-unsigned int ab8500_audio_anc_status(void)
+/* ANC FIR-coefficients configuration sequence */
+static void ab8500_audio_anc_fir(struct snd_soc_codec *codec,
+ unsigned int bank, unsigned int param)
{
- return ab8500_anc_status;
+ if (param == 0 && bank == 0)
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ REG_MASK_NONE, BMASK(REG_ANCCONF1_ANCFIRUPDATE));
+
+ snd_soc_write(codec, REG_ANCCONF5,
+ anc_fir_cache[param] >> 8 & REG_MASK_ALL);
+ snd_soc_write(codec, REG_ANCCONF6,
+ anc_fir_cache[param] & REG_MASK_ALL);
+
+ if (param == REG_ANC_FIR_COEFFS - 1 && bank == 1)
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ BMASK(REG_ANCCONF1_ANCFIRUPDATE), REG_MASK_NONE);
}
-/* ANC IIR-/FIR-coefficients configuration sequence */
-int ab8500_audio_anc_configure(unsigned int req_state)
+/* ANC IIR-coefficients configuration sequence */
+static void ab8500_audio_anc_iir(struct snd_soc_codec *codec,
+ unsigned int bank, unsigned int param)
{
- bool configure_fir = req_state == ANC_CONFIGURE_FIR ||
- req_state == ANC_CONFIGURE_FIR_IIR;
- bool configure_iir = req_state == ANC_CONFIGURE_IIR ||
- req_state == ANC_CONFIGURE_FIR_IIR;
- unsigned int bank, param;
- int ret;
-
- if (req_state == ANC_UNCONFIGURED ||
- req_state == ANC_FIR_IIR_CONFIGURED ||
- req_state == ANC_FIR_CONFIGURED ||
- req_state == ANC_IIR_CONFIGURED ||
- req_state == ANC_ERROR)
- return -EINVAL;
-
- mutex_lock(&ab8500_anc_conf_lock);
-
- if (configure_fir)
- AB8500_CLEAR_BIT_LOCKED(REG_ANCCONF1, REG_ANCCONF1_ENANC, ret, cleanup)
-
- AB8500_SET_BIT_LOCKED(REG_ANCCONF1, REG_ANCCONF1_ENANC, ret, cleanup)
-
- if (configure_fir) {
- for (bank = 0; bank < AB8500_NR_OF_ANC_COEFF_BANKS; bank++) {
- for (param = 0; param < REG_ANC_FIR_COEFFS; param++) {
- if (param == 0 && bank == 0)
- AB8500_SET_BIT_LOCKED(REG_ANCCONF1,
- REG_ANCCONF1_ANCFIRUPDATE, ret, cleanup)
-
- AB8500_WRITE(REG_ANCCONF5,
- anc_fir_cache[param] >> 8 & REG_MASK_ALL,
- ret, cleanup)
- AB8500_WRITE(REG_ANCCONF6,
- anc_fir_cache[param] & REG_MASK_ALL,
- ret, cleanup)
-
- if (param == REG_ANC_FIR_COEFFS - 1 && bank == 1)
- AB8500_CLEAR_BIT_LOCKED(REG_ANCCONF1,
- REG_ANCCONF1_ANCFIRUPDATE, ret, cleanup)
- }
+ if (param == 0) {
+ if (bank == 0) {
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ REG_MASK_NONE, BMASK(REG_ANCCONF1_ANCIIRINIT));
+ usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ BMASK(REG_ANCCONF1_ANCIIRINIT), REG_MASK_NONE);
+ usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+ } else {
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ REG_MASK_NONE, BMASK(REG_ANCCONF1_ANCIIRUPDATE));
}
- if (ab8500_anc_status == ANC_IIR_CONFIGURED)
- ab8500_anc_status = ANC_FIR_IIR_CONFIGURED;
- else if (ab8500_anc_status != ANC_FIR_IIR_CONFIGURED)
- ab8500_anc_status = ANC_FIR_CONFIGURED;
+ } else if (param > 3) {
+ snd_soc_write(codec, REG_ANCCONF7, REG_MASK_NONE);
+ snd_soc_write(codec, REG_ANCCONF8,
+ anc_iir_cache[param] >> 16 & REG_MASK_ALL);
}
- if (configure_iir) {
- for (bank = 0; bank < AB8500_NR_OF_ANC_COEFF_BANKS; bank++) {
- for (param = 0; param < REG_ANC_IIR_COEFFS; param++) {
- if (param == 0) {
- if (bank == 0) {
- AB8500_SET_BIT_LOCKED(REG_ANCCONF1,
- REG_ANCCONF1_ANCIIRINIT,
- ret, cleanup)
- udelay(2000);
- AB8500_CLEAR_BIT_LOCKED(REG_ANCCONF1,
- REG_ANCCONF1_ANCIIRINIT,
- ret, cleanup)
- udelay(2000);
- } else {
- AB8500_SET_BIT_LOCKED(REG_ANCCONF1,
- REG_ANCCONF1_ANCIIRUPDATE,
- ret, cleanup)
- }
- } else if (param > 3) {
- AB8500_WRITE(REG_ANCCONF7,
- REG_MASK_NONE, ret, cleanup)
- AB8500_WRITE(REG_ANCCONF8,
- anc_iir_cache[param] >> 16 & REG_MASK_ALL,
- ret, cleanup)
- }
-
- AB8500_WRITE(REG_ANCCONF7,
- anc_iir_cache[param] >> 8 & REG_MASK_ALL,
- ret, cleanup)
- AB8500_WRITE(REG_ANCCONF8,
- anc_iir_cache[param] & REG_MASK_ALL,
- ret, cleanup)
-
- if (param == REG_ANC_IIR_COEFFS - 1 && bank == 1)
- AB8500_CLEAR_BIT_LOCKED(REG_ANCCONF1,
- REG_ANCCONF1_ANCIIRUPDATE,
- ret, cleanup)
- }
- }
- if (ab8500_anc_status == ANC_FIR_CONFIGURED)
- ab8500_anc_status = ANC_FIR_IIR_CONFIGURED;
- else if (ab8500_anc_status != ANC_FIR_IIR_CONFIGURED)
- ab8500_anc_status = ANC_IIR_CONFIGURED;
- }
+ snd_soc_write(codec, REG_ANCCONF7,
+ anc_iir_cache[param] >> 8 & REG_MASK_ALL);
+ snd_soc_write(codec, REG_ANCCONF8,
+ anc_iir_cache[param] & REG_MASK_ALL);
- mutex_unlock(&ab8500_anc_conf_lock);
+ if (param == REG_ANC_IIR_COEFFS - 1 && bank == 1)
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ BMASK(REG_ANCCONF1_ANCIIRUPDATE), REG_MASK_NONE);
+}
- return 0;
+/* ANC IIR-/FIR-coefficients configuration sequence */
+void ab8500_audio_anc_configure(struct snd_soc_codec *codec,
+ bool apply_fir, bool apply_iir)
+{
+ unsigned int bank, param;
-cleanup:
- ret |= ab8500_codec_update_reg_audio_locked(ab8500_codec,
- REG_ANCCONF1,
- BMASK(REG_ANCCONF1_ENANC) |
- BMASK(REG_ANCCONF1_ANCIIRINIT) |
- BMASK(REG_ANCCONF1_ANCIIRUPDATE) |
- BMASK(REG_ANCCONF1_ANCFIRUPDATE),
- REG_MASK_NONE);
+ pr_debug("%s: Enter.\n", __func__);
- ab8500_anc_status = ANC_ERROR;
+ if (apply_fir)
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ BMASK(REG_ANCCONF1_ENANC), REG_MASK_NONE);
- mutex_unlock(&ab8500_anc_conf_lock);
+ snd_soc_update_bits(codec, REG_ANCCONF1,
+ REG_MASK_NONE, BMASK(REG_ANCCONF1_ENANC));
- return ret;
-}
+ if (apply_fir)
+ for (bank = 0; bank < AB8500_NR_OF_ANC_COEFF_BANKS; bank++)
+ for (param = 0; param < REG_ANC_FIR_COEFFS; param++)
+ ab8500_audio_anc_fir(codec, bank, param);
-bool ab8500_audio_dapm_path_active(enum ab8500_audio_dapm_path dapm_path)
-{
- int reg, reg_mask;
-
- switch (dapm_path) {
- case AB8500_AUDIO_DAPM_PATH_DMIC:
- reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_DIGMICCONF);
- reg_mask = BMASK(REG_DIGMICCONF_ENDMIC1) |
- BMASK(REG_DIGMICCONF_ENDMIC2) |
- BMASK(REG_DIGMICCONF_ENDMIC3) |
- BMASK(REG_DIGMICCONF_ENDMIC4) |
- BMASK(REG_DIGMICCONF_ENDMIC5) |
- BMASK(REG_DIGMICCONF_ENDMIC6);
- return reg & reg_mask;
-
- case AB8500_AUDIO_DAPM_PATH_AMIC1:
- reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_ANACONF2);
- reg_mask = BMASK(REG_ANACONF2_MUTMIC1);
- return !(reg & reg_mask);
-
- case AB8500_AUDIO_DAPM_PATH_AMIC2:
- reg = ab8500_codec_read_reg_audio(ab8500_codec, REG_ANACONF2);
- reg_mask = BMASK(REG_ANACONF2_MUTMIC2);
- return !(reg & reg_mask);
+ if (apply_iir)
+ for (bank = 0; bank < AB8500_NR_OF_ANC_COEFF_BANKS; bank++)
+ for (param = 0; param < REG_ANC_IIR_COEFFS; param++)
+ ab8500_audio_anc_iir(codec, bank, param);
- default:
- return false;
- }
+ pr_debug("%s: Exit.\n", __func__);
}
int ab8500_audio_set_adcm(enum ab8500_audio_adcm req_adcm)
{
- int ret = 0;
-
if (ab8500_codec == NULL) {
- pr_err("%s: ERROR: AB8500 ASoC-driver not yet probed!\n", __func__);
+ pr_err("%s: ERROR: AB8500 ASoC-driver not yet probed!\n",
+ __func__);
return -EIO;
}
if (adcm == req_adcm)
- return ret;
+ return 0;
+
+ pr_debug("%s: Enter.\n", __func__);
if (AB8500_AUDIO_ADCM_FORCE_UP == req_adcm ||
AB8500_AUDIO_ADCM_FORCE_DOWN == req_adcm) {
mutex_lock(&ab8500_codec->mutex);
- adcm_anaconf5 = ab8500_codec_read_reg_audio(ab8500_codec, REG_ANACONF5);
- adcm_muteconf = ab8500_codec_read_reg_audio(ab8500_codec, REG_MUTECONF);
- adcm_anaconf4 = ab8500_codec_read_reg_audio(ab8500_codec, REG_ANACONF4);
+ adcm_anaconf5 = snd_soc_read(ab8500_codec, REG_ANACONF5);
+ adcm_muteconf = snd_soc_read(ab8500_codec, REG_MUTECONF);
+ adcm_anaconf4 = snd_soc_read(ab8500_codec, REG_ANACONF4);
if (AB8500_AUDIO_ADCM_FORCE_UP == req_adcm) {
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_ANACONF5, REG_MASK_NONE, ADCM_ANACONF5_MASK);
- if (ret < 0)
- goto cleanup;
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_MUTECONF, REG_MASK_NONE, ADCM_MUTECONF_MASK);
- if (ret < 0)
- goto cleanup;
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_ANACONF4, REG_MASK_NONE, ADCM_ANACONF4_MASK);
- if (ret < 0)
- goto cleanup;
+ snd_soc_update_bits(ab8500_codec, REG_ANACONF5,
+ REG_MASK_NONE, ADCM_ANACONF5_MASK);
+ snd_soc_update_bits(ab8500_codec, REG_MUTECONF,
+ REG_MASK_NONE, ADCM_MUTECONF_MASK);
+ snd_soc_update_bits(ab8500_codec, REG_ANACONF4,
+ REG_MASK_NONE, ADCM_ANACONF4_MASK);
} else {
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_ANACONF5, ADCM_ANACONF5_MASK, REG_MASK_NONE);
- if (ret < 0)
- goto cleanup;
+ snd_soc_update_bits(ab8500_codec, REG_ANACONF5,
+ ADCM_ANACONF5_MASK, REG_MASK_NONE);
}
} else if (AB8500_AUDIO_ADCM_NORMAL == req_adcm) {
-
if (AB8500_AUDIO_ADCM_FORCE_UP == adcm) {
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_ANACONF5, ~adcm_anaconf5 & ADCM_ANACONF5_MASK,
+ snd_soc_update_bits(ab8500_codec, REG_ANACONF5,
+ ~adcm_anaconf5 & ADCM_ANACONF5_MASK,
adcm_anaconf5 & ADCM_ANACONF5_MASK);
- if (ret < 0)
- goto cleanup;
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_MUTECONF, ~adcm_muteconf & ADCM_MUTECONF_MASK,
+ snd_soc_update_bits(ab8500_codec, REG_MUTECONF,
+ ~adcm_muteconf & ADCM_MUTECONF_MASK,
adcm_muteconf & ADCM_MUTECONF_MASK);
- if (ret < 0)
- goto cleanup;
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_ANACONF4, ~adcm_anaconf4 & ADCM_ANACONF4_MASK,
+ snd_soc_update_bits(ab8500_codec, REG_ANACONF4,
+ ~adcm_anaconf4 & ADCM_ANACONF4_MASK,
adcm_anaconf4 & ADCM_ANACONF4_MASK);
- if (ret < 0)
- goto cleanup;
} else {
- ret |= ab8500_codec_update_reg_audio(ab8500_codec,
- REG_ANACONF5, ~adcm_anaconf5 & ADCM_ANACONF5_MASK,
+ snd_soc_update_bits(ab8500_codec, REG_ANACONF5,
+ ~adcm_anaconf5 & ADCM_ANACONF5_MASK,
adcm_anaconf5 & ADCM_ANACONF5_MASK);
- if (ret < 0)
- goto cleanup;
}
}
-cleanup:
- adcm = (ret < 0) ? AB8500_AUDIO_ADCM_NORMAL : req_adcm;
+ adcm = req_adcm;
if (AB8500_AUDIO_ADCM_NORMAL == adcm)
mutex_unlock(&ab8500_codec->mutex);
- return ret;
+ pr_debug("%s: Exit.\n", __func__);
+
+ return 0;
}
static int ab8500_codec_add_widgets(struct snd_soc_codec *codec)
@@ -2587,6 +2489,7 @@ static int ab8500_codec_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
{
pr_debug("%s Enter.\n", __func__);
+
return 0;
}
@@ -2603,10 +2506,6 @@ static int ab8500_codec_pcm_prepare(struct snd_pcm_substream *substream,
{
pr_debug("%s Enter.\n", __func__);
- /* Clear interrupt status registers by reading them. */
- ab8500_codec_read_reg_audio(dai->codec, REG_AUDINTSOURCE1);
- ab8500_codec_read_reg_audio(dai->codec, REG_AUDINTSOURCE2);
-
return 0;
}
@@ -2614,8 +2513,6 @@ static void ab8500_codec_pcm_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
pr_debug("%s Enter.\n", __func__);
-
- ab8500_codec_dump_all_reg(dai->codec);
}
static int ab8500_codec_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
diff --git a/sound/soc/codecs/ab8500_audio.h b/sound/soc/codecs/ab8500_audio.h
index c506f8d1e3c..72f7b383830 100644
--- a/sound/soc/codecs/ab8500_audio.h
+++ b/sound/soc/codecs/ab8500_audio.h
@@ -33,15 +33,9 @@ int ab8500_audio_setup_if1(struct snd_soc_codec *codec,
unsigned int fmt,
unsigned int wl,
unsigned int delay);
-unsigned int ab8500_audio_anc_status(void);
-int ab8500_audio_anc_configure(unsigned int req_state);
-enum ab8500_audio_dapm_path {
- AB8500_AUDIO_DAPM_PATH_DMIC,
- AB8500_AUDIO_DAPM_PATH_AMIC1,
- AB8500_AUDIO_DAPM_PATH_AMIC2
-};
-bool ab8500_audio_dapm_path_active(enum ab8500_audio_dapm_path dapm_path);
+void ab8500_audio_anc_configure(struct snd_soc_codec *codec,
+ bool apply_fir, bool apply_iir);
enum ab8500_audio_adcm {
AB8500_AUDIO_ADCM_NORMAL,
@@ -630,8 +624,9 @@ int ab8500_audio_set_adcm(enum ab8500_audio_adcm req_adcm);
/* REG_SIDFIRCOEF1 */
/* REG_SIDFIRCOEF2 */
-#define REG_SIDFIRCOEFX_VALUE_SHIFT 0
-#define REG_SIDFIRCOEFX_VALUE_MAX 0xFFFF
+#define REG_SID_FIR_COEFF_MIN 0
+#define REG_SID_FIR_COEFF_MAX 0xFFFF
+#define REG_SID_FIR_COEFFS 128
/* REG_SIDFIRCONF */
#define REG_SIDFIRCONF_ENFIRSIDS 2
diff --git a/sound/soc/ux500/ux500_ab8500.c b/sound/soc/ux500/ux500_ab8500.c
index 4f1a3170d74..645c7676ffd 100644
--- a/sound/soc/ux500/ux500_ab8500.c
+++ b/sound/soc/ux500/ux500_ab8500.c
@@ -78,15 +78,26 @@ static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
/* ANC States */
static const char * const enum_anc_state[] = {
"Unconfigured",
- "Configure FIR+IIR",
- "FIR+IIR Configured",
- "Configure FIR",
- "FIR Configured",
- "Configure IIR",
- "IIR Configured",
+ "Apply FIR and IIR",
+ "FIR and IIR are configured",
+ "Apply FIR",
+ "FIR is configured",
+ "Apply IIR",
+ "IIR is configured",
"Error"
};
static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state);
+enum anc_state {
+ ANC_UNCONFIGURED = 0,
+ ANC_APPLY_FIR_IIR = 1,
+ ANC_FIR_IIR_CONFIGURED = 2,
+ ANC_APPLY_FIR = 3,
+ ANC_FIR_CONFIGURED = 4,
+ ANC_APPLY_IIR = 5,
+ ANC_IIR_CONFIGURED = 6,
+ ANC_ERROR = 7
+};
+static enum anc_state anc_status = ANC_UNCONFIGURED;
/* Regulators */
enum regulator_idx {
@@ -260,6 +271,8 @@ static int ux500_ab8500_power_control_inc(void)
{
int ret = 0;
+ pr_debug("%s: Enter.\n", __func__);
+
mutex_lock(&power_lock);
ab8500_power_count++;
@@ -308,11 +321,15 @@ clk_err:
out:
mutex_unlock(&power_lock);
+ pr_debug("%s: Exit.\n", __func__);
+
return ret;
}
static void ux500_ab8500_power_control_dec(void)
{
+ pr_debug("%s: Enter.\n", __func__);
+
mutex_lock(&power_lock);
ab8500_power_count--;
@@ -337,6 +354,8 @@ static void ux500_ab8500_power_control_dec(void)
}
mutex_unlock(&power_lock);
+
+ pr_debug("%s: Exit.\n", __func__);
}
/* Controls - Non-DAPM Non-ASoC */
@@ -370,7 +389,11 @@ static const struct snd_kcontrol_new mclk_input_control = \
static int anc_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = ab8500_audio_anc_status();
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ mutex_lock(&codec->mutex);
+ ucontrol->value.integer.value[0] = anc_status;
+ mutex_unlock(&codec->mutex);
return 0;
}
@@ -378,13 +401,49 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
static int anc_status_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- int req_state = ucontrol->value.integer.value[0];
+ struct snd_soc_codec *codec;
+ bool apply_fir, apply_iir;
+ int req, ret;
- int ret = ux500_ab8500_power_control_inc();
- if (ret < 0)
+ pr_debug("%s: Enter.\n", __func__);
+
+ req = ucontrol->value.integer.value[0];
+ if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
+ req != ANC_APPLY_IIR) {
+ pr_err("%s: ERROR: Unsupported status to set '%s'!\n",
+ __func__, enum_anc_state[req]);
+ return -EINVAL;
+ }
+ apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
+ apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
+
+ codec = snd_kcontrol_chip(kcontrol);
+
+ ret = ux500_ab8500_power_control_inc();
+ if (ret < 0) {
+ pr_err("%s: ERROR: Failed to enable power (ret = %d)!\n",
+ __func__, ret);
goto cleanup;
+ }
- ret = ab8500_audio_anc_configure(req_state);
+ mutex_lock(&codec->mutex);
+
+ ab8500_audio_anc_configure(codec, apply_fir, apply_iir);
+
+ if (apply_fir) {
+ if (anc_status == ANC_IIR_CONFIGURED)
+ anc_status = ANC_FIR_IIR_CONFIGURED;
+ else if (anc_status != ANC_FIR_IIR_CONFIGURED)
+ anc_status = ANC_FIR_CONFIGURED;
+ }
+ if (apply_iir) {
+ if (anc_status == ANC_FIR_CONFIGURED)
+ anc_status = ANC_FIR_IIR_CONFIGURED;
+ else if (anc_status != ANC_FIR_IIR_CONFIGURED)
+ anc_status = ANC_IIR_CONFIGURED;
+ }
+
+ mutex_unlock(&codec->mutex);
ux500_ab8500_power_control_dec();
@@ -393,7 +452,9 @@ cleanup:
pr_err("%s: Unable to configure ANC! (ret = %d)\n",
__func__, ret);
- return (ret < 0) ? 0 : 1;
+ pr_debug("%s: Exit.\n", __func__);
+
+ return (ret < 0) ? ret : 1;
}
static const struct snd_kcontrol_new anc_status_control = \
@@ -593,7 +654,6 @@ static const struct snd_soc_dapm_route ux500_ab8500_dapm_intercon[] = {
{"DMic 6", NULL, "DMIC Regulator"},
};
-
static int add_widgets(struct snd_soc_codec *codec)
{
int ret;
@@ -933,6 +993,8 @@ int ux500_ab8500_audio_gpadc_measure(struct ab8500_gpadc *gpadc,
AB8500_AUDIO_ADCM_FORCE_UP :
AB8500_AUDIO_ADCM_FORCE_DOWN;
+ pr_debug("%s: Enter.\n", __func__);
+
mutex_lock(&adcm_lock);
ret = ux500_ab8500_power_control_inc();
@@ -958,6 +1020,8 @@ adcm_failure:
power_failure:
mutex_unlock(&adcm_lock);
+ pr_debug("%s: Exit.\n", __func__);
+
return ret;
}