1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/sound/soc/pxa/z2.c 4 * 5 * SoC Audio driver for Aeronix Zipit Z2 6 * 7 * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com> 8 * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> 9 */ 10 11 #include <linux/module.h> 12 #include <linux/moduleparam.h> 13 #include <linux/timer.h> 14 #include <linux/interrupt.h> 15 #include <linux/platform_device.h> 16 #include <linux/gpio.h> 17 18 #include <sound/core.h> 19 #include <sound/pcm.h> 20 #include <sound/soc.h> 21 #include <sound/jack.h> 22 23 #include <asm/mach-types.h> 24 #include <mach/hardware.h> 25 #include <mach/audio.h> 26 #include <mach/z2.h> 27 28 #include "../codecs/wm8750.h" 29 #include "pxa2xx-i2s.h" 30 31 static struct snd_soc_card snd_soc_z2; 32 33 static int z2_hw_params(struct snd_pcm_substream *substream, 34 struct snd_pcm_hw_params *params) 35 { 36 struct snd_soc_pcm_runtime *rtd = substream->private_data; 37 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 38 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 39 unsigned int clk = 0; 40 int ret = 0; 41 42 switch (params_rate(params)) { 43 case 8000: 44 case 16000: 45 case 48000: 46 case 96000: 47 clk = 12288000; 48 break; 49 case 11025: 50 case 22050: 51 case 44100: 52 clk = 11289600; 53 break; 54 } 55 56 /* set the codec system clock for DAC and ADC */ 57 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, 58 SND_SOC_CLOCK_IN); 59 if (ret < 0) 60 return ret; 61 62 /* set the I2S system clock as input (unused) */ 63 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, 64 SND_SOC_CLOCK_IN); 65 if (ret < 0) 66 return ret; 67 68 return 0; 69 } 70 71 static struct snd_soc_jack hs_jack; 72 73 /* Headset jack detection DAPM pins */ 74 static struct snd_soc_jack_pin hs_jack_pins[] = { 75 { 76 .pin = "Mic Jack", 77 .mask = SND_JACK_MICROPHONE, 78 }, 79 { 80 .pin = "Headphone Jack", 81 .mask = SND_JACK_HEADPHONE, 82 }, 83 { 84 .pin = "Ext Spk", 85 .mask = SND_JACK_HEADPHONE, 86 .invert = 1 87 }, 88 }; 89 90 /* Headset jack detection gpios */ 91 static struct snd_soc_jack_gpio hs_jack_gpios[] = { 92 { 93 .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT, 94 .name = "hsdet-gpio", 95 .report = SND_JACK_HEADSET, 96 .debounce_time = 200, 97 .invert = 1, 98 }, 99 }; 100 101 /* z2 machine dapm widgets */ 102 static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { 103 SND_SOC_DAPM_HP("Headphone Jack", NULL), 104 SND_SOC_DAPM_MIC("Mic Jack", NULL), 105 SND_SOC_DAPM_SPK("Ext Spk", NULL), 106 107 /* headset is a mic and mono headphone */ 108 SND_SOC_DAPM_HP("Headset Jack", NULL), 109 }; 110 111 /* Z2 machine audio_map */ 112 static const struct snd_soc_dapm_route z2_audio_map[] = { 113 114 /* headphone connected to LOUT1, ROUT1 */ 115 {"Headphone Jack", NULL, "LOUT1"}, 116 {"Headphone Jack", NULL, "ROUT1"}, 117 118 /* ext speaker connected to LOUT2, ROUT2 */ 119 {"Ext Spk", NULL, "ROUT2"}, 120 {"Ext Spk", NULL, "LOUT2"}, 121 122 /* mic is connected to R input 2 - with bias */ 123 {"RINPUT2", NULL, "Mic Bias"}, 124 {"Mic Bias", NULL, "Mic Jack"}, 125 }; 126 127 /* 128 * Logic for a wm8750 as connected on a Z2 Device 129 */ 130 static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) 131 { 132 int ret; 133 134 /* Jack detection API stuff */ 135 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, 136 &hs_jack, hs_jack_pins, 137 ARRAY_SIZE(hs_jack_pins)); 138 if (ret) 139 goto err; 140 141 ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), 142 hs_jack_gpios); 143 if (ret) 144 goto err; 145 146 return 0; 147 148 err: 149 return ret; 150 } 151 152 static const struct snd_soc_ops z2_ops = { 153 .hw_params = z2_hw_params, 154 }; 155 156 /* z2 digital audio interface glue - connects codec <--> CPU */ 157 SND_SOC_DAILINK_DEFS(wm8750, 158 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")), 159 DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")), 160 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio"))); 161 162 static struct snd_soc_dai_link z2_dai = { 163 .name = "wm8750", 164 .stream_name = "WM8750", 165 .init = z2_wm8750_init, 166 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 167 SND_SOC_DAIFMT_CBS_CFS, 168 .ops = &z2_ops, 169 SND_SOC_DAILINK_REG(wm8750), 170 }; 171 172 /* z2 audio machine driver */ 173 static struct snd_soc_card snd_soc_z2 = { 174 .name = "Z2", 175 .owner = THIS_MODULE, 176 .dai_link = &z2_dai, 177 .num_links = 1, 178 179 .dapm_widgets = wm8750_dapm_widgets, 180 .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), 181 .dapm_routes = z2_audio_map, 182 .num_dapm_routes = ARRAY_SIZE(z2_audio_map), 183 .fully_routed = true, 184 }; 185 186 static struct platform_device *z2_snd_device; 187 188 static int __init z2_init(void) 189 { 190 int ret; 191 192 if (!machine_is_zipit2()) 193 return -ENODEV; 194 195 z2_snd_device = platform_device_alloc("soc-audio", -1); 196 if (!z2_snd_device) 197 return -ENOMEM; 198 199 platform_set_drvdata(z2_snd_device, &snd_soc_z2); 200 ret = platform_device_add(z2_snd_device); 201 202 if (ret) 203 platform_device_put(z2_snd_device); 204 205 return ret; 206 } 207 208 static void __exit z2_exit(void) 209 { 210 platform_device_unregister(z2_snd_device); 211 } 212 213 module_init(z2_init); 214 module_exit(z2_exit); 215 216 MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, " 217 "Marek Vasut <marek.vasut@gmail.com>"); 218 MODULE_DESCRIPTION("ALSA SoC ZipitZ2"); 219 MODULE_LICENSE("GPL"); 220
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.