summaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra_wm8903.c
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2011-10-03 04:53:58 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:19 -0800
commitb83d7f9131e68c6fa057ce6fc7b36ec2523c3483 (patch)
tree8b60de92202353c4cd12a1544cb28ef20c71dae4 /sound/soc/tegra/tegra_wm8903.c
parent867a3c7a962c98e92da7a2459271e961c153a502 (diff)
ASoC: Tegra: WM8903: Support speaker and dmic
Complete DAPM route map for cardhu and ventana. Expose more alsa controls to facilitate codec routing. Properly handle speaker, internal mic and external mic routing events. Bug 872652 Change-Id: I4620d08ade1f455a4075d9822fcfd5e34474133f Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-on: http://git-master/r/55669 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R42bcced2737f035bb1888fac064ee20fa6371143
Diffstat (limited to 'sound/soc/tegra/tegra_wm8903.c')
-rw-r--r--sound/soc/tegra/tegra_wm8903.c138
1 files changed, 127 insertions, 11 deletions
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 4bea080e6f2a..bebccffe38d4 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -34,6 +34,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <mach/tegra_wm8903_pdata.h>
@@ -59,6 +60,8 @@
struct tegra_wm8903 {
struct tegra_asoc_utils_data util_data;
struct tegra_wm8903_platform_data *pdata;
+ struct regulator *spk_reg;
+ struct regulator *dmic_reg;
int gpio_requested;
};
@@ -162,6 +165,13 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ if (machine->spk_reg) {
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ regulator_enable(machine->spk_reg);
+ else
+ regulator_disable(machine->spk_reg);
+ }
+
if (!(machine->gpio_requested & GPIO_SPKR_EN))
return 0;
@@ -188,7 +198,57 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
return 0;
}
-static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = {
+static int tegra_wm8903_event_int_mic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+ if (machine->dmic_reg) {
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ regulator_enable(machine->dmic_reg);
+ else
+ regulator_disable(machine->dmic_reg);
+ }
+
+ if (!(machine->gpio_requested & GPIO_INT_MIC_EN))
+ return 0;
+
+ gpio_set_value_cansleep(pdata->gpio_int_mic_en,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static int tegra_wm8903_event_ext_mic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_wm8903_platform_data *pdata = machine->pdata;
+
+ if (!(machine->gpio_requested & GPIO_EXT_MIC_EN))
+ return 0;
+
+ gpio_set_value_cansleep(pdata->gpio_ext_mic_en,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget cardhu_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk),
+ SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", tegra_wm8903_event_ext_mic),
+ SND_SOC_DAPM_MIC("Int Mic", tegra_wm8903_event_int_mic),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_widget tegra_wm8903_default_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk),
SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp),
SND_SOC_DAPM_MIC("Mic Jack", NULL),
@@ -205,6 +265,24 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = {
{"IN1L", NULL, "Mic Bias"},
};
+static const struct snd_soc_dapm_route cardhu_audio_map[] = {
+ {"Headphone Jack", NULL, "HPOUTR"},
+ {"Headphone Jack", NULL, "HPOUTL"},
+ {"Int Spk", NULL, "ROP"},
+ {"Int Spk", NULL, "RON"},
+ {"Int Spk", NULL, "LOP"},
+ {"Int Spk", NULL, "LON"},
+ {"Line Out", NULL, "LINEOUTL"},
+ {"Line Out", NULL, "LINEOUTR"},
+ {"Mic Bias", NULL, "Mic Jack"},
+ {"IN1L", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Int Mic"},
+ {"IN1L", NULL, "Mic Bias"},
+ {"IN1R", NULL, "Mic Bias"},
+ {"IN3L", NULL, "Line In"},
+ {"IN3R", NULL, "Line In"},
+};
+
static const struct snd_soc_dapm_route seaboard_audio_map[] = {
{"Headphone Jack", NULL, "HPOUTR"},
{"Headphone Jack", NULL, "HPOUTL"},
@@ -236,7 +314,16 @@ static const struct snd_soc_dapm_route aebl_audio_map[] = {
{"IN1R", NULL, "Mic Bias"},
};
-static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
+static const struct snd_kcontrol_new cardhu_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Int Spk"),
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("LineOut"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("LineIn"),
+};
+
+static const struct snd_kcontrol_new tegra_wm8903_default_controls[] = {
SOC_DAPM_PIN_SWITCH("Int Spk"),
};
@@ -320,9 +407,10 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
/* FIXME: Calculate automatically based on DAPM routes? */
if (!machine_is_harmony() && !machine_is_ventana() &&
- !machine_is_ventana())
+ !machine_is_cardhu())
snd_soc_dapm_nc_pin(dapm, "IN1L");
- if (!machine_is_seaboard() && !machine_is_aebl())
+ if (!machine_is_seaboard() && !machine_is_aebl() &&
+ !machine_is_cardhu())
snd_soc_dapm_nc_pin(dapm, "IN1R");
snd_soc_dapm_nc_pin(dapm, "IN2L");
if (!machine_is_kaen())
@@ -371,11 +459,6 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
.name = "tegra-wm8903",
.dai_link = tegra_wm8903_dai,
.num_links = ARRAY_SIZE(tegra_wm8903_dai),
-
- .controls = tegra_wm8903_controls,
- .num_controls = ARRAY_SIZE(tegra_wm8903_controls),
- .dapm_widgets = tegra_wm8903_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets),
};
static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
@@ -403,6 +486,18 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
if (ret)
goto err_free_machine;
+ machine->spk_reg = regulator_get(&pdev->dev, "vdd_spk_amp");
+ if (IS_ERR(machine->spk_reg)) {
+ dev_info(&pdev->dev, "No speaker regulator found\n");
+ machine->spk_reg = 0;
+ }
+
+ machine->dmic_reg = regulator_get(&pdev->dev, "vdd_dmic");
+ if (IS_ERR(machine->dmic_reg)) {
+ dev_info(&pdev->dev, "No digital mic regulator found\n");
+ machine->dmic_reg = 0;
+ }
+
if (machine_is_cardhu()) {
tegra_wm8903_dai[0].codec_name = "wm8903.4-001a",
tegra_wm8903_dai[0].cpu_dai_name = "tegra30-i2s.1";
@@ -414,10 +509,26 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
- if (machine_is_harmony() || machine_is_ventana() ||
- machine_is_cardhu()) {
+ if (machine_is_cardhu() || machine_is_ventana()) {
+ card->controls = cardhu_controls;
+ card->num_controls = ARRAY_SIZE(cardhu_controls);
+
+ card->dapm_widgets = cardhu_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(cardhu_dapm_widgets);
+ } else {
+ card->controls = tegra_wm8903_default_controls;
+ card->num_controls = ARRAY_SIZE(tegra_wm8903_default_controls);
+
+ card->dapm_widgets = tegra_wm8903_default_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_default_dapm_widgets);
+ }
+
+ if (machine_is_harmony()) {
card->dapm_routes = harmony_audio_map;
card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
+ } else if (machine_is_ventana() || machine_is_cardhu()) {
+ card->dapm_routes = cardhu_audio_map;
+ card->num_dapm_routes = ARRAY_SIZE(cardhu_audio_map);
} else if (machine_is_seaboard()) {
card->dapm_routes = seaboard_audio_map;
card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
@@ -465,6 +576,11 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
gpio_free(pdata->gpio_spkr_en);
machine->gpio_requested = 0;
+ if (machine->spk_reg)
+ regulator_put(machine->spk_reg);
+ if (machine->dmic_reg)
+ regulator_put(machine->dmic_reg);
+
snd_soc_unregister_card(card);
tegra_asoc_utils_fini(&machine->util_data);