linux/sound/soc/samsung/neo1973_wm8753.c
<<
>>
Prefs
   1/*
   2 * neo1973_wm8753.c  --  SoC audio for Openmoko Neo1973 and Freerunner devices
   3 *
   4 * Copyright 2007 Openmoko Inc
   5 * Author: Graeme Gregory <graeme@openmoko.org>
   6 * Copyright 2007 Wolfson Microelectronics PLC.
   7 * Author: Graeme Gregory
   8 *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
   9 * Copyright 2009 Wolfson Microelectronics
  10 *
  11 *  This program is free software; you can redistribute  it and/or modify it
  12 *  under  the terms of  the GNU General  Public License as published by the
  13 *  Free Software Foundation;  either version 2 of the  License, or (at your
  14 *  option) any later version.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/platform_device.h>
  19#include <linux/gpio.h>
  20
  21#include <sound/soc.h>
  22
  23#include <asm/mach-types.h>
  24#include <plat/regs-iis.h>
  25#include <mach/gta02.h>
  26
  27#include "../codecs/wm8753.h"
  28#include "s3c24xx-i2s.h"
  29
  30static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
  31        struct snd_pcm_hw_params *params)
  32{
  33        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  34        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  35        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  36        unsigned int pll_out = 0, bclk = 0;
  37        int ret = 0;
  38        unsigned long iis_clkrate;
  39
  40        iis_clkrate = s3c24xx_i2s_get_clockrate();
  41
  42        switch (params_rate(params)) {
  43        case 8000:
  44        case 16000:
  45                pll_out = 12288000;
  46                break;
  47        case 48000:
  48                bclk = WM8753_BCLK_DIV_4;
  49                pll_out = 12288000;
  50                break;
  51        case 96000:
  52                bclk = WM8753_BCLK_DIV_2;
  53                pll_out = 12288000;
  54                break;
  55        case 11025:
  56                bclk = WM8753_BCLK_DIV_16;
  57                pll_out = 11289600;
  58                break;
  59        case 22050:
  60                bclk = WM8753_BCLK_DIV_8;
  61                pll_out = 11289600;
  62                break;
  63        case 44100:
  64                bclk = WM8753_BCLK_DIV_4;
  65                pll_out = 11289600;
  66                break;
  67        case 88200:
  68                bclk = WM8753_BCLK_DIV_2;
  69                pll_out = 11289600;
  70                break;
  71        }
  72
  73        /* set codec DAI configuration */
  74        ret = snd_soc_dai_set_fmt(codec_dai,
  75                SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  76                SND_SOC_DAIFMT_CBM_CFM);
  77        if (ret < 0)
  78                return ret;
  79
  80        /* set cpu DAI configuration */
  81        ret = snd_soc_dai_set_fmt(cpu_dai,
  82                SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  83                SND_SOC_DAIFMT_CBM_CFM);
  84        if (ret < 0)
  85                return ret;
  86
  87        /* set the codec system clock for DAC and ADC */
  88        ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
  89                SND_SOC_CLOCK_IN);
  90        if (ret < 0)
  91                return ret;
  92
  93        /* set MCLK division for sample rate */
  94        ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
  95                S3C2410_IISMOD_32FS);
  96        if (ret < 0)
  97                return ret;
  98
  99        /* set codec BCLK division for sample rate */
 100        ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
 101        if (ret < 0)
 102                return ret;
 103
 104        /* set prescaler division for sample rate */
 105        ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 106                S3C24XX_PRESCALE(4, 4));
 107        if (ret < 0)
 108                return ret;
 109
 110        /* codec PLL input is PCLK/4 */
 111        ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
 112                iis_clkrate / 4, pll_out);
 113        if (ret < 0)
 114                return ret;
 115
 116        return 0;
 117}
 118
 119static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
 120{
 121        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 122        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 123
 124        /* disable the PLL */
 125        return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
 126}
 127
 128/*
 129 * Neo1973 WM8753 HiFi DAI opserations.
 130 */
 131static struct snd_soc_ops neo1973_hifi_ops = {
 132        .hw_params = neo1973_hifi_hw_params,
 133        .hw_free = neo1973_hifi_hw_free,
 134};
 135
 136static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 137        struct snd_pcm_hw_params *params)
 138{
 139        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 140        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 141        unsigned int pcmdiv = 0;
 142        int ret = 0;
 143        unsigned long iis_clkrate;
 144
 145        iis_clkrate = s3c24xx_i2s_get_clockrate();
 146
 147        if (params_rate(params) != 8000)
 148                return -EINVAL;
 149        if (params_channels(params) != 1)
 150                return -EINVAL;
 151
 152        pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
 153
 154        /* todo: gg check mode (DSP_B) against CSR datasheet */
 155        /* set codec DAI configuration */
 156        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
 157                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
 158        if (ret < 0)
 159                return ret;
 160
 161        /* set the codec system clock for DAC and ADC */
 162        ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
 163                SND_SOC_CLOCK_IN);
 164        if (ret < 0)
 165                return ret;
 166
 167        /* set codec PCM division for sample rate */
 168        ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
 169        if (ret < 0)
 170                return ret;
 171
 172        /* configure and enable PLL for 12.288MHz output */
 173        ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
 174                iis_clkrate / 4, 12288000);
 175        if (ret < 0)
 176                return ret;
 177
 178        return 0;
 179}
 180
 181static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
 182{
 183        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 184        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 185
 186        /* disable the PLL */
 187        return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
 188}
 189
 190static struct snd_soc_ops neo1973_voice_ops = {
 191        .hw_params = neo1973_voice_hw_params,
 192        .hw_free = neo1973_voice_hw_free,
 193};
 194
 195/* Shared routes and controls */
 196
 197static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
 198        SND_SOC_DAPM_LINE("GSM Line Out", NULL),
 199        SND_SOC_DAPM_LINE("GSM Line In", NULL),
 200        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 201        SND_SOC_DAPM_MIC("Handset Mic", NULL),
 202};
 203
 204static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
 205        /* Connections to the GSM Module */
 206        {"GSM Line Out", NULL, "MONO1"},
 207        {"GSM Line Out", NULL, "MONO2"},
 208        {"RXP", NULL, "GSM Line In"},
 209        {"RXN", NULL, "GSM Line In"},
 210
 211        /* Connections to Headset */
 212        {"MIC1", NULL, "Mic Bias"},
 213        {"Mic Bias", NULL, "Headset Mic"},
 214
 215        /* Call Mic */
 216        {"MIC2", NULL, "Mic Bias"},
 217        {"MIC2N", NULL, "Mic Bias"},
 218        {"Mic Bias", NULL, "Handset Mic"},
 219
 220        /* Connect the ALC pins */
 221        {"ACIN", NULL, "ACOP"},
 222};
 223
 224static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
 225        SOC_DAPM_PIN_SWITCH("GSM Line Out"),
 226        SOC_DAPM_PIN_SWITCH("GSM Line In"),
 227        SOC_DAPM_PIN_SWITCH("Headset Mic"),
 228        SOC_DAPM_PIN_SWITCH("Handset Mic"),
 229};
 230
 231/* GTA02 specific routes and controls */
 232
 233static int gta02_speaker_enabled;
 234
 235static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
 236        struct snd_ctl_elem_value *ucontrol)
 237{
 238        gta02_speaker_enabled = ucontrol->value.integer.value[0];
 239
 240        gpio_set_value(S3C2410_GPJ(2), !gta02_speaker_enabled);
 241
 242        return 0;
 243}
 244
 245static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
 246        struct snd_ctl_elem_value *ucontrol)
 247{
 248        ucontrol->value.integer.value[0] = gta02_speaker_enabled;
 249        return 0;
 250}
 251
 252static int lm4853_event(struct snd_soc_dapm_widget *w,
 253                        struct snd_kcontrol *k, int event)
 254{
 255        gpio_set_value(S3C2410_GPJ(1), SND_SOC_DAPM_EVENT_OFF(event));
 256
 257        return 0;
 258}
 259
 260static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
 261        /* Connections to the amp */
 262        {"Stereo Out", NULL, "LOUT1"},
 263        {"Stereo Out", NULL, "ROUT1"},
 264
 265        /* Call Speaker */
 266        {"Handset Spk", NULL, "LOUT2"},
 267        {"Handset Spk", NULL, "ROUT2"},
 268};
 269
 270static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
 271        SOC_DAPM_PIN_SWITCH("Handset Spk"),
 272        SOC_DAPM_PIN_SWITCH("Stereo Out"),
 273
 274        SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
 275                lm4853_get_spk,
 276                lm4853_set_spk),
 277};
 278
 279static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = {
 280        SND_SOC_DAPM_SPK("Handset Spk", NULL),
 281        SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
 282};
 283
 284static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
 285{
 286        struct snd_soc_dapm_context *dapm = &codec->dapm;
 287        int ret;
 288
 289        ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets,
 290                        ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets));
 291        if (ret)
 292                return ret;
 293
 294        ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes,
 295                        ARRAY_SIZE(neo1973_gta02_routes));
 296        if (ret)
 297                return ret;
 298
 299        ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls,
 300                        ARRAY_SIZE(neo1973_gta02_wm8753_controls));
 301        if (ret)
 302                return ret;
 303
 304        snd_soc_dapm_disable_pin(dapm, "Stereo Out");
 305        snd_soc_dapm_disable_pin(dapm, "Handset Spk");
 306        snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
 307        snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
 308
 309        return 0;
 310}
 311
 312static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
 313{
 314        struct snd_soc_codec *codec = rtd->codec;
 315        struct snd_soc_dapm_context *dapm = &codec->dapm;
 316        int ret;
 317
 318        /* set up NC codec pins */
 319        snd_soc_dapm_nc_pin(dapm, "OUT3");
 320        snd_soc_dapm_nc_pin(dapm, "OUT4");
 321        snd_soc_dapm_nc_pin(dapm, "LINE1");
 322        snd_soc_dapm_nc_pin(dapm, "LINE2");
 323
 324        /* Add neo1973 specific widgets */
 325        ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets,
 326                        ARRAY_SIZE(neo1973_wm8753_dapm_widgets));
 327        if (ret)
 328                return ret;
 329
 330        /* add neo1973 specific controls */
 331        ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls,
 332                        ARRAY_SIZE(neo1973_wm8753_controls));
 333        if (ret)
 334                return ret;
 335
 336        /* set up neo1973 specific audio routes */
 337        ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes,
 338                        ARRAY_SIZE(neo1973_wm8753_routes));
 339        if (ret)
 340                return ret;
 341
 342        /* set endpoints to default off mode */
 343        snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
 344        snd_soc_dapm_disable_pin(dapm, "GSM Line In");
 345        snd_soc_dapm_disable_pin(dapm, "Headset Mic");
 346        snd_soc_dapm_disable_pin(dapm, "Handset Mic");
 347
 348        /* allow audio paths from the GSM modem to run during suspend */
 349        snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
 350        snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
 351        snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
 352        snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
 353
 354        if (machine_is_neo1973_gta02()) {
 355                ret = neo1973_gta02_wm8753_init(codec);
 356                if (ret)
 357                        return ret;
 358        }
 359
 360        return 0;
 361}
 362
 363static struct snd_soc_dai_link neo1973_dai[] = {
 364{ /* Hifi Playback - for similatious use with voice below */
 365        .name = "WM8753",
 366        .stream_name = "WM8753 HiFi",
 367        .platform_name = "s3c24xx-iis",
 368        .cpu_dai_name = "s3c24xx-iis",
 369        .codec_dai_name = "wm8753-hifi",
 370        .codec_name = "wm8753.0-001a",
 371        .init = neo1973_wm8753_init,
 372        .ops = &neo1973_hifi_ops,
 373},
 374{ /* Voice via BT */
 375        .name = "Bluetooth",
 376        .stream_name = "Voice",
 377        .cpu_dai_name = "dfbmcs320-pcm",
 378        .codec_dai_name = "wm8753-voice",
 379        .codec_name = "wm8753.0-001a",
 380        .ops = &neo1973_voice_ops,
 381},
 382};
 383
 384static struct snd_soc_aux_dev neo1973_aux_devs[] = {
 385        {
 386                .name = "dfbmcs320",
 387                .codec_name = "dfbmcs320.0",
 388        },
 389};
 390
 391static struct snd_soc_codec_conf neo1973_codec_conf[] = {
 392        {
 393                .dev_name = "lm4857.0-007c",
 394                .name_prefix = "Amp",
 395        },
 396};
 397
 398static const struct gpio neo1973_gta02_gpios[] = {
 399        { S3C2410_GPJ(2), GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
 400        { S3C2410_GPJ(1), GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
 401};
 402
 403static struct snd_soc_card neo1973 = {
 404        .name = "neo1973",
 405        .owner = THIS_MODULE,
 406        .dai_link = neo1973_dai,
 407        .num_links = ARRAY_SIZE(neo1973_dai),
 408        .aux_dev = neo1973_aux_devs,
 409        .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
 410        .codec_conf = neo1973_codec_conf,
 411        .num_configs = ARRAY_SIZE(neo1973_codec_conf),
 412};
 413
 414static struct platform_device *neo1973_snd_device;
 415
 416static int __init neo1973_init(void)
 417{
 418        int ret;
 419
 420        if (!machine_is_neo1973_gta02())
 421                return -ENODEV;
 422
 423        if (machine_is_neo1973_gta02()) {
 424                neo1973.name = "neo1973gta02";
 425                neo1973.num_aux_devs = 1;
 426
 427                ret = gpio_request_array(neo1973_gta02_gpios,
 428                                ARRAY_SIZE(neo1973_gta02_gpios));
 429                if (ret)
 430                        return ret;
 431        }
 432
 433        neo1973_snd_device = platform_device_alloc("soc-audio", -1);
 434        if (!neo1973_snd_device) {
 435                ret = -ENOMEM;
 436                goto err_gpio_free;
 437        }
 438
 439        platform_set_drvdata(neo1973_snd_device, &neo1973);
 440        ret = platform_device_add(neo1973_snd_device);
 441
 442        if (ret)
 443                goto err_put_device;
 444
 445        return 0;
 446
 447err_put_device:
 448        platform_device_put(neo1973_snd_device);
 449err_gpio_free:
 450        if (machine_is_neo1973_gta02()) {
 451                gpio_free_array(neo1973_gta02_gpios,
 452                                ARRAY_SIZE(neo1973_gta02_gpios));
 453        }
 454        return ret;
 455}
 456module_init(neo1973_init);
 457
 458static void __exit neo1973_exit(void)
 459{
 460        platform_device_unregister(neo1973_snd_device);
 461
 462        if (machine_is_neo1973_gta02()) {
 463                gpio_free_array(neo1973_gta02_gpios,
 464                                ARRAY_SIZE(neo1973_gta02_gpios));
 465        }
 466}
 467module_exit(neo1973_exit);
 468
 469/* Module information */
 470MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
 471MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
 472MODULE_LICENSE("GPL");
 473