linux/sound/soc/pxa/e740_wm9705.c
<<
>>
Prefs
   1/*
   2 * e740-wm9705.c  --  SoC audio for e740
   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
  30
  31#define E740_AUDIO_OUT 1
  32#define E740_AUDIO_IN  2
  33
  34static int e740_audio_power;
  35
  36static void e740_sync_audio_power(int status)
  37{
  38        gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status);
  39        gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0);
  40        gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0);
  41}
  42
  43static int e740_mic_amp_event(struct snd_soc_dapm_widget *w,
  44                                struct snd_kcontrol *kcontrol, int event)
  45{
  46        if (event & SND_SOC_DAPM_PRE_PMU)
  47                e740_audio_power |= E740_AUDIO_IN;
  48        else if (event & SND_SOC_DAPM_POST_PMD)
  49                e740_audio_power &= ~E740_AUDIO_IN;
  50
  51        e740_sync_audio_power(e740_audio_power);
  52
  53        return 0;
  54}
  55
  56static int e740_output_amp_event(struct snd_soc_dapm_widget *w,
  57                                struct snd_kcontrol *kcontrol, int event)
  58{
  59        if (event & SND_SOC_DAPM_PRE_PMU)
  60                e740_audio_power |= E740_AUDIO_OUT;
  61        else if (event & SND_SOC_DAPM_POST_PMD)
  62                e740_audio_power &= ~E740_AUDIO_OUT;
  63
  64        e740_sync_audio_power(e740_audio_power);
  65
  66        return 0;
  67}
  68
  69static const struct snd_soc_dapm_widget e740_dapm_widgets[] = {
  70        SND_SOC_DAPM_HP("Headphone Jack", NULL),
  71        SND_SOC_DAPM_SPK("Speaker", NULL),
  72        SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
  73        SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
  74                        e740_output_amp_event, SND_SOC_DAPM_PRE_PMU |
  75                        SND_SOC_DAPM_POST_PMD),
  76        SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
  77                        e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU |
  78                        SND_SOC_DAPM_POST_PMD),
  79};
  80
  81static const struct snd_soc_dapm_route audio_map[] = {
  82        {"Output Amp", NULL, "LOUT"},
  83        {"Output Amp", NULL, "ROUT"},
  84        {"Output Amp", NULL, "MONOOUT"},
  85
  86        {"Speaker", NULL, "Output Amp"},
  87        {"Headphone Jack", NULL, "Output Amp"},
  88
  89        {"MIC1", NULL, "Mic Amp"},
  90        {"Mic Amp", NULL, "Mic (Internal)"},
  91};
  92
  93static int e740_ac97_init(struct snd_soc_codec *codec)
  94{
  95        snd_soc_dapm_nc_pin(codec, "HPOUTL");
  96        snd_soc_dapm_nc_pin(codec, "HPOUTR");
  97        snd_soc_dapm_nc_pin(codec, "PHONE");
  98        snd_soc_dapm_nc_pin(codec, "LINEINL");
  99        snd_soc_dapm_nc_pin(codec, "LINEINR");
 100        snd_soc_dapm_nc_pin(codec, "CDINL");
 101        snd_soc_dapm_nc_pin(codec, "CDINR");
 102        snd_soc_dapm_nc_pin(codec, "PCBEEP");
 103        snd_soc_dapm_nc_pin(codec, "MIC2");
 104
 105        snd_soc_dapm_new_controls(codec, e740_dapm_widgets,
 106                                        ARRAY_SIZE(e740_dapm_widgets));
 107
 108        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 109
 110        snd_soc_dapm_sync(codec);
 111
 112        return 0;
 113}
 114
 115static struct snd_soc_dai_link e740_dai[] = {
 116        {
 117                .name = "AC97",
 118                .stream_name = "AC97 HiFi",
 119                .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
 120                .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
 121                .init = e740_ac97_init,
 122        },
 123        {
 124                .name = "AC97 Aux",
 125                .stream_name = "AC97 Aux",
 126                .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
 127                .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
 128        },
 129};
 130
 131static struct snd_soc_card e740 = {
 132        .name = "Toshiba e740",
 133        .platform = &pxa2xx_soc_platform,
 134        .dai_link = e740_dai,
 135        .num_links = ARRAY_SIZE(e740_dai),
 136};
 137
 138static struct snd_soc_device e740_snd_devdata = {
 139        .card = &e740,
 140        .codec_dev = &soc_codec_dev_wm9705,
 141};
 142
 143static struct platform_device *e740_snd_device;
 144
 145static int __init e740_init(void)
 146{
 147        int ret;
 148
 149        if (!machine_is_e740())
 150                return -ENODEV;
 151
 152        ret = gpio_request(GPIO_E740_MIC_ON,  "Mic amp");
 153        if (ret)
 154                return ret;
 155
 156        ret = gpio_request(GPIO_E740_AMP_ON, "Output amp");
 157        if (ret)
 158                goto free_mic_amp_gpio;
 159
 160        ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power");
 161        if (ret)
 162                goto free_op_amp_gpio;
 163
 164        /* Disable audio */
 165        ret = gpio_direction_output(GPIO_E740_MIC_ON, 0);
 166        if (ret)
 167                goto free_apwr_gpio;
 168        ret = gpio_direction_output(GPIO_E740_AMP_ON, 0);
 169        if (ret)
 170                goto free_apwr_gpio;
 171        ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1);
 172        if (ret)
 173                goto free_apwr_gpio;
 174
 175        e740_snd_device = platform_device_alloc("soc-audio", -1);
 176        if (!e740_snd_device) {
 177                ret = -ENOMEM;
 178                goto free_apwr_gpio;
 179        }
 180
 181        platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
 182        e740_snd_devdata.dev = &e740_snd_device->dev;
 183        ret = platform_device_add(e740_snd_device);
 184
 185        if (!ret)
 186                return 0;
 187
 188/* Fail gracefully */
 189        platform_device_put(e740_snd_device);
 190free_apwr_gpio:
 191        gpio_free(GPIO_E740_WM9705_nAVDD2);
 192free_op_amp_gpio:
 193        gpio_free(GPIO_E740_AMP_ON);
 194free_mic_amp_gpio:
 195        gpio_free(GPIO_E740_MIC_ON);
 196
 197        return ret;
 198}
 199
 200static void __exit e740_exit(void)
 201{
 202        platform_device_unregister(e740_snd_device);
 203}
 204
 205module_init(e740_init);
 206module_exit(e740_exit);
 207
 208/* Module information */
 209MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
 210MODULE_DESCRIPTION("ALSA SoC driver for e740");
 211MODULE_LICENSE("GPL v2");
 212