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
 269SND_SOC_DAILINK_DEFS(wm8753,
 270        DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 271        DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-hifi")),
 272        DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 273
 274SND_SOC_DAILINK_DEFS(bluetooth,
 275        DAILINK_COMP_ARRAY(COMP_CPU("bt-sco-pcm")),
 276        DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-voice")));
 277
 278static struct snd_soc_dai_link neo1973_dai[] = {
 279{ /* Hifi Playback - for similatious use with voice below */
 280        .name = "WM8753",
 281        .stream_name = "WM8753 HiFi",
 282        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 283                   SND_SOC_DAIFMT_CBM_CFM,
 284        .init = neo1973_wm8753_init,
 285        .ops = &neo1973_hifi_ops,
 286        SND_SOC_DAILINK_REG(wm8753),
 287},
 288{ /* Voice via BT */
 289        .name = "Bluetooth",
 290        .stream_name = "Voice",
 291        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
 292                   SND_SOC_DAIFMT_CBS_CFS,
 293        .ops = &neo1973_voice_ops,
 294        SND_SOC_DAILINK_REG(bluetooth),
 295},
 296};
 297
 298static struct snd_soc_aux_dev neo1973_aux_devs[] = {
 299        {
 300                .name = "dfbmcs320",
 301                .codec_name = "dfbmcs320.0",
 302        },
 303};
 304
 305static struct snd_soc_codec_conf neo1973_codec_conf[] = {
 306        {
 307                .dev_name = "lm4857.0-007c",
 308                .name_prefix = "Amp",
 309        },
 310};
 311
 312static const struct gpio neo1973_gta02_gpios[] = {
 313        { S3C2410_GPJ(2), GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
 314        { S3C2410_GPJ(1), GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
 315};
 316
 317static struct snd_soc_card neo1973 = {
 318        .name = "neo1973",
 319        .owner = THIS_MODULE,
 320        .dai_link = neo1973_dai,
 321        .num_links = ARRAY_SIZE(neo1973_dai),
 322        .aux_dev = neo1973_aux_devs,
 323        .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
 324        .codec_conf = neo1973_codec_conf,
 325        .num_configs = ARRAY_SIZE(neo1973_codec_conf),
 326
 327        .controls = neo1973_wm8753_controls,
 328        .num_controls = ARRAY_SIZE(neo1973_wm8753_controls),
 329        .dapm_widgets = neo1973_wm8753_dapm_widgets,
 330        .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
 331        .dapm_routes = neo1973_wm8753_routes,
 332        .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
 333        .fully_routed = true,
 334};
 335
 336static struct platform_device *neo1973_snd_device;
 337
 338static int __init neo1973_init(void)
 339{
 340        int ret;
 341
 342        if (!machine_is_neo1973_gta02())
 343                return -ENODEV;
 344
 345        if (machine_is_neo1973_gta02()) {
 346                neo1973.name = "neo1973gta02";
 347                neo1973.num_aux_devs = 1;
 348
 349                ret = gpio_request_array(neo1973_gta02_gpios,
 350                                ARRAY_SIZE(neo1973_gta02_gpios));
 351                if (ret)
 352                        return ret;
 353        }
 354
 355        neo1973_snd_device = platform_device_alloc("soc-audio", -1);
 356        if (!neo1973_snd_device) {
 357                ret = -ENOMEM;
 358                goto err_gpio_free;
 359        }
 360
 361        platform_set_drvdata(neo1973_snd_device, &neo1973);
 362        ret = platform_device_add(neo1973_snd_device);
 363
 364        if (ret)
 365                goto err_put_device;
 366
 367        return 0;
 368
 369err_put_device:
 370        platform_device_put(neo1973_snd_device);
 371err_gpio_free:
 372        if (machine_is_neo1973_gta02()) {
 373                gpio_free_array(neo1973_gta02_gpios,
 374                                ARRAY_SIZE(neo1973_gta02_gpios));
 375        }
 376        return ret;
 377}
 378module_init(neo1973_init);
 379
 380static void __exit neo1973_exit(void)
 381{
 382        platform_device_unregister(neo1973_snd_device);
 383
 384        if (machine_is_neo1973_gta02()) {
 385                gpio_free_array(neo1973_gta02_gpios,
 386                                ARRAY_SIZE(neo1973_gta02_gpios));
 387        }
 388}
 389module_exit(neo1973_exit);
 390
 391/* Module information */
 392MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
 393MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
 394MODULE_LICENSE("GPL");
 395