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@ti.com>
   7 *          Eduardo Valentin <eduardo.valentin@nokia.com>
   8 *          Jarkko Nikula <jarkko.nikula@bitmer.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 <linux/module.h>
  30#include <sound/core.h>
  31#include <sound/jack.h>
  32#include <sound/pcm.h>
  33#include <sound/soc.h>
  34#include <linux/platform_data/asoc-ti-mcbsp.h>
  35#include "../codecs/tpa6130a2.h"
  36
  37#include <asm/mach-types.h>
  38
  39#include "omap-mcbsp.h"
  40
  41#define RX51_TVOUT_SEL_GPIO             40
  42#define RX51_JACK_DETECT_GPIO           177
  43#define RX51_ECI_SW_GPIO                182
  44/*
  45 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
  46 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
  47 */
  48#define RX51_SPEAKER_AMP_TWL_GPIO       (192 + 7)
  49
  50enum {
  51        RX51_JACK_DISABLED,
  52        RX51_JACK_TVOUT,                /* tv-out with stereo output */
  53        RX51_JACK_HP,                   /* headphone: stereo output, no mic */
  54        RX51_JACK_HS,                   /* headset: stereo output with mic */
  55};
  56
  57static int rx51_spk_func;
  58static int rx51_dmic_func;
  59static int rx51_jack_func;
  60
  61static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
  62{
  63        int hp = 0, hs = 0, tvout = 0;
  64
  65        switch (rx51_jack_func) {
  66        case RX51_JACK_TVOUT:
  67                tvout = 1;
  68                hp = 1;
  69                break;
  70        case RX51_JACK_HS:
  71                hs = 1;
  72        case RX51_JACK_HP:
  73                hp = 1;
  74                break;
  75        }
  76
  77        if (rx51_spk_func)
  78                snd_soc_dapm_enable_pin(dapm, "Ext Spk");
  79        else
  80                snd_soc_dapm_disable_pin(dapm, "Ext Spk");
  81        if (rx51_dmic_func)
  82                snd_soc_dapm_enable_pin(dapm, "DMic");
  83        else
  84                snd_soc_dapm_disable_pin(dapm, "DMic");
  85        if (hp)
  86                snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
  87        else
  88                snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
  89        if (hs)
  90                snd_soc_dapm_enable_pin(dapm, "HS Mic");
  91        else
  92                snd_soc_dapm_disable_pin(dapm, "HS Mic");
  93
  94        gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
  95
  96        snd_soc_dapm_sync(dapm);
  97}
  98
  99static int rx51_startup(struct snd_pcm_substream *substream)
 100{
 101        struct snd_pcm_runtime *runtime = substream->runtime;
 102        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 103        struct snd_soc_card *card = rtd->card;
 104
 105        snd_pcm_hw_constraint_minmax(runtime,
 106                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
 107        rx51_ext_control(&card->dapm);
 108
 109        return 0;
 110}
 111
 112static int rx51_hw_params(struct snd_pcm_substream *substream,
 113        struct snd_pcm_hw_params *params)
 114{
 115        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 116        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 117
 118        /* Set the codec system clock for DAC and ADC */
 119        return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
 120                                      SND_SOC_CLOCK_IN);
 121}
 122
 123static struct snd_soc_ops rx51_ops = {
 124        .startup = rx51_startup,
 125        .hw_params = rx51_hw_params,
 126};
 127
 128static int rx51_get_spk(struct snd_kcontrol *kcontrol,
 129                        struct snd_ctl_elem_value *ucontrol)
 130{
 131        ucontrol->value.integer.value[0] = rx51_spk_func;
 132
 133        return 0;
 134}
 135
 136static int rx51_set_spk(struct snd_kcontrol *kcontrol,
 137                        struct snd_ctl_elem_value *ucontrol)
 138{
 139        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 140
 141        if (rx51_spk_func == ucontrol->value.integer.value[0])
 142                return 0;
 143
 144        rx51_spk_func = ucontrol->value.integer.value[0];
 145        rx51_ext_control(&card->dapm);
 146
 147        return 1;
 148}
 149
 150static int rx51_spk_event(struct snd_soc_dapm_widget *w,
 151                          struct snd_kcontrol *k, int event)
 152{
 153        if (SND_SOC_DAPM_EVENT_ON(event))
 154                gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
 155        else
 156                gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
 157
 158        return 0;
 159}
 160
 161static int rx51_hp_event(struct snd_soc_dapm_widget *w,
 162                         struct snd_kcontrol *k, int event)
 163{
 164        struct snd_soc_codec *codec = w->dapm->codec;
 165
 166        if (SND_SOC_DAPM_EVENT_ON(event))
 167                tpa6130a2_stereo_enable(codec, 1);
 168        else
 169                tpa6130a2_stereo_enable(codec, 0);
 170
 171        return 0;
 172}
 173
 174static int rx51_get_input(struct snd_kcontrol *kcontrol,
 175                          struct snd_ctl_elem_value *ucontrol)
 176{
 177        ucontrol->value.integer.value[0] = rx51_dmic_func;
 178
 179        return 0;
 180}
 181
 182static int rx51_set_input(struct snd_kcontrol *kcontrol,
 183                          struct snd_ctl_elem_value *ucontrol)
 184{
 185        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 186
 187        if (rx51_dmic_func == ucontrol->value.integer.value[0])
 188                return 0;
 189
 190        rx51_dmic_func = ucontrol->value.integer.value[0];
 191        rx51_ext_control(&card->dapm);
 192
 193        return 1;
 194}
 195
 196static int rx51_get_jack(struct snd_kcontrol *kcontrol,
 197                         struct snd_ctl_elem_value *ucontrol)
 198{
 199        ucontrol->value.integer.value[0] = rx51_jack_func;
 200
 201        return 0;
 202}
 203
 204static int rx51_set_jack(struct snd_kcontrol *kcontrol,
 205                         struct snd_ctl_elem_value *ucontrol)
 206{
 207        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 208
 209        if (rx51_jack_func == ucontrol->value.integer.value[0])
 210                return 0;
 211
 212        rx51_jack_func = ucontrol->value.integer.value[0];
 213        rx51_ext_control(&card->dapm);
 214
 215        return 1;
 216}
 217
 218static struct snd_soc_jack rx51_av_jack;
 219
 220static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
 221        {
 222                .gpio = RX51_JACK_DETECT_GPIO,
 223                .name = "avdet-gpio",
 224                .report = SND_JACK_HEADSET,
 225                .invert = 1,
 226                .debounce_time = 200,
 227        },
 228};
 229
 230static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
 231        SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
 232        SND_SOC_DAPM_MIC("DMic", NULL),
 233        SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
 234        SND_SOC_DAPM_MIC("HS Mic", NULL),
 235        SND_SOC_DAPM_LINE("FM Transmitter", NULL),
 236};
 237
 238static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
 239        SND_SOC_DAPM_SPK("Earphone", NULL),
 240};
 241
 242static const struct snd_soc_dapm_route audio_map[] = {
 243        {"Ext Spk", NULL, "HPLOUT"},
 244        {"Ext Spk", NULL, "HPROUT"},
 245        {"Headphone Jack", NULL, "LLOUT"},
 246        {"Headphone Jack", NULL, "RLOUT"},
 247        {"FM Transmitter", NULL, "LLOUT"},
 248        {"FM Transmitter", NULL, "RLOUT"},
 249
 250        {"DMic Rate 64", NULL, "Mic Bias"},
 251        {"Mic Bias", NULL, "DMic"},
 252};
 253
 254static const struct snd_soc_dapm_route audio_mapb[] = {
 255        {"b LINE2R", NULL, "MONO_LOUT"},
 256        {"Earphone", NULL, "b HPLOUT"},
 257
 258        {"LINE1L", NULL, "b Mic Bias"},
 259        {"b Mic Bias", NULL, "HS Mic"}
 260};
 261
 262static const char *spk_function[] = {"Off", "On"};
 263static const char *input_function[] = {"ADC", "Digital Mic"};
 264static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"};
 265
 266static const struct soc_enum rx51_enum[] = {
 267        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
 268        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
 269        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
 270};
 271
 272static const struct snd_kcontrol_new aic34_rx51_controls[] = {
 273        SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
 274                     rx51_get_spk, rx51_set_spk),
 275        SOC_ENUM_EXT("Input Select",  rx51_enum[1],
 276                     rx51_get_input, rx51_set_input),
 277        SOC_ENUM_EXT("Jack Function", rx51_enum[2],
 278                     rx51_get_jack, rx51_set_jack),
 279        SOC_DAPM_PIN_SWITCH("FM Transmitter"),
 280};
 281
 282static const struct snd_kcontrol_new aic34_rx51_controlsb[] = {
 283        SOC_DAPM_PIN_SWITCH("Earphone"),
 284};
 285
 286static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 287{
 288        struct snd_soc_codec *codec = rtd->codec;
 289        struct snd_soc_dapm_context *dapm = &codec->dapm;
 290        int err;
 291
 292        /* Set up NC codec pins */
 293        snd_soc_dapm_nc_pin(dapm, "MIC3L");
 294        snd_soc_dapm_nc_pin(dapm, "MIC3R");
 295        snd_soc_dapm_nc_pin(dapm, "LINE1R");
 296
 297        /* Add RX-51 specific controls */
 298        err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls,
 299                                   ARRAY_SIZE(aic34_rx51_controls));
 300        if (err < 0)
 301                return err;
 302
 303        /* Add RX-51 specific widgets */
 304        snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
 305                                  ARRAY_SIZE(aic34_dapm_widgets));
 306
 307        /* Set up RX-51 specific audio path audio_map */
 308        snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 309
 310        err = tpa6130a2_add_controls(codec);
 311        if (err < 0)
 312                return err;
 313        snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
 314
 315        err = omap_mcbsp_st_add_controls(rtd);
 316        if (err < 0)
 317                return err;
 318
 319        /* AV jack detection */
 320        err = snd_soc_jack_new(codec, "AV Jack",
 321                               SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
 322                               &rx51_av_jack);
 323        if (err)
 324                return err;
 325        err = snd_soc_jack_add_gpios(&rx51_av_jack,
 326                                     ARRAY_SIZE(rx51_av_jack_gpios),
 327                                     rx51_av_jack_gpios);
 328
 329        return err;
 330}
 331
 332static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
 333{
 334        int err;
 335
 336        err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb,
 337                                   ARRAY_SIZE(aic34_rx51_controlsb));
 338        if (err < 0)
 339                return err;
 340
 341        err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb,
 342                                        ARRAY_SIZE(aic34_dapm_widgetsb));
 343        if (err < 0)
 344                return 0;
 345
 346        return snd_soc_dapm_add_routes(dapm, audio_mapb,
 347                                       ARRAY_SIZE(audio_mapb));
 348}
 349
 350/* Digital audio interface glue - connects codec <--> CPU */
 351static struct snd_soc_dai_link rx51_dai[] = {
 352        {
 353                .name = "TLV320AIC34",
 354                .stream_name = "AIC34",
 355                .cpu_dai_name = "omap-mcbsp.2",
 356                .codec_dai_name = "tlv320aic3x-hifi",
 357                .platform_name = "omap-pcm-audio",
 358                .codec_name = "tlv320aic3x-codec.2-0018",
 359                .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
 360                           SND_SOC_DAIFMT_CBM_CFM,
 361                .init = rx51_aic34_init,
 362                .ops = &rx51_ops,
 363        },
 364};
 365
 366static struct snd_soc_aux_dev rx51_aux_dev[] = {
 367        {
 368                .name = "TLV320AIC34b",
 369                .codec_name = "tlv320aic3x-codec.2-0019",
 370                .init = rx51_aic34b_init,
 371        },
 372};
 373
 374static struct snd_soc_codec_conf rx51_codec_conf[] = {
 375        {
 376                .dev_name = "tlv320aic3x-codec.2-0019",
 377                .name_prefix = "b",
 378        },
 379};
 380
 381/* Audio card */
 382static struct snd_soc_card rx51_sound_card = {
 383        .name = "RX-51",
 384        .owner = THIS_MODULE,
 385        .dai_link = rx51_dai,
 386        .num_links = ARRAY_SIZE(rx51_dai),
 387        .aux_dev = rx51_aux_dev,
 388        .num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
 389        .codec_conf = rx51_codec_conf,
 390        .num_configs = ARRAY_SIZE(rx51_codec_conf),
 391};
 392
 393static struct platform_device *rx51_snd_device;
 394
 395static int __init rx51_soc_init(void)
 396{
 397        int err;
 398
 399        if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
 400                return -ENODEV;
 401
 402        err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
 403                               GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel");
 404        if (err)
 405                goto err_gpio_tvout_sel;
 406        err = gpio_request_one(RX51_ECI_SW_GPIO,
 407                               GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw");
 408        if (err)
 409                goto err_gpio_eci_sw;
 410
 411        rx51_snd_device = platform_device_alloc("soc-audio", -1);
 412        if (!rx51_snd_device) {
 413                err = -ENOMEM;
 414                goto err1;
 415        }
 416
 417        platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
 418
 419        err = platform_device_add(rx51_snd_device);
 420        if (err)
 421                goto err2;
 422
 423        return 0;
 424err2:
 425        platform_device_put(rx51_snd_device);
 426err1:
 427        gpio_free(RX51_ECI_SW_GPIO);
 428err_gpio_eci_sw:
 429        gpio_free(RX51_TVOUT_SEL_GPIO);
 430err_gpio_tvout_sel:
 431
 432        return err;
 433}
 434
 435static void __exit rx51_soc_exit(void)
 436{
 437        snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
 438                                rx51_av_jack_gpios);
 439
 440        platform_device_unregister(rx51_snd_device);
 441        gpio_free(RX51_ECI_SW_GPIO);
 442        gpio_free(RX51_TVOUT_SEL_GPIO);
 443}
 444
 445module_init(rx51_soc_init);
 446module_exit(rx51_soc_exit);
 447
 448MODULE_AUTHOR("Nokia Corporation");
 449MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
 450MODULE_LICENSE("GPL");
 451