| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Handles the Mitac mioa701 SoC system |
| * |
| * Copyright (C) 2008 Robert Jarzmik |
| * |
| * This is a little schema of the sound interconnections : |
| * |
| * Sagem X200 Wolfson WM9713 |
| * +--------+ +-------------------+ Rear Speaker |
| * | | | | /-+ |
| * | +--->----->---+MONOIN SPKL+--->----+-+ | |
| * | GSM | | | | | | |
| * | +--->----->---+PCBEEP SPKR+--->----+-+ | |
| * | CHIP | | | \-+ |
| * | +---<-----<---+MONO | |
| * | | | | Front Speaker |
| * +--------+ | | /-+ |
| * | HPL+--->----+-+ | |
| * | | | | | |
| * | OUT3+--->----+-+ | |
| * | | \-+ |
| * | | |
| * | | Front Micro |
| * | | + |
| * | MIC1+-----<--+o+ |
| * | | + |
| * +-------------------+ --- |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/moduleparam.h> |
| #include <linux/platform_device.h> |
| |
| #include <asm/mach-types.h> |
| #include <mach/audio.h> |
| |
| #include <sound/core.h> |
| #include <sound/pcm.h> |
| #include <sound/soc.h> |
| #include <sound/initval.h> |
| #include <sound/ac97_codec.h> |
| |
| #include "../codecs/wm9713.h" |
| |
| #define AC97_GPIO_PULL 0x58 |
| |
| /* Use GPIO8 for rear speaker amplifier */ |
| static int rear_amp_power(struct snd_soc_component *component, int power) |
| { |
| unsigned short reg; |
| |
| if (power) { |
| reg = snd_soc_component_read32(component, AC97_GPIO_CFG); |
| snd_soc_component_write(component, AC97_GPIO_CFG, reg | 0x0100); |
| reg = snd_soc_component_read32(component, AC97_GPIO_PULL); |
| snd_soc_component_write(component, AC97_GPIO_PULL, reg | (1<<15)); |
| } else { |
| reg = snd_soc_component_read32(component, AC97_GPIO_CFG); |
| snd_soc_component_write(component, AC97_GPIO_CFG, reg & ~0x0100); |
| reg = snd_soc_component_read32(component, AC97_GPIO_PULL); |
| snd_soc_component_write(component, AC97_GPIO_PULL, reg & ~(1<<15)); |
| } |
| |
| return 0; |
| } |
| |
| static int rear_amp_event(struct snd_soc_dapm_widget *widget, |
| struct snd_kcontrol *kctl, int event) |
| { |
| struct snd_soc_card *card = widget->dapm->card; |
| struct snd_soc_pcm_runtime *rtd; |
| struct snd_soc_component *component; |
| |
| rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); |
| component = rtd->codec_dai->component; |
| return rear_amp_power(component, SND_SOC_DAPM_EVENT_ON(event)); |
| } |
| |
| /* mioa701 machine dapm widgets */ |
| static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = { |
| SND_SOC_DAPM_SPK("Front Speaker", NULL), |
| SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event), |
| SND_SOC_DAPM_MIC("Headset", NULL), |
| SND_SOC_DAPM_LINE("GSM Line Out", NULL), |
| SND_SOC_DAPM_LINE("GSM Line In", NULL), |
| SND_SOC_DAPM_MIC("Headset Mic", NULL), |
| SND_SOC_DAPM_MIC("Front Mic", NULL), |
| }; |
| |
| static const struct snd_soc_dapm_route audio_map[] = { |
| /* Call Mic */ |
| {"Mic Bias", NULL, "Front Mic"}, |
| {"MIC1", NULL, "Mic Bias"}, |
| |
| /* Headset Mic */ |
| {"LINEL", NULL, "Headset Mic"}, |
| {"LINER", NULL, "Headset Mic"}, |
| |
| /* GSM Module */ |
| {"MONOIN", NULL, "GSM Line Out"}, |
| {"PCBEEP", NULL, "GSM Line Out"}, |
| {"GSM Line In", NULL, "MONO"}, |
| |
| /* headphone connected to HPL, HPR */ |
| {"Headset", NULL, "HPL"}, |
| {"Headset", NULL, "HPR"}, |
| |
| /* front speaker connected to HPL, OUT3 */ |
| {"Front Speaker", NULL, "HPL"}, |
| {"Front Speaker", NULL, "OUT3"}, |
| |
| /* rear speaker connected to SPKL, SPKR */ |
| {"Rear Speaker", NULL, "SPKL"}, |
| {"Rear Speaker", NULL, "SPKR"}, |
| }; |
| |
| static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
| { |
| struct snd_soc_component *component = rtd->codec_dai->component; |
| |
| /* Prepare GPIO8 for rear speaker amplifier */ |
| snd_soc_component_update_bits(component, AC97_GPIO_CFG, 0x100, 0x100); |
| |
| /* Prepare MIC input */ |
| snd_soc_component_update_bits(component, AC97_3D_CONTROL, 0xc000, 0xc000); |
| |
| return 0; |
| } |
| |
| static struct snd_soc_ops mioa701_ops; |
| |
| SND_SOC_DAILINK_DEFS(ac97, |
| DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")), |
| DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-hifi")), |
| DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio"))); |
| |
| SND_SOC_DAILINK_DEFS(ac97_aux, |
| DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")), |
| DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-aux")), |
| DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio"))); |
| |
| static struct snd_soc_dai_link mioa701_dai[] = { |
| { |
| .name = "AC97", |
| .stream_name = "AC97 HiFi", |
| .init = mioa701_wm9713_init, |
| .ops = &mioa701_ops, |
| SND_SOC_DAILINK_REG(ac97), |
| }, |
| { |
| .name = "AC97 Aux", |
| .stream_name = "AC97 Aux", |
| .ops = &mioa701_ops, |
| SND_SOC_DAILINK_REG(ac97_aux), |
| }, |
| }; |
| |
| static struct snd_soc_card mioa701 = { |
| .name = "MioA701", |
| .owner = THIS_MODULE, |
| .dai_link = mioa701_dai, |
| .num_links = ARRAY_SIZE(mioa701_dai), |
| |
| .dapm_widgets = mioa701_dapm_widgets, |
| .num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets), |
| .dapm_routes = audio_map, |
| .num_dapm_routes = ARRAY_SIZE(audio_map), |
| }; |
| |
| static int mioa701_wm9713_probe(struct platform_device *pdev) |
| { |
| int rc; |
| |
| if (!machine_is_mioa701()) |
| return -ENODEV; |
| |
| mioa701.dev = &pdev->dev; |
| rc = devm_snd_soc_register_card(&pdev->dev, &mioa701); |
| if (!rc) |
| dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will " |
| "lead to overheating and possible destruction of your device." |
| " Do not use without a good knowledge of mio's board design!\n"); |
| return rc; |
| } |
| |
| static struct platform_driver mioa701_wm9713_driver = { |
| .probe = mioa701_wm9713_probe, |
| .driver = { |
| .name = "mioa701-wm9713", |
| .pm = &snd_soc_pm_ops, |
| }, |
| }; |
| |
| module_platform_driver(mioa701_wm9713_driver); |
| |
| /* Module information */ |
| MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); |
| MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); |
| MODULE_LICENSE("GPL"); |
| MODULE_ALIAS("platform:mioa701-wm9713"); |