summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOla Lilja <ola.o.lilja@stericsson.com>2011-06-29 10:52:10 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:56 +0200
commitebc86bf44154f0afc80a33f7b9c7d49c47df72d2 (patch)
tree24317adb810b28c1765998f75baa1932c6951e1d
parent6884f421e3913afc6dae16889cb2c90ea37a08d0 (diff)
Ux500 ASoC: Proper handling of vibra output driver
The Class-D amplifier used for vibra is now turned of to same power when not needed. A new control to handle this is introduced. ST-Ericsson Linux next: NA ST-Ericsson ID: 345554 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I28d4daf28b3ff33b9cc2665e8a156c6f56175b66 Signed-off-by: Ola Lilja <ola.o.lilja@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/26046 Reviewed-by: QATEST Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30799 Reviewed-by: Roger NILSSON1 <roger.xr.nilsson@stericsson.com> Tested-by: Roger NILSSON1 <roger.xr.nilsson@stericsson.com>
-rw-r--r--sound/soc/codecs/ab8500_audio.c94
1 files changed, 84 insertions, 10 deletions
diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c
index d2de1822b82..d9668723e53 100644
--- a/sound/soc/codecs/ab8500_audio.c
+++ b/sound/soc/codecs/ab8500_audio.c
@@ -280,6 +280,9 @@ static inline int ab8500_codec_update_reg_audio(struct snd_soc_codec *codec,
return ab8500_codec_write_reg_audio(codec, reg, new);
}
+static const char *enum_ena_dis[] = {"Enabled", "Disabled"};
+static const char *enum_dis_ena[] = {"Disabled", "Enabled"};
+
/* Whether widget's register definitions should be inverted or not */
enum control_inversion {
NORMAL = 0,
@@ -316,6 +319,16 @@ static const struct snd_kcontrol_new dapm_ihfr_mute[] = {
REG_DIGMULTCONF2_DATOHFREN, 1, NORMAL),
};
+/* Vibra 1 switch control */
+static const struct soc_enum enum_vibra1 = SOC_ENUM_SINGLE(0, 0, 2, enum_dis_ena);
+static const struct snd_kcontrol_new dapm_vibra1_mux =
+ SOC_DAPM_ENUM_VIRT("Vibra 1", enum_vibra1);
+
+/* Vibra 2 switch control */
+static const struct soc_enum enum_vibra2 = SOC_ENUM_SINGLE(0, 0, 2, enum_dis_ena);
+static const struct snd_kcontrol_new dapm_vibra2_mux =
+ SOC_DAPM_ENUM_VIRT("Vibra 2", enum_vibra2);
+
/* Mic 1 mute control */
static const struct snd_kcontrol_new dapm_mic1_mute[] = {
SOC_DAPM_SINGLE("Capture Switch", REG_ANACONF2,
@@ -490,10 +503,8 @@ static const struct snd_kcontrol_new dapm_anc_in_select[] = {
};
/* ANC enable control */
-static const char *enum_anc_dis_ena[] = {"Disabled", "Enabled"};
-
static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_enable, REG_ANCCONF1,
- REG_ANCCONF1_ENANC, enum_anc_dis_ena);
+ REG_ANCCONF1_ENANC, enum_dis_ena);
static const struct snd_kcontrol_new dapm_anc_enable[] = {
SOC_DAPM_ENUM("ANC", dapm_enum_anc_enable),
@@ -633,7 +644,8 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DA_IN5", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DA_IN6", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0),
-
+ SND_SOC_DAPM_MUX("Vibra 1", SND_SOC_NOPM, 0, 0, &dapm_vibra1_mux),
+ SND_SOC_DAPM_MUX("Vibra 2", SND_SOC_NOPM, 0, 0, &dapm_vibra2_mux),
SND_SOC_DAPM_MIXER("DA5 Channel Gain", REG_DAPATHENA,
REG_DAPATHENA_ENDA5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("DA6 Channel Gain", REG_DAPATHENA,
@@ -874,8 +886,11 @@ static const struct snd_soc_dapm_route intercon[] = {
/* Vibrator path */
- {"DA5 Channel Gain", NULL, "DA_IN5"},
- {"DA6 Channel Gain", NULL, "DA_IN6"},
+ {"Vibra 1", "Enabled", "DA_IN5"},
+ {"Vibra 2", "Enabled", "DA_IN6"},
+
+ {"DA5 Channel Gain", NULL, "Vibra 1"},
+ {"DA6 Channel Gain", NULL, "Vibra 2"},
{"VIB1 DAC", NULL, "DA5 Channel Gain"},
{"VIB2 DAC", NULL, "DA6 Channel Gain"},
@@ -1059,9 +1074,6 @@ static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0);
/* from -36 to 0 dB in 2 dB steps (mute instead of -38 dB) */
static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1);
-static const char *enum_ena_dis[] = {"Enabled", "Disabled"};
-static const char *enum_dis_ena[] = {"Disabled", "Enabled"};
-
static SOC_ENUM_SINGLE_DECL(soc_enum_hshpen,
REG_ANACONF1, REG_ANACONF1_HSHPEN, enum_dis_ena);
static SOC_ENUM_SINGLE_DECL(soc_enum_hslowpow,
@@ -1855,7 +1867,69 @@ void ab8500_audio_power_control(bool power_on)
}
}
-/* Extended interface for codec-driver */
+void ab8500_audio_pwm_vibra(unsigned char speed_left_pos,
+ unsigned char speed_left_neg,
+ unsigned char speed_right_pos,
+ unsigned char speed_right_neg)
+{
+ unsigned int clear_mask, set_mask;
+ bool vibra_on;
+
+ if (ab8500_codec == NULL) {
+ pr_err("%s: ERROR: AB8500 ASoC-driver not yet probed!\n", __func__);
+ return;
+ }
+
+ vibra_on = speed_left_pos | speed_left_neg | speed_right_pos | speed_right_neg;
+ if (!vibra_on) {
+ speed_left_pos = 0;
+ speed_left_neg = 0;
+ speed_right_pos = 0;
+ speed_right_neg = 0;
+ }
+
+ pr_debug("%s: PWM-vibra (%d, %d, %d, %d).\n",
+ __func__,
+ speed_left_pos,
+ speed_left_neg,
+ speed_right_pos,
+ speed_right_neg);
+
+ set_mask = BMASK(REG_PWMGENCONF1_PWMTOVIB1) |
+ BMASK(REG_PWMGENCONF1_PWMTOVIB2) |
+ BMASK(REG_PWMGENCONF1_PWM1CTRL) |
+ BMASK(REG_PWMGENCONF1_PWM2CTRL) |
+ BMASK(REG_PWMGENCONF1_PWM1NCTRL) |
+ BMASK(REG_PWMGENCONF1_PWM1PCTRL) |
+ BMASK(REG_PWMGENCONF1_PWM2NCTRL) |
+ BMASK(REG_PWMGENCONF1_PWM2PCTRL);
+ ab8500_codec_update_reg_audio(ab8500_codec, REG_PWMGENCONF1, 0x00, set_mask);
+
+ if (speed_left_pos > REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX)
+ speed_left_pos = REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX;
+ ab8500_codec_update_reg_audio(ab8500_codec, REG_PWMGENCONF3, REG_MASK_ALL, speed_left_pos);
+
+ if (speed_left_neg > REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX)
+ speed_left_neg = REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX;
+ ab8500_codec_update_reg_audio(ab8500_codec, REG_PWMGENCONF2, REG_MASK_ALL, speed_left_neg);
+
+ if (speed_right_pos > REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX)
+ speed_right_pos = REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX;
+ ab8500_codec_update_reg_audio(ab8500_codec, REG_PWMGENCONF5, REG_MASK_ALL, speed_right_pos);
+
+ if (speed_right_neg > REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX)
+ speed_right_neg = REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX;
+ ab8500_codec_update_reg_audio(ab8500_codec, REG_PWMGENCONF4, REG_MASK_ALL, speed_right_neg);
+
+ if (vibra_on) {
+ clear_mask = 0;
+ set_mask = BMASK(REG_ANACONF4_ENVIB1) | BMASK(REG_ANACONF4_ENVIB2);
+ } else {
+ clear_mask = BMASK(REG_ANACONF4_ENVIB1) | BMASK(REG_ANACONF4_ENVIB2);
+ set_mask = 0;
+ };
+ ab8500_codec_update_reg_audio(ab8500_codec, REG_ANACONF4, clear_mask, set_mask);
+}
int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl)
{