linux/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * MediaTek ALSA SoC Audio DAI PCM I/F Control
   4 *
   5 * Copyright (c) 2020 MediaTek Inc.
   6 * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
   7 *         Trevor Wu <trevor.wu@mediatek.com>
   8 */
   9
  10#include <linux/regmap.h>
  11#include <sound/pcm_params.h>
  12#include "mt8195-afe-clk.h"
  13#include "mt8195-afe-common.h"
  14#include "mt8195-reg.h"
  15
  16enum {
  17        MTK_DAI_PCM_FMT_I2S,
  18        MTK_DAI_PCM_FMT_EIAJ,
  19        MTK_DAI_PCM_FMT_MODEA,
  20        MTK_DAI_PCM_FMT_MODEB,
  21};
  22
  23enum {
  24        MTK_DAI_PCM_CLK_A1SYS,
  25        MTK_DAI_PCM_CLK_A2SYS,
  26        MTK_DAI_PCM_CLK_26M_48K,
  27        MTK_DAI_PCM_CLK_26M_441K,
  28};
  29
  30struct mtk_dai_pcm_rate {
  31        unsigned int rate;
  32        unsigned int reg_value;
  33};
  34
  35struct mtk_dai_pcmif_priv {
  36        unsigned int slave_mode;
  37        unsigned int lrck_inv;
  38        unsigned int bck_inv;
  39        unsigned int format;
  40};
  41
  42static const struct mtk_dai_pcm_rate mtk_dai_pcm_rates[] = {
  43        { .rate = 8000, .reg_value = 0, },
  44        { .rate = 16000, .reg_value = 1, },
  45        { .rate = 32000, .reg_value = 2, },
  46        { .rate = 48000, .reg_value = 3, },
  47        { .rate = 11025, .reg_value = 1, },
  48        { .rate = 22050, .reg_value = 2, },
  49        { .rate = 44100, .reg_value = 3, },
  50};
  51
  52static int mtk_dai_pcm_mode(unsigned int rate)
  53{
  54        int i;
  55
  56        for (i = 0; i < ARRAY_SIZE(mtk_dai_pcm_rates); i++)
  57                if (mtk_dai_pcm_rates[i].rate == rate)
  58                        return mtk_dai_pcm_rates[i].reg_value;
  59
  60        return -EINVAL;
  61}
  62
  63static const struct snd_kcontrol_new mtk_dai_pcm_o000_mix[] = {
  64        SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN0, 0, 1, 0),
  65        SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN0_2, 6, 1, 0),
  66};
  67
  68static const struct snd_kcontrol_new mtk_dai_pcm_o001_mix[] = {
  69        SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN1, 1, 1, 0),
  70        SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN1_2, 7, 1, 0),
  71};
  72
  73static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
  74        SND_SOC_DAPM_MIXER("I002", SND_SOC_NOPM, 0, 0, NULL, 0),
  75        SND_SOC_DAPM_MIXER("I003", SND_SOC_NOPM, 0, 0, NULL, 0),
  76        SND_SOC_DAPM_MIXER("O000", SND_SOC_NOPM, 0, 0,
  77                           mtk_dai_pcm_o000_mix,
  78                           ARRAY_SIZE(mtk_dai_pcm_o000_mix)),
  79        SND_SOC_DAPM_MIXER("O001", SND_SOC_NOPM, 0, 0,
  80                           mtk_dai_pcm_o001_mix,
  81                           ARRAY_SIZE(mtk_dai_pcm_o001_mix)),
  82
  83        SND_SOC_DAPM_INPUT("PCM1_INPUT"),
  84        SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"),
  85};
  86
  87static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
  88        {"I002", NULL, "PCM1 Capture"},
  89        {"I003", NULL, "PCM1 Capture"},
  90
  91        {"O000", "I000 Switch", "I000"},
  92        {"O001", "I001 Switch", "I001"},
  93
  94        {"O000", "I070 Switch", "I070"},
  95        {"O001", "I071 Switch", "I071"},
  96
  97        {"PCM1 Playback", NULL, "O000"},
  98        {"PCM1 Playback", NULL, "O001"},
  99
 100        {"PCM1_OUTPUT", NULL, "PCM1 Playback"},
 101        {"PCM1 Capture", NULL, "PCM1_INPUT"},
 102};
 103
 104static void mtk_dai_pcm_enable(struct mtk_base_afe *afe)
 105{
 106        regmap_update_bits(afe->regmap, PCM_INTF_CON1,
 107                           PCM_INTF_CON1_PCM_EN, PCM_INTF_CON1_PCM_EN);
 108}
 109
 110static void mtk_dai_pcm_disable(struct mtk_base_afe *afe)
 111{
 112        regmap_update_bits(afe->regmap, PCM_INTF_CON1,
 113                           PCM_INTF_CON1_PCM_EN, 0x0);
 114}
 115
 116static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,
 117                                 struct snd_soc_dai *dai)
 118{
 119        struct snd_pcm_runtime * const runtime = substream->runtime;
 120        struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 121        struct mt8195_afe_private *afe_priv = afe->platform_priv;
 122        struct mtk_dai_pcmif_priv *pcmif_priv = afe_priv->dai_priv[dai->id];
 123        unsigned int slave_mode = pcmif_priv->slave_mode;
 124        unsigned int lrck_inv = pcmif_priv->lrck_inv;
 125        unsigned int bck_inv = pcmif_priv->bck_inv;
 126        unsigned int fmt = pcmif_priv->format;
 127        unsigned int bit_width = dai->sample_bits;
 128        unsigned int val = 0;
 129        unsigned int mask = 0;
 130        int fs = 0;
 131        int mode = 0;
 132
 133        /* sync freq mode */
 134        fs = mt8195_afe_fs_timing(runtime->rate);
 135        if (fs < 0)
 136                return -EINVAL;
 137        val |= PCM_INTF_CON2_SYNC_FREQ_MODE(fs);
 138        mask |= PCM_INTF_CON2_SYNC_FREQ_MODE_MASK;
 139
 140        /* clk domain sel */
 141        if (runtime->rate % 8000)
 142                val |= PCM_INTF_CON2_CLK_DOMAIN_SEL(MTK_DAI_PCM_CLK_26M_441K);
 143        else
 144                val |= PCM_INTF_CON2_CLK_DOMAIN_SEL(MTK_DAI_PCM_CLK_26M_48K);
 145        mask |= PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK;
 146
 147        regmap_update_bits(afe->regmap, PCM_INTF_CON2, mask, val);
 148
 149        val = 0;
 150        mask = 0;
 151
 152        /* pcm mode */
 153        mode = mtk_dai_pcm_mode(runtime->rate);
 154        if (mode < 0)
 155                return -EINVAL;
 156        val |= PCM_INTF_CON1_PCM_MODE(mode);
 157        mask |= PCM_INTF_CON1_PCM_MODE_MASK;
 158
 159        /* pcm format */
 160        val |= PCM_INTF_CON1_PCM_FMT(fmt);
 161        mask |= PCM_INTF_CON1_PCM_FMT_MASK;
 162
 163        /* pcm sync length */
 164        if (fmt == MTK_DAI_PCM_FMT_MODEA ||
 165            fmt == MTK_DAI_PCM_FMT_MODEB)
 166                val |= PCM_INTF_CON1_SYNC_LENGTH(1);
 167        else
 168                val |= PCM_INTF_CON1_SYNC_LENGTH(bit_width);
 169        mask |= PCM_INTF_CON1_SYNC_LENGTH_MASK;
 170
 171        /* pcm bits, word length */
 172        if (bit_width > 16) {
 173                val |= PCM_INTF_CON1_PCM_24BIT;
 174                val |= PCM_INTF_CON1_PCM_WLEN_64BCK;
 175        } else {
 176                val |= PCM_INTF_CON1_PCM_16BIT;
 177                val |= PCM_INTF_CON1_PCM_WLEN_32BCK;
 178        }
 179        mask |= PCM_INTF_CON1_PCM_BIT_MASK;
 180        mask |= PCM_INTF_CON1_PCM_WLEN_MASK;
 181
 182        /* master/slave */
 183        if (!slave_mode) {
 184                val |= PCM_INTF_CON1_PCM_MASTER;
 185
 186                if (lrck_inv)
 187                        val |= PCM_INTF_CON1_SYNC_OUT_INV;
 188                if (bck_inv)
 189                        val |= PCM_INTF_CON1_BCLK_OUT_INV;
 190                mask |= PCM_INTF_CON1_CLK_OUT_INV_MASK;
 191        } else {
 192                val |= PCM_INTF_CON1_PCM_SLAVE;
 193
 194                if (lrck_inv)
 195                        val |= PCM_INTF_CON1_SYNC_IN_INV;
 196                if (bck_inv)
 197                        val |= PCM_INTF_CON1_BCLK_IN_INV;
 198                mask |= PCM_INTF_CON1_CLK_IN_INV_MASK;
 199
 200                /* TODO: add asrc setting for slave mode */
 201        }
 202        mask |= PCM_INTF_CON1_PCM_M_S_MASK;
 203
 204        regmap_update_bits(afe->regmap, PCM_INTF_CON1, mask, val);
 205
 206        return 0;
 207}
 208
 209/* dai ops */
 210static int mtk_dai_pcm_startup(struct snd_pcm_substream *substream,
 211                               struct snd_soc_dai *dai)
 212{
 213        struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 214        struct mt8195_afe_private *afe_priv = afe->platform_priv;
 215
 216        if (dai->component->active)
 217                return 0;
 218
 219        mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC11]);
 220        mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC12]);
 221        mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_PCMIF]);
 222
 223        return 0;
 224}
 225
 226static void mtk_dai_pcm_shutdown(struct snd_pcm_substream *substream,
 227                                 struct snd_soc_dai *dai)
 228{
 229        struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 230        struct mt8195_afe_private *afe_priv = afe->platform_priv;
 231
 232        if (dai->component->active)
 233                return;
 234
 235        mtk_dai_pcm_disable(afe);
 236
 237        mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_PCMIF]);
 238        mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC12]);
 239        mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC11]);
 240}
 241
 242static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream,
 243                               struct snd_soc_dai *dai)
 244{
 245        struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 246        int ret = 0;
 247
 248        if (snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) &&
 249            snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE))
 250                return 0;
 251
 252        ret = mtk_dai_pcm_configure(substream, dai);
 253        if (ret)
 254                return ret;
 255
 256        mtk_dai_pcm_enable(afe);
 257
 258        return 0;
 259}
 260
 261static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 262{
 263        struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 264        struct mt8195_afe_private *afe_priv = afe->platform_priv;
 265        struct mtk_dai_pcmif_priv *pcmif_priv = afe_priv->dai_priv[dai->id];
 266
 267        dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt);
 268
 269        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 270        case SND_SOC_DAIFMT_I2S:
 271                pcmif_priv->format = MTK_DAI_PCM_FMT_I2S;
 272                break;
 273        case SND_SOC_DAIFMT_DSP_A:
 274                pcmif_priv->format = MTK_DAI_PCM_FMT_MODEA;
 275                break;
 276        case SND_SOC_DAIFMT_DSP_B:
 277                pcmif_priv->format = MTK_DAI_PCM_FMT_MODEB;
 278                break;
 279        default:
 280                return -EINVAL;
 281        }
 282
 283        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 284        case SND_SOC_DAIFMT_NB_NF:
 285                pcmif_priv->bck_inv = 0;
 286                pcmif_priv->lrck_inv = 0;
 287                break;
 288        case SND_SOC_DAIFMT_NB_IF:
 289                pcmif_priv->bck_inv = 0;
 290                pcmif_priv->lrck_inv = 1;
 291                break;
 292        case SND_SOC_DAIFMT_IB_NF:
 293                pcmif_priv->bck_inv = 1;
 294                pcmif_priv->lrck_inv = 0;
 295                break;
 296        case SND_SOC_DAIFMT_IB_IF:
 297                pcmif_priv->bck_inv = 1;
 298                pcmif_priv->lrck_inv = 1;
 299                break;
 300        default:
 301                return -EINVAL;
 302        }
 303
 304        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 305        case SND_SOC_DAIFMT_CBM_CFM:
 306                pcmif_priv->slave_mode = 1;
 307                break;
 308        case SND_SOC_DAIFMT_CBS_CFS:
 309                pcmif_priv->slave_mode = 0;
 310                break;
 311        default:
 312                return -EINVAL;
 313        }
 314
 315        return 0;
 316}
 317
 318static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
 319        .startup        = mtk_dai_pcm_startup,
 320        .shutdown       = mtk_dai_pcm_shutdown,
 321        .prepare        = mtk_dai_pcm_prepare,
 322        .set_fmt        = mtk_dai_pcm_set_fmt,
 323};
 324
 325/* dai driver */
 326#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000)
 327
 328#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
 329                         SNDRV_PCM_FMTBIT_S24_LE |\
 330                         SNDRV_PCM_FMTBIT_S32_LE)
 331
 332static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 333        {
 334                .name = "PCM1",
 335                .id = MT8195_AFE_IO_PCM,
 336                .playback = {
 337                        .stream_name = "PCM1 Playback",
 338                        .channels_min = 1,
 339                        .channels_max = 2,
 340                        .rates = MTK_PCM_RATES,
 341                        .formats = MTK_PCM_FORMATS,
 342                },
 343                .capture = {
 344                        .stream_name = "PCM1 Capture",
 345                        .channels_min = 1,
 346                        .channels_max = 2,
 347                        .rates = MTK_PCM_RATES,
 348                        .formats = MTK_PCM_FORMATS,
 349                },
 350                .ops = &mtk_dai_pcm_ops,
 351                .symmetric_rate = 1,
 352                .symmetric_sample_bits = 1,
 353        },
 354};
 355
 356static int init_pcmif_priv_data(struct mtk_base_afe *afe)
 357{
 358        struct mt8195_afe_private *afe_priv = afe->platform_priv;
 359        struct mtk_dai_pcmif_priv *pcmif_priv;
 360
 361        pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_pcmif_priv),
 362                                  GFP_KERNEL);
 363        if (!pcmif_priv)
 364                return -ENOMEM;
 365
 366        afe_priv->dai_priv[MT8195_AFE_IO_PCM] = pcmif_priv;
 367        return 0;
 368}
 369
 370int mt8195_dai_pcm_register(struct mtk_base_afe *afe)
 371{
 372        struct mtk_base_afe_dai *dai;
 373
 374        dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
 375        if (!dai)
 376                return -ENOMEM;
 377
 378        list_add(&dai->list, &afe->sub_dais);
 379
 380        dai->dai_drivers = mtk_dai_pcm_driver;
 381        dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
 382
 383        dai->dapm_widgets = mtk_dai_pcm_widgets;
 384        dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
 385        dai->dapm_routes = mtk_dai_pcm_routes;
 386        dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
 387
 388        return init_pcmif_priv_data(afe);
 389}
 390