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