linux/sound/soc/qcom/sdm845.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/module.h>
   7#include <linux/platform_device.h>
   8#include <linux/of_device.h>
   9#include <sound/core.h>
  10#include <sound/pcm.h>
  11#include <sound/pcm_params.h>
  12#include <sound/jack.h>
  13#include <sound/soc.h>
  14#include <uapi/linux/input-event-codes.h>
  15#include "common.h"
  16#include "qdsp6/q6afe.h"
  17#include "../codecs/rt5663.h"
  18
  19#define DEFAULT_SAMPLE_RATE_48K         48000
  20#define DEFAULT_MCLK_RATE               24576000
  21#define TDM_BCLK_RATE           6144000
  22#define MI2S_BCLK_RATE          1536000
  23#define LEFT_SPK_TDM_TX_MASK    0x30
  24#define RIGHT_SPK_TDM_TX_MASK   0xC0
  25#define SPK_TDM_RX_MASK         0x03
  26#define NUM_TDM_SLOTS           8
  27
  28struct sdm845_snd_data {
  29        struct snd_soc_jack jack;
  30        bool jack_setup;
  31        struct snd_soc_card *card;
  32        uint32_t pri_mi2s_clk_count;
  33        uint32_t sec_mi2s_clk_count;
  34        uint32_t quat_tdm_clk_count;
  35};
  36
  37static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
  38
  39static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
  40                                        struct snd_pcm_hw_params *params)
  41{
  42        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  43        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  44        int ret = 0, j;
  45        int channels, slot_width;
  46
  47        switch (params_format(params)) {
  48        case SNDRV_PCM_FORMAT_S16_LE:
  49                slot_width = 16;
  50                break;
  51        default:
  52                dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
  53                                __func__, params_format(params));
  54                return -EINVAL;
  55        }
  56
  57        channels = params_channels(params);
  58        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  59                ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
  60                                8, slot_width);
  61                if (ret < 0) {
  62                        dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
  63                                        __func__, ret);
  64                        goto end;
  65                }
  66
  67                ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
  68                                channels, tdm_slot_offset);
  69                if (ret < 0) {
  70                        dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
  71                                        __func__, ret);
  72                        goto end;
  73                }
  74        } else {
  75                ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
  76                                8, slot_width);
  77                if (ret < 0) {
  78                        dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
  79                                        __func__, ret);
  80                        goto end;
  81                }
  82
  83                ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
  84                                tdm_slot_offset, 0, NULL);
  85                if (ret < 0) {
  86                        dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
  87                                        __func__, ret);
  88                        goto end;
  89                }
  90        }
  91
  92        for (j = 0; j < rtd->num_codecs; j++) {
  93                struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
  94
  95                if (!strcmp(codec_dai->component->name_prefix, "Left")) {
  96                        ret = snd_soc_dai_set_tdm_slot(
  97                                        codec_dai, LEFT_SPK_TDM_TX_MASK,
  98                                        SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
  99                                        slot_width);
 100                        if (ret < 0) {
 101                                dev_err(rtd->dev,
 102                                        "DEV0 TDM slot err:%d\n", ret);
 103                                return ret;
 104                        }
 105                }
 106
 107                if (!strcmp(codec_dai->component->name_prefix, "Right")) {
 108                        ret = snd_soc_dai_set_tdm_slot(
 109                                        codec_dai, RIGHT_SPK_TDM_TX_MASK,
 110                                        SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
 111                                        slot_width);
 112                        if (ret < 0) {
 113                                dev_err(rtd->dev,
 114                                        "DEV1 TDM slot err:%d\n", ret);
 115                                return ret;
 116                        }
 117                }
 118        }
 119
 120end:
 121        return ret;
 122}
 123
 124static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
 125                                        struct snd_pcm_hw_params *params)
 126{
 127        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 128        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 129        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 130        int ret = 0;
 131
 132        switch (cpu_dai->id) {
 133        case PRIMARY_MI2S_RX:
 134        case PRIMARY_MI2S_TX:
 135                /*
 136                 * Use ASRC for internal clocks, as PLL rate isn't multiple
 137                 * of BCLK.
 138                 */
 139                rt5663_sel_asrc_clk_src(
 140                        codec_dai->component,
 141                        RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
 142                        RT5663_CLK_SEL_I2S1_ASRC);
 143                ret = snd_soc_dai_set_sysclk(
 144                        codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
 145                        SND_SOC_CLOCK_IN);
 146                if (ret < 0)
 147                        dev_err(rtd->dev,
 148                                "snd_soc_dai_set_sysclk err = %d\n", ret);
 149                break;
 150        case QUATERNARY_TDM_RX_0:
 151        case QUATERNARY_TDM_TX_0:
 152                ret = sdm845_tdm_snd_hw_params(substream, params);
 153                break;
 154        default:
 155                pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
 156                break;
 157        }
 158        return ret;
 159}
 160
 161static void sdm845_jack_free(struct snd_jack *jack)
 162{
 163        struct snd_soc_component *component = jack->private_data;
 164
 165        snd_soc_component_set_jack(component, NULL, NULL);
 166}
 167
 168static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
 169{
 170        struct snd_soc_component *component;
 171        struct snd_soc_card *card = rtd->card;
 172        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 173        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 174        struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
 175        struct snd_jack *jack;
 176        int rval;
 177
 178        if (!pdata->jack_setup) {
 179                rval = snd_soc_card_jack_new(card, "Headset Jack",
 180                                SND_JACK_HEADSET |
 181                                SND_JACK_HEADPHONE |
 182                                SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 183                                SND_JACK_BTN_2 | SND_JACK_BTN_3,
 184                                &pdata->jack, NULL, 0);
 185
 186                if (rval < 0) {
 187                        dev_err(card->dev, "Unable to add Headphone Jack\n");
 188                        return rval;
 189                }
 190
 191                jack = pdata->jack.jack;
 192
 193                snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
 194                snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
 195                snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 196                snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 197                pdata->jack_setup = true;
 198        }
 199
 200        switch (cpu_dai->id) {
 201        case PRIMARY_MI2S_RX:
 202                jack  = pdata->jack.jack;
 203                component = codec_dai->component;
 204
 205                jack->private_data = component;
 206                jack->private_free = sdm845_jack_free;
 207                rval = snd_soc_component_set_jack(component,
 208                                                  &pdata->jack, NULL);
 209                if (rval != 0 && rval != -ENOTSUPP) {
 210                        dev_warn(card->dev, "Failed to set jack: %d\n", rval);
 211                        return rval;
 212                }
 213                break;
 214        default:
 215                break;
 216        }
 217
 218        return 0;
 219}
 220
 221
 222static int sdm845_snd_startup(struct snd_pcm_substream *substream)
 223{
 224        unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
 225        unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
 226        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 227        struct snd_soc_card *card = rtd->card;
 228        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
 229        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 230        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 231        int j;
 232        int ret;
 233
 234        switch (cpu_dai->id) {
 235        case PRIMARY_MI2S_RX:
 236        case PRIMARY_MI2S_TX:
 237                codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
 238                if (++(data->pri_mi2s_clk_count) == 1) {
 239                        snd_soc_dai_set_sysclk(cpu_dai,
 240                                Q6AFE_LPASS_CLK_ID_MCLK_1,
 241                                DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 242                        snd_soc_dai_set_sysclk(cpu_dai,
 243                                Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
 244                                MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 245                }
 246                snd_soc_dai_set_fmt(cpu_dai, fmt);
 247                snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
 248                break;
 249
 250        case SECONDARY_MI2S_TX:
 251                codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
 252                if (++(data->sec_mi2s_clk_count) == 1) {
 253                        snd_soc_dai_set_sysclk(cpu_dai,
 254                                Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
 255                                MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
 256                }
 257                snd_soc_dai_set_fmt(cpu_dai, fmt);
 258                snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
 259                break;
 260
 261        case QUATERNARY_TDM_RX_0:
 262        case QUATERNARY_TDM_TX_0:
 263                if (++(data->quat_tdm_clk_count) == 1) {
 264                        snd_soc_dai_set_sysclk(cpu_dai,
 265                                Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
 266                                TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
 267                }
 268
 269                codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
 270
 271                for (j = 0; j < rtd->num_codecs; j++) {
 272                        codec_dai = rtd->codec_dais[j];
 273
 274                        if (!strcmp(codec_dai->component->name_prefix,
 275                                    "Left")) {
 276                                ret = snd_soc_dai_set_fmt(
 277                                                codec_dai, codec_dai_fmt);
 278                                if (ret < 0) {
 279                                        dev_err(rtd->dev,
 280                                                "Left TDM fmt err:%d\n", ret);
 281                                        return ret;
 282                                }
 283                        }
 284
 285                        if (!strcmp(codec_dai->component->name_prefix,
 286                                    "Right")) {
 287                                ret = snd_soc_dai_set_fmt(
 288                                                codec_dai, codec_dai_fmt);
 289                                if (ret < 0) {
 290                                        dev_err(rtd->dev,
 291                                                "Right TDM slot err:%d\n", ret);
 292                                        return ret;
 293                                }
 294                        }
 295                }
 296                break;
 297
 298        default:
 299                pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
 300                break;
 301        }
 302        return 0;
 303}
 304
 305static void  sdm845_snd_shutdown(struct snd_pcm_substream *substream)
 306{
 307        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 308        struct snd_soc_card *card = rtd->card;
 309        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
 310        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 311
 312        switch (cpu_dai->id) {
 313        case PRIMARY_MI2S_RX:
 314        case PRIMARY_MI2S_TX:
 315                if (--(data->pri_mi2s_clk_count) == 0) {
 316                        snd_soc_dai_set_sysclk(cpu_dai,
 317                                Q6AFE_LPASS_CLK_ID_MCLK_1,
 318                                0, SNDRV_PCM_STREAM_PLAYBACK);
 319                        snd_soc_dai_set_sysclk(cpu_dai,
 320                                Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
 321                                0, SNDRV_PCM_STREAM_PLAYBACK);
 322                };
 323                break;
 324
 325        case SECONDARY_MI2S_TX:
 326                if (--(data->sec_mi2s_clk_count) == 0) {
 327                        snd_soc_dai_set_sysclk(cpu_dai,
 328                                Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
 329                                0, SNDRV_PCM_STREAM_CAPTURE);
 330                }
 331                break;
 332
 333        case QUATERNARY_TDM_RX_0:
 334        case QUATERNARY_TDM_TX_0:
 335                if (--(data->quat_tdm_clk_count) == 0) {
 336                        snd_soc_dai_set_sysclk(cpu_dai,
 337                                Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
 338                                0, SNDRV_PCM_STREAM_PLAYBACK);
 339                }
 340                break;
 341
 342        default:
 343                pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
 344                break;
 345        }
 346}
 347
 348static const struct snd_soc_ops sdm845_be_ops = {
 349        .hw_params = sdm845_snd_hw_params,
 350        .startup = sdm845_snd_startup,
 351        .shutdown = sdm845_snd_shutdown,
 352};
 353
 354static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 355                                struct snd_pcm_hw_params *params)
 356{
 357        struct snd_interval *rate = hw_param_interval(params,
 358                                        SNDRV_PCM_HW_PARAM_RATE);
 359        struct snd_interval *channels = hw_param_interval(params,
 360                                        SNDRV_PCM_HW_PARAM_CHANNELS);
 361        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 362
 363        rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
 364        channels->min = channels->max = 2;
 365        snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 366
 367        return 0;
 368}
 369
 370static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
 371        SND_SOC_DAPM_HP("Headphone Jack", NULL),
 372        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 373        SND_SOC_DAPM_SPK("Left Spk", NULL),
 374        SND_SOC_DAPM_SPK("Right Spk", NULL),
 375        SND_SOC_DAPM_MIC("Int Mic", NULL),
 376};
 377
 378static void sdm845_add_ops(struct snd_soc_card *card)
 379{
 380        struct snd_soc_dai_link *link;
 381        int i;
 382
 383        for_each_card_prelinks(card, i, link) {
 384                if (link->no_pcm == 1) {
 385                        link->ops = &sdm845_be_ops;
 386                        link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
 387                }
 388                link->init = sdm845_dai_init;
 389        }
 390}
 391
 392static int sdm845_snd_platform_probe(struct platform_device *pdev)
 393{
 394        struct snd_soc_card *card;
 395        struct sdm845_snd_data *data;
 396        struct device *dev = &pdev->dev;
 397        int ret;
 398
 399        card = kzalloc(sizeof(*card), GFP_KERNEL);
 400        if (!card)
 401                return -ENOMEM;
 402
 403        /* Allocate the private data */
 404        data = kzalloc(sizeof(*data), GFP_KERNEL);
 405        if (!data) {
 406                ret = -ENOMEM;
 407                goto data_alloc_fail;
 408        }
 409
 410        card->dapm_widgets = sdm845_snd_widgets;
 411        card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
 412        card->dev = dev;
 413        dev_set_drvdata(dev, card);
 414        ret = qcom_snd_parse_of(card);
 415        if (ret) {
 416                dev_err(dev, "Error parsing OF data\n");
 417                goto parse_dt_fail;
 418        }
 419
 420        data->card = card;
 421        snd_soc_card_set_drvdata(card, data);
 422
 423        sdm845_add_ops(card);
 424        ret = snd_soc_register_card(card);
 425        if (ret) {
 426                dev_err(dev, "Sound card registration failed\n");
 427                goto register_card_fail;
 428        }
 429        return ret;
 430
 431register_card_fail:
 432        kfree(card->dai_link);
 433parse_dt_fail:
 434        kfree(data);
 435data_alloc_fail:
 436        kfree(card);
 437        return ret;
 438}
 439
 440static int sdm845_snd_platform_remove(struct platform_device *pdev)
 441{
 442        struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
 443        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
 444
 445        snd_soc_unregister_card(card);
 446        kfree(card->dai_link);
 447        kfree(data);
 448        kfree(card);
 449        return 0;
 450}
 451
 452static const struct of_device_id sdm845_snd_device_id[]  = {
 453        { .compatible = "qcom,sdm845-sndcard" },
 454        {},
 455};
 456MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
 457
 458static struct platform_driver sdm845_snd_driver = {
 459        .probe = sdm845_snd_platform_probe,
 460        .remove = sdm845_snd_platform_remove,
 461        .driver = {
 462                .name = "msm-snd-sdm845",
 463                .of_match_table = sdm845_snd_device_id,
 464        },
 465};
 466module_platform_driver(sdm845_snd_driver);
 467
 468MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
 469MODULE_LICENSE("GPL v2");
 470