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