1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * e740-wm9705.c -- SoC audio for e740 4 * 5 * Copyright 2007 (c) Ian Molton <spyro@f2s.com> 6 */ 7 8#include <linux/module.h> 9#include <linux/moduleparam.h> 10#include <linux/gpio.h> 11 12#include <sound/core.h> 13#include <sound/pcm.h> 14#include <sound/soc.h> 15 16#include <mach/audio.h> 17#include <mach/eseries-gpio.h> 18 19#include <asm/mach-types.h> 20 21#define E740_AUDIO_OUT 1 22#define E740_AUDIO_IN 2 23 24static int e740_audio_power; 25 26static void e740_sync_audio_power(int status) 27{ 28 gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status); 29 gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0); 30 gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0); 31} 32 33static int e740_mic_amp_event(struct snd_soc_dapm_widget *w, 34 struct snd_kcontrol *kcontrol, int event) 35{ 36 if (event & SND_SOC_DAPM_PRE_PMU) 37 e740_audio_power |= E740_AUDIO_IN; 38 else if (event & SND_SOC_DAPM_POST_PMD) 39 e740_audio_power &= ~E740_AUDIO_IN; 40 41 e740_sync_audio_power(e740_audio_power); 42 43 return 0; 44} 45 46static int e740_output_amp_event(struct snd_soc_dapm_widget *w, 47 struct snd_kcontrol *kcontrol, int event) 48{ 49 if (event & SND_SOC_DAPM_PRE_PMU) 50 e740_audio_power |= E740_AUDIO_OUT; 51 else if (event & SND_SOC_DAPM_POST_PMD) 52 e740_audio_power &= ~E740_AUDIO_OUT; 53 54 e740_sync_audio_power(e740_audio_power); 55 56 return 0; 57} 58 59static const struct snd_soc_dapm_widget e740_dapm_widgets[] = { 60 SND_SOC_DAPM_HP("Headphone Jack", NULL), 61 SND_SOC_DAPM_SPK("Speaker", NULL), 62 SND_SOC_DAPM_MIC("Mic (Internal)", NULL), 63 SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0, 64 e740_output_amp_event, SND_SOC_DAPM_PRE_PMU | 65 SND_SOC_DAPM_POST_PMD), 66 SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0, 67 e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU | 68 SND_SOC_DAPM_POST_PMD), 69}; 70 71static const struct snd_soc_dapm_route audio_map[] = { 72 {"Output Amp", NULL, "LOUT"}, 73 {"Output Amp", NULL, "ROUT"}, 74 {"Output Amp", NULL, "MONOOUT"}, 75 76 {"Speaker", NULL, "Output Amp"}, 77 {"Headphone Jack", NULL, "Output Amp"}, 78 79 {"MIC1", NULL, "Mic Amp"}, 80 {"Mic Amp", NULL, "Mic (Internal)"}, 81}; 82 83SND_SOC_DAILINK_DEFS(ac97, 84 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")), 85 DAILINK_COMP_ARRAY(COMP_CODEC("wm9705-codec", "wm9705-hifi")), 86 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio"))); 87 88SND_SOC_DAILINK_DEFS(ac97_aux, 89 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")), 90 DAILINK_COMP_ARRAY(COMP_CODEC("wm9705-codec", "wm9705-aux")), 91 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio"))); 92 93static struct snd_soc_dai_link e740_dai[] = { 94 { 95 .name = "AC97", 96 .stream_name = "AC97 HiFi", 97 SND_SOC_DAILINK_REG(ac97), 98 }, 99 { 100 .name = "AC97 Aux", 101 .stream_name = "AC97 Aux", 102 SND_SOC_DAILINK_REG(ac97_aux), 103 }, 104}; 105 106static struct snd_soc_card e740 = { 107 .name = "Toshiba e740", 108 .owner = THIS_MODULE, 109 .dai_link = e740_dai, 110 .num_links = ARRAY_SIZE(e740_dai), 111 112 .dapm_widgets = e740_dapm_widgets, 113 .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets), 114 .dapm_routes = audio_map, 115 .num_dapm_routes = ARRAY_SIZE(audio_map), 116 .fully_routed = true, 117}; 118 119static struct gpio e740_audio_gpios[] = { 120 { GPIO_E740_MIC_ON, GPIOF_OUT_INIT_LOW, "Mic amp" }, 121 { GPIO_E740_AMP_ON, GPIOF_OUT_INIT_LOW, "Output amp" }, 122 { GPIO_E740_WM9705_nAVDD2, GPIOF_OUT_INIT_HIGH, "Audio power" }, 123}; 124 125static int e740_probe(struct platform_device *pdev) 126{ 127 struct snd_soc_card *card = &e740; 128 int ret; 129 130 ret = gpio_request_array(e740_audio_gpios, 131 ARRAY_SIZE(e740_audio_gpios)); 132 if (ret) 133 return ret; 134 135 card->dev = &pdev->dev; 136 137 ret = devm_snd_soc_register_card(&pdev->dev, card); 138 if (ret) { 139 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", 140 ret); 141 gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios)); 142 } 143 return ret; 144} 145 146static int e740_remove(struct platform_device *pdev) 147{ 148 gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios)); 149 return 0; 150} 151 152static struct platform_driver e740_driver = { 153 .driver = { 154 .name = "e740-audio", 155 .pm = &snd_soc_pm_ops, 156 }, 157 .probe = e740_probe, 158 .remove = e740_remove, 159}; 160 161module_platform_driver(e740_driver); 162 163/* Module information */ 164MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); 165MODULE_DESCRIPTION("ALSA SoC driver for e740"); 166MODULE_LICENSE("GPL v2"); 167MODULE_ALIAS("platform:e740-audio"); 168