linux/sound/soc/samsung/goni_wm8994.c
<<
>>
Prefs
   1/*
   2 * goni_wm8994.c
   3 *
   4 * Copyright (C) 2010 Samsung Electronics Co.Ltd
   5 * Author: Chanwoo Choi <cw00.choi@samsung.com>
   6 *
   7 *  This program is free software; you can redistribute  it and/or modify it
   8 *  under  the terms of  the GNU General  Public License as published by the
   9 *  Free Software Foundation;  either version 2 of the  License, or (at your
  10 *  option) any later version.
  11 *
  12 */
  13
  14#include <linux/module.h>
  15#include <sound/soc.h>
  16#include <sound/jack.h>
  17
  18#include <asm/mach-types.h>
  19#include <mach/gpio.h>
  20
  21#include "../codecs/wm8994.h"
  22
  23#define MACHINE_NAME    0
  24#define CPU_VOICE_DAI   1
  25
  26static const char *aquila_str[] = {
  27        [MACHINE_NAME] = "aquila",
  28        [CPU_VOICE_DAI] = "aquila-voice-dai",
  29};
  30
  31static struct snd_soc_card goni;
  32static struct platform_device *goni_snd_device;
  33
  34/* 3.5 pie jack */
  35static struct snd_soc_jack jack;
  36
  37/* 3.5 pie jack detection DAPM pins */
  38static struct snd_soc_jack_pin jack_pins[] = {
  39        {
  40                .pin = "Headset Mic",
  41                .mask = SND_JACK_MICROPHONE,
  42        }, {
  43                .pin = "Headset Stereophone",
  44                .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
  45                        SND_JACK_AVOUT,
  46        },
  47};
  48
  49/* 3.5 pie jack detection gpios */
  50static struct snd_soc_jack_gpio jack_gpios[] = {
  51        {
  52                .gpio = S5PV210_GPH0(6),
  53                .name = "DET_3.5",
  54                .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
  55                        SND_JACK_AVOUT,
  56                .debounce_time = 200,
  57        },
  58};
  59
  60static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
  61        SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
  62        SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
  63        SND_SOC_DAPM_SPK("Ext Rcv", NULL),
  64        SND_SOC_DAPM_HP("Headset Stereophone", NULL),
  65        SND_SOC_DAPM_MIC("Headset Mic", NULL),
  66        SND_SOC_DAPM_MIC("Main Mic", NULL),
  67        SND_SOC_DAPM_MIC("2nd Mic", NULL),
  68        SND_SOC_DAPM_LINE("Radio In", NULL),
  69};
  70
  71static const struct snd_soc_dapm_route goni_dapm_routes[] = {
  72        {"Ext Left Spk", NULL, "SPKOUTLP"},
  73        {"Ext Left Spk", NULL, "SPKOUTLN"},
  74
  75        {"Ext Right Spk", NULL, "SPKOUTRP"},
  76        {"Ext Right Spk", NULL, "SPKOUTRN"},
  77
  78        {"Ext Rcv", NULL, "HPOUT2N"},
  79        {"Ext Rcv", NULL, "HPOUT2P"},
  80
  81        {"Headset Stereophone", NULL, "HPOUT1L"},
  82        {"Headset Stereophone", NULL, "HPOUT1R"},
  83
  84        {"IN1RN", NULL, "Headset Mic"},
  85        {"IN1RP", NULL, "Headset Mic"},
  86
  87        {"IN1RN", NULL, "2nd Mic"},
  88        {"IN1RP", NULL, "2nd Mic"},
  89
  90        {"IN1LN", NULL, "Main Mic"},
  91        {"IN1LP", NULL, "Main Mic"},
  92
  93        {"IN2LN", NULL, "Radio In"},
  94        {"IN2RN", NULL, "Radio In"},
  95};
  96
  97static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
  98{
  99        struct snd_soc_codec *codec = rtd->codec;
 100        struct snd_soc_dapm_context *dapm = &codec->dapm;
 101        int ret;
 102
 103        /* set endpoints to not connected */
 104        snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
 105        snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
 106        snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
 107        snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
 108        snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
 109        snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
 110
 111        if (machine_is_aquila()) {
 112                snd_soc_dapm_nc_pin(dapm, "SPKOUTRN");
 113                snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
 114        }
 115
 116        /* Headset jack detection */
 117        ret = snd_soc_jack_new(codec, "Headset Jack",
 118                        SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
 119                        &jack);
 120        if (ret)
 121                return ret;
 122
 123        ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
 124        if (ret)
 125                return ret;
 126
 127        ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
 128        if (ret)
 129                return ret;
 130
 131        return 0;
 132}
 133
 134static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
 135                struct snd_pcm_hw_params *params)
 136{
 137        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 138        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 139        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 140        unsigned int pll_out = 24000000;
 141        int ret = 0;
 142
 143        /* set the cpu DAI configuration */
 144        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
 145                        SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
 146        if (ret < 0)
 147                return ret;
 148
 149        /* set codec DAI configuration */
 150        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
 151                        SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
 152        if (ret < 0)
 153                return ret;
 154
 155        /* set the codec FLL */
 156        ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
 157                        params_rate(params) * 256);
 158        if (ret < 0)
 159                return ret;
 160
 161        /* set the codec system clock */
 162        ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
 163                        params_rate(params) * 256, SND_SOC_CLOCK_IN);
 164        if (ret < 0)
 165                return ret;
 166
 167        return 0;
 168}
 169
 170static struct snd_soc_ops goni_hifi_ops = {
 171        .hw_params = goni_hifi_hw_params,
 172};
 173
 174static int goni_voice_hw_params(struct snd_pcm_substream *substream,
 175                struct snd_pcm_hw_params *params)
 176{
 177        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 178        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 179        unsigned int pll_out = 24000000;
 180        int ret = 0;
 181
 182        if (params_rate(params) != 8000)
 183                return -EINVAL;
 184
 185        /* set codec DAI configuration */
 186        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
 187                        SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
 188        if (ret < 0)
 189                return ret;
 190
 191        /* set the codec FLL */
 192        ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
 193                        params_rate(params) * 256);
 194        if (ret < 0)
 195                return ret;
 196
 197        /* set the codec system clock */
 198        ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
 199                        params_rate(params) * 256, SND_SOC_CLOCK_IN);
 200        if (ret < 0)
 201                return ret;
 202
 203        return 0;
 204}
 205
 206static struct snd_soc_dai_driver voice_dai = {
 207        .name = "goni-voice-dai",
 208        .id = 0,
 209        .playback = {
 210                .channels_min = 1,
 211                .channels_max = 2,
 212                .rates = SNDRV_PCM_RATE_8000,
 213                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
 214        .capture = {
 215                .channels_min = 1,
 216                .channels_max = 2,
 217                .rates = SNDRV_PCM_RATE_8000,
 218                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
 219};
 220
 221static const struct snd_soc_component_driver voice_component = {
 222        .name           = "goni-voice",
 223};
 224
 225static struct snd_soc_ops goni_voice_ops = {
 226        .hw_params = goni_voice_hw_params,
 227};
 228
 229static struct snd_soc_dai_link goni_dai[] = {
 230{
 231        .name = "WM8994",
 232        .stream_name = "WM8994 HiFi",
 233        .cpu_dai_name = "samsung-i2s.0",
 234        .codec_dai_name = "wm8994-aif1",
 235        .platform_name = "samsung-i2s.0",
 236        .codec_name = "wm8994-codec.0-001a",
 237        .init = goni_wm8994_init,
 238        .ops = &goni_hifi_ops,
 239}, {
 240        .name = "WM8994 Voice",
 241        .stream_name = "Voice",
 242        .cpu_dai_name = "goni-voice-dai",
 243        .codec_dai_name = "wm8994-aif2",
 244        .codec_name = "wm8994-codec.0-001a",
 245        .ops = &goni_voice_ops,
 246},
 247};
 248
 249static struct snd_soc_card goni = {
 250        .name = "goni",
 251        .owner = THIS_MODULE,
 252        .dai_link = goni_dai,
 253        .num_links = ARRAY_SIZE(goni_dai),
 254
 255        .dapm_widgets = goni_dapm_widgets,
 256        .num_dapm_widgets = ARRAY_SIZE(goni_dapm_widgets),
 257        .dapm_routes = goni_dapm_routes,
 258        .num_dapm_routes = ARRAY_SIZE(goni_dapm_routes),
 259};
 260
 261static int __init goni_init(void)
 262{
 263        int ret;
 264
 265        if (machine_is_aquila()) {
 266                voice_dai.name = aquila_str[CPU_VOICE_DAI];
 267                goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI];
 268                goni.name = aquila_str[MACHINE_NAME];
 269        } else if (!machine_is_goni())
 270                return -ENODEV;
 271
 272        goni_snd_device = platform_device_alloc("soc-audio", -1);
 273        if (!goni_snd_device)
 274                return -ENOMEM;
 275
 276        /* register voice DAI here */
 277        ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component,
 278                                         &voice_dai, 1);
 279        if (ret) {
 280                platform_device_put(goni_snd_device);
 281                return ret;
 282        }
 283
 284        platform_set_drvdata(goni_snd_device, &goni);
 285        ret = platform_device_add(goni_snd_device);
 286
 287        if (ret) {
 288                snd_soc_unregister_component(&goni_snd_device->dev);
 289                platform_device_put(goni_snd_device);
 290        }
 291
 292        return ret;
 293}
 294
 295static void __exit goni_exit(void)
 296{
 297        snd_soc_unregister_component(&goni_snd_device->dev);
 298        platform_device_unregister(goni_snd_device);
 299}
 300
 301module_init(goni_init);
 302module_exit(goni_exit);
 303
 304/* Module information */
 305MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
 306MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
 307MODULE_LICENSE("GPL");
 308