18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/sound/soc/pxa/z2.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * SoC Audio driver for Aeronix Zipit Z2 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 138c2ecf20Sopenharmony_ci#include <linux/timer.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <sound/core.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm.h> 208c2ecf20Sopenharmony_ci#include <sound/soc.h> 218c2ecf20Sopenharmony_ci#include <sound/jack.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 248c2ecf20Sopenharmony_ci#include <mach/hardware.h> 258c2ecf20Sopenharmony_ci#include <mach/audio.h> 268c2ecf20Sopenharmony_ci#include <mach/z2.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "../codecs/wm8750.h" 298c2ecf20Sopenharmony_ci#include "pxa2xx-i2s.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic struct snd_soc_card snd_soc_z2; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int z2_hw_params(struct snd_pcm_substream *substream, 348c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 378c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 388c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 398c2ecf20Sopenharmony_ci unsigned int clk = 0; 408c2ecf20Sopenharmony_ci int ret = 0; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci switch (params_rate(params)) { 438c2ecf20Sopenharmony_ci case 8000: 448c2ecf20Sopenharmony_ci case 16000: 458c2ecf20Sopenharmony_ci case 48000: 468c2ecf20Sopenharmony_ci case 96000: 478c2ecf20Sopenharmony_ci clk = 12288000; 488c2ecf20Sopenharmony_ci break; 498c2ecf20Sopenharmony_ci case 11025: 508c2ecf20Sopenharmony_ci case 22050: 518c2ecf20Sopenharmony_ci case 44100: 528c2ecf20Sopenharmony_ci clk = 11289600; 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* set the codec system clock for DAC and ADC */ 578c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, 588c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 598c2ecf20Sopenharmony_ci if (ret < 0) 608c2ecf20Sopenharmony_ci return ret; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* set the I2S system clock as input (unused) */ 638c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, 648c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 658c2ecf20Sopenharmony_ci if (ret < 0) 668c2ecf20Sopenharmony_ci return ret; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic struct snd_soc_jack hs_jack; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Headset jack detection DAPM pins */ 748c2ecf20Sopenharmony_cistatic struct snd_soc_jack_pin hs_jack_pins[] = { 758c2ecf20Sopenharmony_ci { 768c2ecf20Sopenharmony_ci .pin = "Mic Jack", 778c2ecf20Sopenharmony_ci .mask = SND_JACK_MICROPHONE, 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci { 808c2ecf20Sopenharmony_ci .pin = "Headphone Jack", 818c2ecf20Sopenharmony_ci .mask = SND_JACK_HEADPHONE, 828c2ecf20Sopenharmony_ci }, 838c2ecf20Sopenharmony_ci { 848c2ecf20Sopenharmony_ci .pin = "Ext Spk", 858c2ecf20Sopenharmony_ci .mask = SND_JACK_HEADPHONE, 868c2ecf20Sopenharmony_ci .invert = 1 878c2ecf20Sopenharmony_ci }, 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Headset jack detection gpios */ 918c2ecf20Sopenharmony_cistatic struct snd_soc_jack_gpio hs_jack_gpios[] = { 928c2ecf20Sopenharmony_ci { 938c2ecf20Sopenharmony_ci .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT, 948c2ecf20Sopenharmony_ci .name = "hsdet-gpio", 958c2ecf20Sopenharmony_ci .report = SND_JACK_HEADSET, 968c2ecf20Sopenharmony_ci .debounce_time = 200, 978c2ecf20Sopenharmony_ci .invert = 1, 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* z2 machine dapm widgets */ 1028c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { 1038c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", NULL), 1048c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Mic Jack", NULL), 1058c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Ext Spk", NULL), 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* headset is a mic and mono headphone */ 1088c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headset Jack", NULL), 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* Z2 machine audio_map */ 1128c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route z2_audio_map[] = { 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* headphone connected to LOUT1, ROUT1 */ 1158c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "LOUT1"}, 1168c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "ROUT1"}, 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* ext speaker connected to LOUT2, ROUT2 */ 1198c2ecf20Sopenharmony_ci {"Ext Spk", NULL, "ROUT2"}, 1208c2ecf20Sopenharmony_ci {"Ext Spk", NULL, "LOUT2"}, 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* mic is connected to R input 2 - with bias */ 1238c2ecf20Sopenharmony_ci {"RINPUT2", NULL, "Mic Bias"}, 1248c2ecf20Sopenharmony_ci {"Mic Bias", NULL, "Mic Jack"}, 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * Logic for a wm8750 as connected on a Z2 Device 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci int ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Jack detection API stuff */ 1358c2ecf20Sopenharmony_ci ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, 1368c2ecf20Sopenharmony_ci &hs_jack, hs_jack_pins, 1378c2ecf20Sopenharmony_ci ARRAY_SIZE(hs_jack_pins)); 1388c2ecf20Sopenharmony_ci if (ret) 1398c2ecf20Sopenharmony_ci goto err; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), 1428c2ecf20Sopenharmony_ci hs_jack_gpios); 1438c2ecf20Sopenharmony_ci if (ret) 1448c2ecf20Sopenharmony_ci goto err; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cierr: 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct snd_soc_ops z2_ops = { 1538c2ecf20Sopenharmony_ci .hw_params = z2_hw_params, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* z2 digital audio interface glue - connects codec <--> CPU */ 1578c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(wm8750, 1588c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")), 1598c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")), 1608c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio"))); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link z2_dai = { 1638c2ecf20Sopenharmony_ci .name = "wm8750", 1648c2ecf20Sopenharmony_ci .stream_name = "WM8750", 1658c2ecf20Sopenharmony_ci .init = z2_wm8750_init, 1668c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 1678c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 1688c2ecf20Sopenharmony_ci .ops = &z2_ops, 1698c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(wm8750), 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* z2 audio machine driver */ 1738c2ecf20Sopenharmony_cistatic struct snd_soc_card snd_soc_z2 = { 1748c2ecf20Sopenharmony_ci .name = "Z2", 1758c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1768c2ecf20Sopenharmony_ci .dai_link = &z2_dai, 1778c2ecf20Sopenharmony_ci .num_links = 1, 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci .dapm_widgets = wm8750_dapm_widgets, 1808c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), 1818c2ecf20Sopenharmony_ci .dapm_routes = z2_audio_map, 1828c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(z2_audio_map), 1838c2ecf20Sopenharmony_ci .fully_routed = true, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic struct platform_device *z2_snd_device; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int __init z2_init(void) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!machine_is_zipit2()) 1938c2ecf20Sopenharmony_ci return -ENODEV; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci z2_snd_device = platform_device_alloc("soc-audio", -1); 1968c2ecf20Sopenharmony_ci if (!z2_snd_device) 1978c2ecf20Sopenharmony_ci return -ENOMEM; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci platform_set_drvdata(z2_snd_device, &snd_soc_z2); 2008c2ecf20Sopenharmony_ci ret = platform_device_add(z2_snd_device); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (ret) 2038c2ecf20Sopenharmony_ci platform_device_put(z2_snd_device); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void __exit z2_exit(void) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci platform_device_unregister(z2_snd_device); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cimodule_init(z2_init); 2148c2ecf20Sopenharmony_cimodule_exit(z2_exit); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, " 2178c2ecf20Sopenharmony_ci "Marek Vasut <marek.vasut@gmail.com>"); 2188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC ZipitZ2"); 2198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 220