summaryrefslogtreecommitdiffstats
path: root/sound/soc/pxa/z2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/pxa/z2.c')
-rw-r--r--sound/soc/pxa/z2.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
new file mode 100644
index 000000000..020dcce1d
--- /dev/null
+++ b/sound/soc/pxa/z2.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/sound/soc/pxa/z2.c
+ *
+ * SoC Audio driver for Aeronix Zipit Z2
+ *
+ * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com>
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+#include <linux/platform_data/asoc-pxa.h>
+
+#include "../codecs/wm8750.h"
+#include "pxa2xx-i2s.h"
+
+static struct snd_soc_card snd_soc_z2;
+
+static int z2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_jack hs_jack;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Ext Spk",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1
+ },
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+ {
+ .name = "hsdet-gpio",
+ .report = SND_JACK_HEADSET,
+ .debounce_time = 200,
+ .invert = 1,
+ },
+};
+
+/* z2 machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+
+ /* headset is a mic and mono headphone */
+ SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Z2 machine audio_map */
+static const struct snd_soc_dapm_route z2_audio_map[] = {
+
+ /* headphone connected to LOUT1, ROUT1 */
+ {"Headphone Jack", NULL, "LOUT1"},
+ {"Headphone Jack", NULL, "ROUT1"},
+
+ /* ext speaker connected to LOUT2, ROUT2 */
+ {"Ext Spk", NULL, "ROUT2"},
+ {"Ext Spk", NULL, "LOUT2"},
+
+ /* mic is connected to R input 2 - with bias */
+ {"RINPUT2", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Mic Jack"},
+};
+
+/*
+ * Logic for a wm8750 as connected on a Z2 Device
+ */
+static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ /* Jack detection API stuff */
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET, &hs_jack,
+ hs_jack_pins,
+ ARRAY_SIZE(hs_jack_pins));
+ if (ret)
+ goto err;
+
+ ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static const struct snd_soc_ops z2_ops = {
+ .hw_params = z2_hw_params,
+};
+
+/* z2 digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(wm8750,
+ DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link z2_dai = {
+ .name = "wm8750",
+ .stream_name = "WM8750",
+ .init = z2_wm8750_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &z2_ops,
+ SND_SOC_DAILINK_REG(wm8750),
+};
+
+/* z2 audio machine driver */
+static struct snd_soc_card snd_soc_z2 = {
+ .name = "Z2",
+ .owner = THIS_MODULE,
+ .dai_link = &z2_dai,
+ .num_links = 1,
+
+ .dapm_widgets = wm8750_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+ .dapm_routes = z2_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(z2_audio_map),
+ .fully_routed = true,
+};
+
+static struct platform_device *z2_snd_device;
+
+static int __init z2_init(void)
+{
+ int ret;
+
+ if (!machine_is_zipit2())
+ return -ENODEV;
+
+ z2_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!z2_snd_device)
+ return -ENOMEM;
+
+ hs_jack_gpios[0].gpiod_dev = &z2_snd_device->dev;
+ platform_set_drvdata(z2_snd_device, &snd_soc_z2);
+ ret = platform_device_add(z2_snd_device);
+
+ if (ret)
+ platform_device_put(z2_snd_device);
+
+ return ret;
+}
+
+static void __exit z2_exit(void)
+{
+ platform_device_unregister(z2_snd_device);
+}
+
+module_init(z2_init);
+module_exit(z2_exit);
+
+MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, "
+ "Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC ZipitZ2");
+MODULE_LICENSE("GPL");