Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/sound/soc/pxa/z2.c
0004  *
0005  * SoC Audio driver for Aeronix Zipit Z2
0006  *
0007  * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com>
0008  * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/moduleparam.h>
0013 #include <linux/timer.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/gpio/consumer.h>
0017 
0018 #include <sound/core.h>
0019 #include <sound/pcm.h>
0020 #include <sound/soc.h>
0021 #include <sound/jack.h>
0022 
0023 #include <asm/mach-types.h>
0024 #include <linux/platform_data/asoc-pxa.h>
0025 
0026 #include "../codecs/wm8750.h"
0027 #include "pxa2xx-i2s.h"
0028 
0029 static struct snd_soc_card snd_soc_z2;
0030 
0031 static int z2_hw_params(struct snd_pcm_substream *substream,
0032     struct snd_pcm_hw_params *params)
0033 {
0034     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0035     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0036     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0037     unsigned int clk = 0;
0038     int ret = 0;
0039 
0040     switch (params_rate(params)) {
0041     case 8000:
0042     case 16000:
0043     case 48000:
0044     case 96000:
0045         clk = 12288000;
0046         break;
0047     case 11025:
0048     case 22050:
0049     case 44100:
0050         clk = 11289600;
0051         break;
0052     }
0053 
0054     /* set the codec system clock for DAC and ADC */
0055     ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
0056         SND_SOC_CLOCK_IN);
0057     if (ret < 0)
0058         return ret;
0059 
0060     /* set the I2S system clock as input (unused) */
0061     ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
0062         SND_SOC_CLOCK_IN);
0063     if (ret < 0)
0064         return ret;
0065 
0066     return 0;
0067 }
0068 
0069 static struct snd_soc_jack hs_jack;
0070 
0071 /* Headset jack detection DAPM pins */
0072 static struct snd_soc_jack_pin hs_jack_pins[] = {
0073     {
0074         .pin    = "Mic Jack",
0075         .mask   = SND_JACK_MICROPHONE,
0076     },
0077     {
0078         .pin    = "Headphone Jack",
0079         .mask   = SND_JACK_HEADPHONE,
0080     },
0081     {
0082         .pin    = "Ext Spk",
0083         .mask   = SND_JACK_HEADPHONE,
0084         .invert = 1
0085     },
0086 };
0087 
0088 /* Headset jack detection gpios */
0089 static struct snd_soc_jack_gpio hs_jack_gpios[] = {
0090     {
0091         .name       = "hsdet-gpio",
0092         .report     = SND_JACK_HEADSET,
0093         .debounce_time  = 200,
0094         .invert     = 1,
0095     },
0096 };
0097 
0098 /* z2 machine dapm widgets */
0099 static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
0100     SND_SOC_DAPM_HP("Headphone Jack", NULL),
0101     SND_SOC_DAPM_MIC("Mic Jack", NULL),
0102     SND_SOC_DAPM_SPK("Ext Spk", NULL),
0103 
0104     /* headset is a mic and mono headphone */
0105     SND_SOC_DAPM_HP("Headset Jack", NULL),
0106 };
0107 
0108 /* Z2 machine audio_map */
0109 static const struct snd_soc_dapm_route z2_audio_map[] = {
0110 
0111     /* headphone connected to LOUT1, ROUT1 */
0112     {"Headphone Jack", NULL, "LOUT1"},
0113     {"Headphone Jack", NULL, "ROUT1"},
0114 
0115     /* ext speaker connected to LOUT2, ROUT2  */
0116     {"Ext Spk", NULL, "ROUT2"},
0117     {"Ext Spk", NULL, "LOUT2"},
0118 
0119     /* mic is connected to R input 2 - with bias */
0120     {"RINPUT2", NULL, "Mic Bias"},
0121     {"Mic Bias", NULL, "Mic Jack"},
0122 };
0123 
0124 /*
0125  * Logic for a wm8750 as connected on a Z2 Device
0126  */
0127 static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
0128 {
0129     int ret;
0130 
0131     /* Jack detection API stuff */
0132     ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
0133                      SND_JACK_HEADSET, &hs_jack,
0134                      hs_jack_pins,
0135                      ARRAY_SIZE(hs_jack_pins));
0136     if (ret)
0137         goto err;
0138 
0139     ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
0140                 hs_jack_gpios);
0141     if (ret)
0142         goto err;
0143 
0144     return 0;
0145 
0146 err:
0147     return ret;
0148 }
0149 
0150 static const struct snd_soc_ops z2_ops = {
0151     .hw_params = z2_hw_params,
0152 };
0153 
0154 /* z2 digital audio interface glue - connects codec <--> CPU */
0155 SND_SOC_DAILINK_DEFS(wm8750,
0156     DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
0157     DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
0158     DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
0159 
0160 static struct snd_soc_dai_link z2_dai = {
0161     .name       = "wm8750",
0162     .stream_name    = "WM8750",
0163     .init       = z2_wm8750_init,
0164     .dai_fmt    = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0165               SND_SOC_DAIFMT_CBS_CFS,
0166     .ops        = &z2_ops,
0167     SND_SOC_DAILINK_REG(wm8750),
0168 };
0169 
0170 /* z2 audio machine driver */
0171 static struct snd_soc_card snd_soc_z2 = {
0172     .name       = "Z2",
0173     .owner      = THIS_MODULE,
0174     .dai_link   = &z2_dai,
0175     .num_links  = 1,
0176 
0177     .dapm_widgets = wm8750_dapm_widgets,
0178     .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
0179     .dapm_routes = z2_audio_map,
0180     .num_dapm_routes = ARRAY_SIZE(z2_audio_map),
0181     .fully_routed = true,
0182 };
0183 
0184 static struct platform_device *z2_snd_device;
0185 
0186 static int __init z2_init(void)
0187 {
0188     int ret;
0189 
0190     if (!machine_is_zipit2())
0191         return -ENODEV;
0192 
0193     z2_snd_device = platform_device_alloc("soc-audio", -1);
0194     if (!z2_snd_device)
0195         return -ENOMEM;
0196 
0197     hs_jack_gpios[0].gpiod_dev = &z2_snd_device->dev;
0198     platform_set_drvdata(z2_snd_device, &snd_soc_z2);
0199     ret = platform_device_add(z2_snd_device);
0200 
0201     if (ret)
0202         platform_device_put(z2_snd_device);
0203 
0204     return ret;
0205 }
0206 
0207 static void __exit z2_exit(void)
0208 {
0209     platform_device_unregister(z2_snd_device);
0210 }
0211 
0212 module_init(z2_init);
0213 module_exit(z2_exit);
0214 
0215 MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, "
0216         "Marek Vasut <marek.vasut@gmail.com>");
0217 MODULE_DESCRIPTION("ALSA SoC ZipitZ2");
0218 MODULE_LICENSE("GPL");