1/* 2 * e750-wm9705.c -- SoC audio for e750 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 <mach/audio.h> 22#include <mach/eseries-gpio.h> 23 24#include <asm/mach-types.h> 25 26#include "../codecs/wm9705.h" 27#include "pxa2xx-pcm.h" 28#include "pxa2xx-ac97.h" 29 30static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, 31 struct snd_kcontrol *kcontrol, int event) 32{ 33 if (event & SND_SOC_DAPM_PRE_PMU) 34 gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0); 35 else if (event & SND_SOC_DAPM_POST_PMD) 36 gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1); 37 38 return 0; 39} 40 41static int e750_hp_amp_event(struct snd_soc_dapm_widget *w, 42 struct snd_kcontrol *kcontrol, int event) 43{ 44 if (event & SND_SOC_DAPM_PRE_PMU) 45 gpio_set_value(GPIO_E750_HP_AMP_OFF, 0); 46 else if (event & SND_SOC_DAPM_POST_PMD) 47 gpio_set_value(GPIO_E750_HP_AMP_OFF, 1); 48 49 return 0; 50} 51 52static const struct snd_soc_dapm_widget e750_dapm_widgets[] = { 53 SND_SOC_DAPM_HP("Headphone Jack", NULL), 54 SND_SOC_DAPM_SPK("Speaker", NULL), 55 SND_SOC_DAPM_MIC("Mic (Internal)", NULL), 56 SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, 57 e750_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 e750_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 Amp", NULL, "HPOUTL"}, 66 {"Headphone Amp", NULL, "HPOUTR"}, 67 {"Headphone Jack", NULL, "Headphone Amp"}, 68 69 {"Speaker Amp", NULL, "MONOOUT"}, 70 {"Speaker", NULL, "Speaker Amp"}, 71 72 {"MIC1", NULL, "Mic (Internal)"}, 73}; 74 75static int e750_ac97_init(struct snd_soc_codec *codec) 76{ 77 snd_soc_dapm_nc_pin(codec, "LOUT"); 78 snd_soc_dapm_nc_pin(codec, "ROUT"); 79 snd_soc_dapm_nc_pin(codec, "PHONE"); 80 snd_soc_dapm_nc_pin(codec, "LINEINL"); 81 snd_soc_dapm_nc_pin(codec, "LINEINR"); 82 snd_soc_dapm_nc_pin(codec, "CDINL"); 83 snd_soc_dapm_nc_pin(codec, "CDINR"); 84 snd_soc_dapm_nc_pin(codec, "PCBEEP"); 85 snd_soc_dapm_nc_pin(codec, "MIC2"); 86 87 snd_soc_dapm_new_controls(codec, e750_dapm_widgets, 88 ARRAY_SIZE(e750_dapm_widgets)); 89 90 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 91 92 snd_soc_dapm_sync(codec); 93 94 return 0; 95} 96 97static struct snd_soc_dai_link e750_dai[] = { 98 { 99 .name = "AC97", 100 .stream_name = "AC97 HiFi", 101 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], 102 .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI], 103 .init = e750_ac97_init, 104 /* use ops to check startup state */ 105 }, 106 { 107 .name = "AC97 Aux", 108 .stream_name = "AC97 Aux", 109 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], 110 .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX], 111 }, 112}; 113 114static struct snd_soc_card e750 = { 115 .name = "Toshiba e750", 116 .platform = &pxa2xx_soc_platform, 117 .dai_link = e750_dai, 118 .num_links = ARRAY_SIZE(e750_dai), 119}; 120 121static struct snd_soc_device e750_snd_devdata = { 122 .card = &e750, 123 .codec_dev = &soc_codec_dev_wm9705, 124}; 125 126static struct platform_device *e750_snd_device; 127 128static int __init e750_init(void) 129{ 130 int ret; 131 132 if (!machine_is_e750()) 133 return -ENODEV; 134 135 ret = gpio_request(GPIO_E750_HP_AMP_OFF, "Headphone amp"); 136 if (ret) 137 return ret; 138 139 ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp"); 140 if (ret) 141 goto free_hp_amp_gpio; 142 143 ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1); 144 if (ret) 145 goto free_spk_amp_gpio; 146 147 ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1); 148 if (ret) 149 goto free_spk_amp_gpio; 150 151 e750_snd_device = platform_device_alloc("soc-audio", -1); 152 if (!e750_snd_device) { 153 ret = -ENOMEM; 154 goto free_spk_amp_gpio; 155 } 156 157 platform_set_drvdata(e750_snd_device, &e750_snd_devdata); 158 e750_snd_devdata.dev = &e750_snd_device->dev; 159 ret = platform_device_add(e750_snd_device); 160 161 if (!ret) 162 return 0; 163 164/* Fail gracefully */ 165 platform_device_put(e750_snd_device); 166free_spk_amp_gpio: 167 gpio_free(GPIO_E750_SPK_AMP_OFF); 168free_hp_amp_gpio: 169 gpio_free(GPIO_E750_HP_AMP_OFF); 170 171 return ret; 172} 173 174static void __exit e750_exit(void) 175{ 176 platform_device_unregister(e750_snd_device); 177 gpio_free(GPIO_E750_SPK_AMP_OFF); 178 gpio_free(GPIO_E750_HP_AMP_OFF); 179} 180 181module_init(e750_init); 182module_exit(e750_exit); 183 184/* Module information */ 185MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); 186MODULE_DESCRIPTION("ALSA SoC driver for e750"); 187MODULE_LICENSE("GPL v2"); 188