[alsa-devel] [PATCH 5/6] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec
Barry Song
21cnbao at gmail.com
Fri Jul 19 13:07:21 CEST 2013
From: Rongjun Ying <Rongjun.Ying at csr.com>
This connects DMA, CPU DAI and Codec DAI together and works
as a mach driver.
Signed-off-by: Rongjun Ying <Rongjun.Ying at csr.com>
Signed-off-by: Barry Song <Baohua.Song at csr.com>
---
sound/soc/sirf/Kconfig | 7 +-
sound/soc/sirf/Makefile | 2 +
sound/soc/sirf/sirf-inner.c | 267 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 275 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/sirf/sirf-inner.c
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
index 60b8857..ce3c025 100644
--- a/sound/soc/sirf/Kconfig
+++ b/sound/soc/sirf/Kconfig
@@ -2,7 +2,7 @@ config SND_SIRF_SOC
tristate "Platform DMA driver for the SiRF SoC chips"
depends on ARCH_SIRF && SND_SOC
select SND_SOC_DMAENGINE_PCM
-
+
config SND_SOC_SIRF_I2S
tristate
@@ -11,3 +11,8 @@ config SND_SIRF_SOC_INNER
config SND_SOC_SIRF_USP
tristate
+
+config SND_SIRF_INNER
+ tristate "SoC Audio support for SiRF inner codec of SiRF EVB"
+ depends on SND_SIRF_SOC
+ select SND_SIRF_SOC_INNER
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
index 8517c67..80abdf6 100644
--- a/sound/soc/sirf/Makefile
+++ b/sound/soc/sirf/Makefile
@@ -1,9 +1,11 @@
snd-soc-sirf-objs := sirf-pcm.o
+snd-soc-sirf-inner-objs := sirf-inner.o
snd-soc-sirf-soc-inner-objs := sirf-soc-inner.o
snd-soc-sirf-i2s-objs := sirf-i2s.o
snd-soc-sirf-usp-objs := sirf-usp.o
obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
+obj-$(CONFIG_SND_SIRF_INNER) += snd-soc-sirf-inner.o
obj-$(CONFIG_SND_SIRF_SOC_INNER) += snd-soc-sirf-soc-inner.o
obj-$(CONFIG_SND_SOC_SIRF_I2S) += snd-soc-sirf-i2s.o
obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-inner.c b/sound/soc/sirf/sirf-inner.c
new file mode 100644
index 0000000..a8f2765
--- /dev/null
+++ b/sound/soc/sirf/sirf-inner.c
@@ -0,0 +1,267 @@
+/*
+ * SiRF inner audio device driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+struct sirf_inner_card {
+ unsigned int gpio_hp_pa;
+ unsigned int gpio_spk_pa;
+ /*
+ * Android platform uses switch gpio instead of jack.
+ */
+#ifndef CONFIG_ANDROID
+ unsigned int gpio_hp_detect;
+ struct snd_soc_jack hp_jack;
+#endif
+};
+
+#ifndef CONFIG_ANDROID
+static int sirf_inner_jack_status_check(void);
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ {
+ .name = "hpdet-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 200,
+ .jack_status_check = sirf_inner_jack_status_check,
+ },
+};
+
+static int sirf_inner_jack_status_check(void)
+{
+ int spk_out = 0;
+ struct snd_soc_codec *codec = hp_jack_gpios[0].jack->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+ int hp_report = 0;
+
+ if (gpio_is_valid(sinner_card->gpio_hp_detect))
+ spk_out = gpio_get_value(sinner_card->gpio_hp_detect);
+
+ if (gpio_is_valid(sinner_card->gpio_hp_pa))
+ gpio_direction_output(sinner_card->gpio_hp_pa, !spk_out);
+
+ if (gpio_is_valid(sinner_card->gpio_spk_pa))
+ gpio_direction_output(sinner_card->gpio_spk_pa, spk_out);
+
+ if (!spk_out)
+ hp_report |= SND_JACK_HEADPHONE;
+
+ return hp_report;
+}
+
+static int sirf_inner_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+ int ret;
+ hp_jack_gpios[0].gpio = sinner_card->gpio_hp_detect;
+ ret = snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &sinner_card->hp_jack);
+ if (ret)
+ return ret;
+ return snd_soc_jack_add_gpios(&sinner_card->hp_jack,
+ ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+}
+#endif
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link sirf_inner_dai_links[] = {
+ {
+ .name = "SiRF inner",
+ .stream_name = "SiRF inner",
+ .codec_dai_name = "sirf-soc-inner",
+#ifndef CONFIG_ANDROID
+ .init = sirf_inner_init,
+#endif
+ },
+};
+
+static int sirf_inner_headphone_out_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int hp_out = 0;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = codec->card;
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(sinner_card->gpio_hp_pa))
+ hp_out = gpio_get_value(sinner_card->gpio_hp_pa);
+
+ *ucontrol->value.integer.value = hp_out;
+ return 0;
+}
+
+static int sirf_inner_headphone_out_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int is_hp_out = ucontrol->value.integer.value[0];
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = codec->card;
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(sinner_card->gpio_hp_pa))
+ gpio_direction_output(sinner_card->gpio_hp_pa, is_hp_out);
+
+ return 0;
+}
+
+static int sirf_inner_speaker_out_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int spk_out = 0;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = codec->card;
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(sinner_card->gpio_spk_pa))
+ spk_out = gpio_get_value(sinner_card->gpio_spk_pa);
+
+ *ucontrol->value.integer.value = spk_out;
+ return 0;
+}
+
+static int sirf_inner_speaker_out_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int is_spk_out = ucontrol->value.integer.value[0];
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = codec->card;
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(sinner_card->gpio_spk_pa))
+ gpio_direction_output(sinner_card->gpio_spk_pa, is_spk_out);
+ return 0;
+}
+
+static int sirf_inner_speaker_out_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ return 0;
+}
+
+static int sirf_inner_headphone_out_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ return 0;
+}
+
+static struct snd_kcontrol_new snd_sirf_inner_out_route_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Speaker Out",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = sirf_inner_speaker_out_info,
+ .get = sirf_inner_speaker_out_get,
+ .put = sirf_inner_speaker_out_put,
+ }, {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Out",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = sirf_inner_headphone_out_info,
+ .get = sirf_inner_headphone_out_get,
+ .put = sirf_inner_headphone_out_put,
+ },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_sirf_inner_card = {
+ .name = "SiRF inner",
+ .owner = THIS_MODULE,
+ .dai_link = sirf_inner_dai_links,
+ .num_links = ARRAY_SIZE(sirf_inner_dai_links),
+ .controls = snd_sirf_inner_out_route_controls,
+ .num_controls = ARRAY_SIZE(snd_sirf_inner_out_route_controls),
+};
+
+static int sirf_inner_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_sirf_inner_card;
+ struct sirf_inner_card *sinner_card;
+ sinner_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_inner_card),
+ GFP_KERNEL);
+ if (sinner_card == NULL)
+ return -ENOMEM;
+
+ sirf_inner_dai_links[0].platform_of_node =
+ of_find_compatible_node(NULL, NULL, "sirf,pcm-audio");
+ sirf_inner_dai_links[0].cpu_of_node =
+ of_parse_phandle(pdev->dev.of_node, "sirf,inner-platform", 0);
+ sirf_inner_dai_links[0].codec_of_node =
+ of_parse_phandle(pdev->dev.of_node, "sirf,inner-codec", 0);
+ sinner_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node,
+ "spk-pa-gpios", 0);
+ sinner_card->gpio_hp_pa = of_get_named_gpio(pdev->dev.of_node,
+ "hp-pa-gpios", 0);
+#ifndef CONFIG_ANDROID
+ sinner_card->gpio_hp_detect = of_get_named_gpio(pdev->dev.of_node,
+ "hp-switch-gpios", 0);
+#endif
+ if (gpio_is_valid(sinner_card->gpio_spk_pa))
+ gpio_request(sinner_card->gpio_spk_pa, "SPA_PA_SD");
+ if (gpio_is_valid(sinner_card->gpio_hp_pa))
+ gpio_request(sinner_card->gpio_hp_pa, "HP_PA_SD");
+
+ card->dev = &pdev->dev;
+ snd_soc_card_set_drvdata(card, sinner_card);
+ platform_set_drvdata(pdev, card);
+ if (gpio_is_valid(sinner_card->gpio_hp_pa))
+ gpio_direction_output(sinner_card->gpio_hp_pa, 0);
+ if (gpio_is_valid(sinner_card->gpio_spk_pa))
+ gpio_direction_output(sinner_card->gpio_spk_pa, 0);
+
+ return snd_soc_register_card(card);
+}
+
+static int sirf_inner_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+
+ if (gpio_is_valid(sinner_card->gpio_hp_pa))
+ gpio_free(sinner_card->gpio_hp_pa);
+ if (gpio_is_valid(sinner_card->gpio_spk_pa))
+ gpio_free(sinner_card->gpio_spk_pa);
+
+ snd_soc_unregister_card(card);
+ return 0;
+}
+
+static const struct of_device_id sirf_inner_of_match[] = {
+ {.compatible = "sirf,sirf-inner-audio", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sirf_inner_of_match);
+
+static struct platform_driver sirf_inner_driver = {
+ .driver = {
+ .name = "sirf-inner-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = sirf_inner_of_match,
+ },
+ .probe = sirf_inner_probe,
+ .remove = sirf_inner_remove,
+};
+module_platform_driver(sirf_inner_driver);
+
+MODULE_AUTHOR("RongJun Ying <RongJun.Ying at csr.com>");
+MODULE_DESCRIPTION("ALSA SoC SIRF inner AUDIO driver");
+MODULE_LICENSE("GPL v2");
--
1.8.2.3
More information about the Alsa-devel
mailing list