linux/sound/soc/ux500/mop500_ab8500.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) ST-Ericsson SA 2012
   3 *
   4 * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
   5 *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
   6 *         for ST-Ericsson.
   7 *
   8 * License terms:
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as published
  12 * by the Free Software Foundation.
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/device.h>
  17#include <linux/io.h>
  18#include <linux/clk.h>
  19#include <linux/mutex.h>
  20
  21#include <sound/soc.h>
  22#include <sound/soc-dapm.h>
  23#include <sound/pcm.h>
  24#include <sound/pcm_params.h>
  25
  26#include "ux500_pcm.h"
  27#include "ux500_msp_dai.h"
  28#include "mop500_ab8500.h"
  29#include "../codecs/ab8500-codec.h"
  30
  31#define TX_SLOT_MONO    0x0008
  32#define TX_SLOT_STEREO  0x000a
  33#define RX_SLOT_MONO    0x0001
  34#define RX_SLOT_STEREO  0x0003
  35#define TX_SLOT_8CH     0x00FF
  36#define RX_SLOT_8CH     0x00FF
  37
  38#define DEF_TX_SLOTS    TX_SLOT_STEREO
  39#define DEF_RX_SLOTS    RX_SLOT_MONO
  40
  41#define DRIVERMODE_NORMAL       0
  42#define DRIVERMODE_CODEC_ONLY   1
  43
  44/* Slot configuration */
  45static unsigned int tx_slots = DEF_TX_SLOTS;
  46static unsigned int rx_slots = DEF_RX_SLOTS;
  47
  48/* Configuration consistency parameters */
  49static DEFINE_MUTEX(mop500_ab8500_params_lock);
  50static unsigned long mop500_ab8500_usage;
  51static int mop500_ab8500_rate;
  52static int mop500_ab8500_channels;
  53
  54/* Clocks */
  55static const char * const enum_mclk[] = {
  56        "SYSCLK",
  57        "ULPCLK"
  58};
  59enum mclk {
  60        MCLK_SYSCLK,
  61        MCLK_ULPCLK,
  62};
  63
  64static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
  65
  66/* Private data for machine-part MOP500<->AB8500 */
  67struct mop500_ab8500_drvdata {
  68        /* Clocks */
  69        enum mclk mclk_sel;
  70        struct clk *clk_ptr_intclk;
  71        struct clk *clk_ptr_sysclk;
  72        struct clk *clk_ptr_ulpclk;
  73};
  74
  75static inline const char *get_mclk_str(enum mclk mclk_sel)
  76{
  77        switch (mclk_sel) {
  78        case MCLK_SYSCLK:
  79                return "SYSCLK";
  80        case MCLK_ULPCLK:
  81                return "ULPCLK";
  82        default:
  83                return "Unknown";
  84        }
  85}
  86
  87static int mop500_ab8500_set_mclk(struct device *dev,
  88                                struct mop500_ab8500_drvdata *drvdata)
  89{
  90        int status;
  91        struct clk *clk_ptr;
  92
  93        if (IS_ERR(drvdata->clk_ptr_intclk)) {
  94                dev_err(dev,
  95                        "%s: ERROR: intclk not initialized!\n", __func__);
  96                return -EIO;
  97        }
  98
  99        switch (drvdata->mclk_sel) {
 100        case MCLK_SYSCLK:
 101                clk_ptr = drvdata->clk_ptr_sysclk;
 102                break;
 103        case MCLK_ULPCLK:
 104                clk_ptr = drvdata->clk_ptr_ulpclk;
 105                break;
 106        default:
 107                return -EINVAL;
 108        }
 109
 110        if (IS_ERR(clk_ptr)) {
 111                dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
 112                        get_mclk_str(drvdata->mclk_sel));
 113                return -EIO;
 114        }
 115
 116        status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
 117        if (status)
 118                dev_err(dev,
 119                        "%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
 120                        __func__, get_mclk_str(drvdata->mclk_sel), status);
 121        else
 122                dev_dbg(dev,
 123                        "%s: intclk parent changed to %s.\n",
 124                        __func__, get_mclk_str(drvdata->mclk_sel));
 125
 126        return status;
 127}
 128
 129/*
 130 * Control-events
 131 */
 132
 133static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
 134                                struct snd_ctl_elem_value *ucontrol)
 135{
 136        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 137        struct mop500_ab8500_drvdata *drvdata =
 138                                snd_soc_card_get_drvdata(card);
 139
 140        ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
 141
 142        return 0;
 143}
 144
 145static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
 146                                struct snd_ctl_elem_value *ucontrol)
 147{
 148        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 149        struct mop500_ab8500_drvdata *drvdata =
 150                                snd_soc_card_get_drvdata(card);
 151        unsigned int val = ucontrol->value.enumerated.item[0];
 152
 153        if (val > (unsigned int)MCLK_ULPCLK)
 154                return -EINVAL;
 155        if (drvdata->mclk_sel == val)
 156                return 0;
 157
 158        drvdata->mclk_sel = val;
 159
 160        return 1;
 161}
 162
 163/*
 164 * Controls
 165 */
 166
 167static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
 168        SOC_ENUM_EXT("Master Clock Select",
 169                soc_enum_mclk,
 170                mclk_input_control_get, mclk_input_control_put),
 171        SOC_DAPM_PIN_SWITCH("Headset Left"),
 172        SOC_DAPM_PIN_SWITCH("Headset Right"),
 173        SOC_DAPM_PIN_SWITCH("Earpiece"),
 174        SOC_DAPM_PIN_SWITCH("Speaker Left"),
 175        SOC_DAPM_PIN_SWITCH("Speaker Right"),
 176        SOC_DAPM_PIN_SWITCH("LineOut Left"),
 177        SOC_DAPM_PIN_SWITCH("LineOut Right"),
 178        SOC_DAPM_PIN_SWITCH("Vibra 1"),
 179        SOC_DAPM_PIN_SWITCH("Vibra 2"),
 180        SOC_DAPM_PIN_SWITCH("Mic 1"),
 181        SOC_DAPM_PIN_SWITCH("Mic 2"),
 182        SOC_DAPM_PIN_SWITCH("LineIn Left"),
 183        SOC_DAPM_PIN_SWITCH("LineIn Right"),
 184        SOC_DAPM_PIN_SWITCH("DMic 1"),
 185        SOC_DAPM_PIN_SWITCH("DMic 2"),
 186        SOC_DAPM_PIN_SWITCH("DMic 3"),
 187        SOC_DAPM_PIN_SWITCH("DMic 4"),
 188        SOC_DAPM_PIN_SWITCH("DMic 5"),
 189        SOC_DAPM_PIN_SWITCH("DMic 6"),
 190};
 191
 192/* ASoC */
 193
 194static int mop500_ab8500_startup(struct snd_pcm_substream *substream)
 195{
 196        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 197
 198        /* Set audio-clock source */
 199        return mop500_ab8500_set_mclk(rtd->card->dev,
 200                                snd_soc_card_get_drvdata(rtd->card));
 201}
 202
 203static void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
 204{
 205        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 206        struct device *dev = rtd->card->dev;
 207
 208        dev_dbg(dev, "%s: Enter\n", __func__);
 209
 210        /* Reset slots configuration to default(s) */
 211        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 212                tx_slots = DEF_TX_SLOTS;
 213        else
 214                rx_slots = DEF_RX_SLOTS;
 215}
 216
 217static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
 218                        struct snd_pcm_hw_params *params)
 219{
 220        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 221        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 222        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 223        struct device *dev = rtd->card->dev;
 224        unsigned int fmt;
 225        int channels, ret = 0, driver_mode, slots;
 226        unsigned int sw_codec, sw_cpu;
 227        bool is_playback;
 228
 229        dev_dbg(dev, "%s: Enter\n", __func__);
 230
 231        dev_dbg(dev, "%s: substream->pcm->name = %s\n"
 232                "substream->pcm->id = %s.\n"
 233                "substream->name = %s.\n"
 234                "substream->number = %d.\n",
 235                __func__,
 236                substream->pcm->name,
 237                substream->pcm->id,
 238                substream->name,
 239                substream->number);
 240
 241        /* Ensure configuration consistency between DAIs */
 242        mutex_lock(&mop500_ab8500_params_lock);
 243        if (mop500_ab8500_usage) {
 244                if (mop500_ab8500_rate != params_rate(params) ||
 245                    mop500_ab8500_channels != params_channels(params)) {
 246                        mutex_unlock(&mop500_ab8500_params_lock);
 247                        return -EBUSY;
 248                }
 249        } else {
 250                mop500_ab8500_rate = params_rate(params);
 251                mop500_ab8500_channels = params_channels(params);
 252        }
 253        __set_bit(cpu_dai->id, &mop500_ab8500_usage);
 254        mutex_unlock(&mop500_ab8500_params_lock);
 255
 256        channels = params_channels(params);
 257
 258        switch (params_format(params)) {
 259        case SNDRV_PCM_FORMAT_S32_LE:
 260                sw_cpu = 32;
 261                break;
 262
 263        case SNDRV_PCM_FORMAT_S16_LE:
 264                sw_cpu = 16;
 265                break;
 266
 267        default:
 268                return -EINVAL;
 269        }
 270
 271        /* Setup codec depending on driver-mode */
 272        if (channels == 8)
 273                driver_mode = DRIVERMODE_CODEC_ONLY;
 274        else
 275                driver_mode = DRIVERMODE_NORMAL;
 276        dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
 277                (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
 278
 279        /* Setup format */
 280
 281        if (driver_mode == DRIVERMODE_NORMAL) {
 282                fmt = SND_SOC_DAIFMT_DSP_A |
 283                        SND_SOC_DAIFMT_CBM_CFM |
 284                        SND_SOC_DAIFMT_NB_NF |
 285                        SND_SOC_DAIFMT_CONT;
 286        } else {
 287                fmt = SND_SOC_DAIFMT_DSP_A |
 288                        SND_SOC_DAIFMT_CBM_CFM |
 289                        SND_SOC_DAIFMT_NB_NF |
 290                        SND_SOC_DAIFMT_GATED;
 291        }
 292
 293        ret = snd_soc_runtime_set_dai_fmt(rtd, fmt);
 294        if (ret)
 295                return ret;
 296
 297        /* Setup TDM-slots */
 298
 299        is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 300        switch (channels) {
 301        case 1:
 302                slots = 16;
 303                tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
 304                rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
 305                break;
 306        case 2:
 307                slots = 16;
 308                tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
 309                rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
 310                break;
 311        case 8:
 312                slots = 16;
 313                tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
 314                rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
 315                break;
 316        default:
 317                return -EINVAL;
 318        }
 319
 320        if (driver_mode == DRIVERMODE_NORMAL)
 321                sw_codec = sw_cpu;
 322        else
 323                sw_codec = 20;
 324
 325        dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
 326                tx_slots, rx_slots);
 327        ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
 328                                sw_cpu);
 329        if (ret)
 330                return ret;
 331
 332        dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
 333                tx_slots, rx_slots);
 334        ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
 335                                sw_codec);
 336        if (ret)
 337                return ret;
 338
 339        return 0;
 340}
 341
 342static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream)
 343{
 344        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 345        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 346
 347        mutex_lock(&mop500_ab8500_params_lock);
 348        __clear_bit(cpu_dai->id, &mop500_ab8500_usage);
 349        mutex_unlock(&mop500_ab8500_params_lock);
 350
 351        return 0;
 352}
 353
 354struct snd_soc_ops mop500_ab8500_ops[] = {
 355        {
 356                .hw_params = mop500_ab8500_hw_params,
 357                .hw_free = mop500_ab8500_hw_free,
 358                .startup = mop500_ab8500_startup,
 359                .shutdown = mop500_ab8500_shutdown,
 360        }
 361};
 362
 363int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
 364{
 365        struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 366        struct device *dev = rtd->card->dev;
 367        struct mop500_ab8500_drvdata *drvdata;
 368        int ret;
 369
 370        dev_dbg(dev, "%s Enter.\n", __func__);
 371
 372        /* Create driver private-data struct */
 373        drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
 374                        GFP_KERNEL);
 375
 376        if (!drvdata)
 377                return -ENOMEM;
 378
 379        snd_soc_card_set_drvdata(rtd->card, drvdata);
 380
 381        /* Setup clocks */
 382
 383        drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
 384        if (IS_ERR(drvdata->clk_ptr_sysclk))
 385                dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
 386                        __func__);
 387        drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
 388        if (IS_ERR(drvdata->clk_ptr_ulpclk))
 389                dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
 390                        __func__);
 391        drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
 392        if (IS_ERR(drvdata->clk_ptr_intclk))
 393                dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
 394                        __func__);
 395
 396        /* Set intclk default parent to ulpclk */
 397        drvdata->mclk_sel = MCLK_ULPCLK;
 398        ret = mop500_ab8500_set_mclk(dev, drvdata);
 399        if (ret < 0)
 400                dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
 401                        __func__);
 402
 403        drvdata->mclk_sel = MCLK_ULPCLK;
 404
 405        /* Add controls */
 406        ret = snd_soc_add_card_controls(rtd->card, mop500_ab8500_ctrls,
 407                        ARRAY_SIZE(mop500_ab8500_ctrls));
 408        if (ret < 0) {
 409                pr_err("%s: Failed to add machine-controls (%d)!\n",
 410                                __func__, ret);
 411                return ret;
 412        }
 413
 414        ret = snd_soc_dapm_disable_pin(dapm, "Earpiece");
 415        ret |= snd_soc_dapm_disable_pin(dapm, "Speaker Left");
 416        ret |= snd_soc_dapm_disable_pin(dapm, "Speaker Right");
 417        ret |= snd_soc_dapm_disable_pin(dapm, "LineOut Left");
 418        ret |= snd_soc_dapm_disable_pin(dapm, "LineOut Right");
 419        ret |= snd_soc_dapm_disable_pin(dapm, "Vibra 1");
 420        ret |= snd_soc_dapm_disable_pin(dapm, "Vibra 2");
 421        ret |= snd_soc_dapm_disable_pin(dapm, "Mic 1");
 422        ret |= snd_soc_dapm_disable_pin(dapm, "Mic 2");
 423        ret |= snd_soc_dapm_disable_pin(dapm, "LineIn Left");
 424        ret |= snd_soc_dapm_disable_pin(dapm, "LineIn Right");
 425        ret |= snd_soc_dapm_disable_pin(dapm, "DMic 1");
 426        ret |= snd_soc_dapm_disable_pin(dapm, "DMic 2");
 427        ret |= snd_soc_dapm_disable_pin(dapm, "DMic 3");
 428        ret |= snd_soc_dapm_disable_pin(dapm, "DMic 4");
 429        ret |= snd_soc_dapm_disable_pin(dapm, "DMic 5");
 430        ret |= snd_soc_dapm_disable_pin(dapm, "DMic 6");
 431
 432        return ret;
 433}
 434
 435void mop500_ab8500_remove(struct snd_soc_card *card)
 436{
 437        struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
 438
 439        if (drvdata->clk_ptr_sysclk != NULL)
 440                clk_put(drvdata->clk_ptr_sysclk);
 441        if (drvdata->clk_ptr_ulpclk != NULL)
 442                clk_put(drvdata->clk_ptr_ulpclk);
 443        if (drvdata->clk_ptr_intclk != NULL)
 444                clk_put(drvdata->clk_ptr_intclk);
 445
 446        snd_soc_card_set_drvdata(card, drvdata);
 447}
 448