1/* 2 * e800-wm9712.c -- SoC audio for e800 3 * 4 * Copyright 2007 (c) Ian Molton <spyro@f2s.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; version 2 ONLY. 9 * 10 */ 11 12#include <linux/module.h> 13#include <linux/moduleparam.h> 14#include <linux/gpio.h> 15 16#include <sound/core.h> 17#include <sound/pcm.h> 18#include <sound/soc.h> 19#include <sound/soc-dapm.h> 20 21#include <asm/mach-types.h> 22#include <mach/audio.h> 23#include <mach/eseries-gpio.h> 24 25#include "../codecs/wm9712.h" 26#include "pxa2xx-pcm.h" 27#include "pxa2xx-ac97.h" 28 29static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, 30 struct snd_kcontrol *kcontrol, int event) 31{ 32 if (event & SND_SOC_DAPM_PRE_PMU) 33 gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); 34 else if (event & SND_SOC_DAPM_POST_PMD) 35 gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); 36 37 return 0; 38} 39 40static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, 41 struct snd_kcontrol *kcontrol, int event) 42{ 43 if (event & SND_SOC_DAPM_PRE_PMU) 44 gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); 45 else if (event & SND_SOC_DAPM_POST_PMD) 46 gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); 47 48 return 0; 49} 50 51static const struct snd_soc_dapm_widget e800_dapm_widgets[] = { 52 SND_SOC_DAPM_HP("Headphone Jack", NULL), 53 SND_SOC_DAPM_MIC("Mic (Internal1)", NULL), 54 SND_SOC_DAPM_MIC("Mic (Internal2)", NULL), 55 SND_SOC_DAPM_SPK("Speaker", NULL), 56 SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, 57 e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU | 58 SND_SOC_DAPM_POST_PMD), 59 SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, 60 e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU | 61 SND_SOC_DAPM_POST_PMD), 62}; 63 64static const struct snd_soc_dapm_route audio_map[] = { 65 {"Headphone Jack", NULL, "HPOUTL"}, 66 {"Headphone Jack", NULL, "HPOUTR"}, 67 {"Headphone Jack", NULL, "Headphone Amp"}, 68 69 {"Speaker Amp", NULL, "MONOOUT"}, 70 {"Speaker", NULL, "Speaker Amp"}, 71 72 {"MIC1", NULL, "Mic (Internal1)"}, 73 {"MIC2", NULL, "Mic (Internal2)"}, 74}; 75 76static int e800_ac97_init(struct snd_soc_codec *codec) 77{ 78 snd_soc_dapm_new_controls(codec, e800_dapm_widgets, 79 ARRAY_SIZE(e800_dapm_widgets)); 80 81 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 82 snd_soc_dapm_sync(codec); 83 84 return 0; 85} 86 87static struct snd_soc_dai_link e800_dai[] = { 88 { 89 .name = "AC97", 90 .stream_name = "AC97 HiFi", 91 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], 92 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], 93 .init = e800_ac97_init, 94 }, 95 { 96 .name = "AC97 Aux", 97 .stream_name = "AC97 Aux", 98 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], 99 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], 100 }, 101}; 102 103static struct snd_soc_card e800 = { 104 .name = "Toshiba e800", 105 .platform = &pxa2xx_soc_platform, 106 .dai_link = e800_dai, 107 .num_links = ARRAY_SIZE(e800_dai), 108}; 109 110static struct snd_soc_device e800_snd_devdata = { 111 .card = &e800, 112 .codec_dev = &soc_codec_dev_wm9712, 113}; 114 115static struct platform_device *e800_snd_device; 116 117static int __init e800_init(void) 118{ 119 int ret; 120 121 if (!machine_is_e800()) 122 return -ENODEV; 123 124 ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp"); 125 if (ret) 126 return ret; 127 128 ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp"); 129 if (ret) 130 goto free_hp_amp_gpio; 131 132 ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1); 133 if (ret) 134 goto free_spk_amp_gpio; 135 136 ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1); 137 if (ret) 138 goto free_spk_amp_gpio; 139 140 e800_snd_device = platform_device_alloc("soc-audio", -1); 141 if (!e800_snd_device) 142 return -ENOMEM; 143 144 platform_set_drvdata(e800_snd_device, &e800_snd_devdata); 145 e800_snd_devdata.dev = &e800_snd_device->dev; 146 ret = platform_device_add(e800_snd_device); 147 148 if (!ret) 149 return 0; 150 151/* Fail gracefully */ 152 platform_device_put(e800_snd_device); 153free_spk_amp_gpio: 154 gpio_free(GPIO_E800_SPK_AMP_ON); 155free_hp_amp_gpio: 156 gpio_free(GPIO_E800_HP_AMP_OFF); 157 158 return ret; 159} 160 161static void __exit e800_exit(void) 162{ 163 platform_device_unregister(e800_snd_device); 164 gpio_free(GPIO_E800_SPK_AMP_ON); 165 gpio_free(GPIO_E800_HP_AMP_OFF); 166} 167 168module_init(e800_init); 169module_exit(e800_exit); 170 171/* Module information */ 172MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); 173MODULE_DESCRIPTION("ALSA SoC driver for e800"); 174MODULE_LICENSE("GPL v2"); 175