linux/sound/soc/omap/rx51.c
<<
>>
Prefs
   1/*
   2 * rx51.c  --  SoC audio for Nokia RX-51
   3 *
   4 * Copyright (C) 2008 - 2009 Nokia Corporation
   5 *
   6 * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com>
   7 *          Eduardo Valentin <eduardo.valentin@nokia.com>
   8 *          Jarkko Nikula <jhnikula@gmail.com>
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License
  12 * version 2 as published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  22 * 02110-1301 USA
  23 *
  24 */
  25
  26#include <linux/delay.h>
  27#include <linux/gpio.h>
  28#include <linux/platform_device.h>
  29#include <sound/core.h>
  30#include <sound/jack.h>
  31#include <sound/pcm.h>
  32#include <sound/soc.h>
  33#include <plat/mcbsp.h>
  34
  35#include <asm/mach-types.h>
  36
  37#include "omap-mcbsp.h"
  38#include "omap-pcm.h"
  39
  40#define RX51_TVOUT_SEL_GPIO             40
  41#define RX51_JACK_DETECT_GPIO           177
  42/*
  43 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
  44 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
  45 */
  46#define RX51_SPEAKER_AMP_TWL_GPIO       (192 + 7)
  47
  48enum {
  49        RX51_JACK_DISABLED,
  50        RX51_JACK_TVOUT,                /* tv-out */
  51};
  52
  53static int rx51_spk_func;
  54static int rx51_dmic_func;
  55static int rx51_jack_func;
  56
  57static void rx51_ext_control(struct snd_soc_codec *codec)
  58{
  59        struct snd_soc_dapm_context *dapm = &codec->dapm;
  60
  61        if (rx51_spk_func)
  62                snd_soc_dapm_enable_pin(dapm, "Ext Spk");
  63        else
  64                snd_soc_dapm_disable_pin(dapm, "Ext Spk");
  65        if (rx51_dmic_func)
  66                snd_soc_dapm_enable_pin(dapm, "DMic");
  67        else
  68                snd_soc_dapm_disable_pin(dapm, "DMic");
  69
  70        gpio_set_value(RX51_TVOUT_SEL_GPIO,
  71                       rx51_jack_func == RX51_JACK_TVOUT);
  72
  73        snd_soc_dapm_sync(dapm);
  74}
  75
  76static int rx51_startup(struct snd_pcm_substream *substream)
  77{
  78        struct snd_pcm_runtime *runtime = substream->runtime;
  79        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  80        struct snd_soc_codec *codec = rtd->codec;
  81
  82        snd_pcm_hw_constraint_minmax(runtime,
  83                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
  84        rx51_ext_control(codec);
  85
  86        return 0;
  87}
  88
  89static int rx51_hw_params(struct snd_pcm_substream *substream,
  90        struct snd_pcm_hw_params *params)
  91{
  92        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  93        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  94        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  95        int err;
  96
  97        /* Set codec DAI configuration */
  98        err = snd_soc_dai_set_fmt(codec_dai,
  99                                  SND_SOC_DAIFMT_DSP_A |
 100                                  SND_SOC_DAIFMT_IB_NF |
 101                                  SND_SOC_DAIFMT_CBM_CFM);
 102        if (err < 0)
 103                return err;
 104
 105        /* Set cpu DAI configuration */
 106        err = snd_soc_dai_set_fmt(cpu_dai,
 107                                  SND_SOC_DAIFMT_DSP_A |
 108                                  SND_SOC_DAIFMT_IB_NF |
 109                                  SND_SOC_DAIFMT_CBM_CFM);
 110        if (err < 0)
 111                return err;
 112
 113        /* Set the codec system clock for DAC and ADC */
 114        return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
 115                                      SND_SOC_CLOCK_IN);
 116}
 117
 118static struct snd_soc_ops rx51_ops = {
 119        .startup = rx51_startup,
 120        .hw_params = rx51_hw_params,
 121};
 122
 123static int rx51_get_spk(struct snd_kcontrol *kcontrol,
 124                        struct snd_ctl_elem_value *ucontrol)
 125{
 126        ucontrol->value.integer.value[0] = rx51_spk_func;
 127
 128        return 0;
 129}
 130
 131static int rx51_set_spk(struct snd_kcontrol *kcontrol,
 132                        struct snd_ctl_elem_value *ucontrol)
 133{
 134        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 135
 136        if (rx51_spk_func == ucontrol->value.integer.value[0])
 137                return 0;
 138
 139        rx51_spk_func = ucontrol->value.integer.value[0];
 140        rx51_ext_control(codec);
 141
 142        return 1;
 143}
 144
 145static int rx51_spk_event(struct snd_soc_dapm_widget *w,
 146                          struct snd_kcontrol *k, int event)
 147{
 148        if (SND_SOC_DAPM_EVENT_ON(event))
 149                gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
 150        else
 151                gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
 152
 153        return 0;
 154}
 155
 156static int rx51_get_input(struct snd_kcontrol *kcontrol,
 157                          struct snd_ctl_elem_value *ucontrol)
 158{
 159        ucontrol->value.integer.value[0] = rx51_dmic_func;
 160
 161        return 0;
 162}
 163
 164static int rx51_set_input(struct snd_kcontrol *kcontrol,
 165                          struct snd_ctl_elem_value *ucontrol)
 166{
 167        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 168
 169        if (rx51_dmic_func == ucontrol->value.integer.value[0])
 170                return 0;
 171
 172        rx51_dmic_func = ucontrol->value.integer.value[0];
 173        rx51_ext_control(codec);
 174
 175        return 1;
 176}
 177
 178static int rx51_get_jack(struct snd_kcontrol *kcontrol,
 179                         struct snd_ctl_elem_value *ucontrol)
 180{
 181        ucontrol->value.integer.value[0] = rx51_jack_func;
 182
 183        return 0;
 184}
 185
 186static int rx51_set_jack(struct snd_kcontrol *kcontrol,
 187                         struct snd_ctl_elem_value *ucontrol)
 188{
 189        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 190
 191        if (rx51_jack_func == ucontrol->value.integer.value[0])
 192                return 0;
 193
 194        rx51_jack_func = ucontrol->value.integer.value[0];
 195        rx51_ext_control(codec);
 196
 197        return 1;
 198}
 199
 200static struct snd_soc_jack rx51_av_jack;
 201
 202static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
 203        {
 204                .gpio = RX51_JACK_DETECT_GPIO,
 205                .name = "avdet-gpio",
 206                .report = SND_JACK_VIDEOOUT,
 207                .invert = 1,
 208                .debounce_time = 200,
 209        },
 210};
 211
 212static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
 213        SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
 214        SND_SOC_DAPM_MIC("DMic", NULL),
 215};
 216
 217static const struct snd_soc_dapm_route audio_map[] = {
 218        {"Ext Spk", NULL, "HPLOUT"},
 219        {"Ext Spk", NULL, "HPROUT"},
 220
 221        {"DMic Rate 64", NULL, "Mic Bias 2V"},
 222        {"Mic Bias 2V", NULL, "DMic"},
 223};
 224
 225static const char *spk_function[] = {"Off", "On"};
 226static const char *input_function[] = {"ADC", "Digital Mic"};
 227static const char *jack_function[] = {"Off", "TV-OUT"};
 228
 229static const struct soc_enum rx51_enum[] = {
 230        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
 231        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
 232        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
 233};
 234
 235static const struct snd_kcontrol_new aic34_rx51_controls[] = {
 236        SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
 237                     rx51_get_spk, rx51_set_spk),
 238        SOC_ENUM_EXT("Input Select",  rx51_enum[1],
 239                     rx51_get_input, rx51_set_input),
 240        SOC_ENUM_EXT("Jack Function", rx51_enum[2],
 241                     rx51_get_jack, rx51_set_jack),
 242};
 243
 244static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 245{
 246        struct snd_soc_codec *codec = rtd->codec;
 247        struct snd_soc_dapm_context *dapm = &codec->dapm;
 248        int err;
 249
 250        /* Set up NC codec pins */
 251        snd_soc_dapm_nc_pin(dapm, "MIC3L");
 252        snd_soc_dapm_nc_pin(dapm, "MIC3R");
 253        snd_soc_dapm_nc_pin(dapm, "LINE1R");
 254
 255        /* Add RX-51 specific controls */
 256        err = snd_soc_add_controls(codec, aic34_rx51_controls,
 257                                   ARRAY_SIZE(aic34_rx51_controls));
 258        if (err < 0)
 259                return err;
 260
 261        /* Add RX-51 specific widgets */
 262        snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
 263                                  ARRAY_SIZE(aic34_dapm_widgets));
 264
 265        /* Set up RX-51 specific audio path audio_map */
 266        snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 267
 268        snd_soc_dapm_sync(dapm);
 269
 270        /* AV jack detection */
 271        err = snd_soc_jack_new(codec, "AV Jack",
 272                               SND_JACK_VIDEOOUT, &rx51_av_jack);
 273        if (err)
 274                return err;
 275        err = snd_soc_jack_add_gpios(&rx51_av_jack,
 276                                     ARRAY_SIZE(rx51_av_jack_gpios),
 277                                     rx51_av_jack_gpios);
 278
 279        return err;
 280}
 281
 282/* Digital audio interface glue - connects codec <--> CPU */
 283static struct snd_soc_dai_link rx51_dai[] = {
 284        {
 285                .name = "TLV320AIC34",
 286                .stream_name = "AIC34",
 287                .cpu_dai_name = "omap-mcbsp-dai.1",
 288                .codec_dai_name = "tlv320aic3x-hifi",
 289                .platform_name = "omap-pcm-audio",
 290                .codec_name = "tlv320aic3x-codec.2-0018",
 291                .init = rx51_aic34_init,
 292                .ops = &rx51_ops,
 293        },
 294};
 295
 296/* Audio card */
 297static struct snd_soc_card rx51_sound_card = {
 298        .name = "RX-51",
 299        .dai_link = rx51_dai,
 300        .num_links = ARRAY_SIZE(rx51_dai),
 301};
 302
 303static struct platform_device *rx51_snd_device;
 304
 305static int __init rx51_soc_init(void)
 306{
 307        int err;
 308
 309        if (!machine_is_nokia_rx51())
 310                return -ENODEV;
 311
 312        err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel");
 313        if (err)
 314                goto err_gpio_tvout_sel;
 315        gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0);
 316
 317        rx51_snd_device = platform_device_alloc("soc-audio", -1);
 318        if (!rx51_snd_device) {
 319                err = -ENOMEM;
 320                goto err1;
 321        }
 322
 323        platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
 324
 325        err = platform_device_add(rx51_snd_device);
 326        if (err)
 327                goto err2;
 328
 329        return 0;
 330err2:
 331        platform_device_put(rx51_snd_device);
 332err1:
 333        gpio_free(RX51_TVOUT_SEL_GPIO);
 334err_gpio_tvout_sel:
 335
 336        return err;
 337}
 338
 339static void __exit rx51_soc_exit(void)
 340{
 341        snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
 342                                rx51_av_jack_gpios);
 343
 344        platform_device_unregister(rx51_snd_device);
 345        gpio_free(RX51_TVOUT_SEL_GPIO);
 346}
 347
 348module_init(rx51_soc_init);
 349module_exit(rx51_soc_exit);
 350
 351MODULE_AUTHOR("Nokia Corporation");
 352MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
 353MODULE_LICENSE("GPL");
 354