linux/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// MediaTek ALSA SoC Audio DAI I2S Control
   4//
   5// Copyright (c) 2018 MediaTek Inc.
   6// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
   7
   8#include <linux/regmap.h>
   9#include <sound/pcm_params.h>
  10#include "mt8183-afe-common.h"
  11#include "mt8183-interconnection.h"
  12#include "mt8183-reg.h"
  13
  14enum AUD_TX_LCH_RPT {
  15        AUD_TX_LCH_RPT_NO_REPEAT = 0,
  16        AUD_TX_LCH_RPT_REPEAT = 1
  17};
  18
  19enum AUD_VBT_16K_MODE {
  20        AUD_VBT_16K_MODE_DISABLE = 0,
  21        AUD_VBT_16K_MODE_ENABLE = 1
  22};
  23
  24enum AUD_EXT_MODEM {
  25        AUD_EXT_MODEM_SELECT_INTERNAL = 0,
  26        AUD_EXT_MODEM_SELECT_EXTERNAL = 1
  27};
  28
  29enum AUD_PCM_SYNC_TYPE {
  30        /* bck sync length = 1 */
  31        AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
  32        /* bck sync length = PCM_INTF_CON1[9:13] */
  33        AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
  34};
  35
  36enum AUD_BT_MODE {
  37        AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
  38        AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
  39};
  40
  41enum AUD_PCM_AFIFO_SRC {
  42        /* slave mode & external modem uses different crystal */
  43        AUD_PCM_AFIFO_ASRC = 0,
  44        /* slave mode & external modem uses the same crystal */
  45        AUD_PCM_AFIFO_AFIFO = 1
  46};
  47
  48enum AUD_PCM_CLOCK_SOURCE {
  49        AUD_PCM_CLOCK_MASTER_MODE = 0,
  50        AUD_PCM_CLOCK_SLAVE_MODE = 1
  51};
  52
  53enum AUD_PCM_WLEN {
  54        AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
  55        AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
  56};
  57
  58enum AUD_PCM_MODE {
  59        AUD_PCM_MODE_PCM_MODE_8K = 0,
  60        AUD_PCM_MODE_PCM_MODE_16K = 1,
  61        AUD_PCM_MODE_PCM_MODE_32K = 2,
  62        AUD_PCM_MODE_PCM_MODE_48K = 3,
  63};
  64
  65enum AUD_PCM_FMT {
  66        AUD_PCM_FMT_I2S = 0,
  67        AUD_PCM_FMT_EIAJ = 1,
  68        AUD_PCM_FMT_PCM_MODE_A = 2,
  69        AUD_PCM_FMT_PCM_MODE_B = 3
  70};
  71
  72enum AUD_BCLK_OUT_INV {
  73        AUD_BCLK_OUT_INV_NO_INVERSE = 0,
  74        AUD_BCLK_OUT_INV_INVERSE = 1
  75};
  76
  77enum AUD_PCM_EN {
  78        AUD_PCM_EN_DISABLE = 0,
  79        AUD_PCM_EN_ENABLE = 1
  80};
  81
  82/* dai component */
  83static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
  84        SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
  85                                    I_ADDA_UL_CH1, 1, 0),
  86        SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
  87                                    I_DL2_CH1, 1, 0),
  88};
  89
  90static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
  91        SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
  92                                    I_ADDA_UL_CH2, 1, 0),
  93        SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
  94                                    I_DL2_CH2, 1, 0),
  95};
  96
  97static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
  98        SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
  99                                    I_DL1_CH1, 1, 0),
 100};
 101
 102static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
 103        SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
 104                                    I_ADDA_UL_CH1, 1, 0),
 105        SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
 106                                    I_DL2_CH1, 1, 0),
 107};
 108
 109static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
 110        SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
 111                                    I_ADDA_UL_CH2, 1, 0),
 112        SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
 113                                    I_DL2_CH2, 1, 0),
 114};
 115
 116static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
 117        SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
 118                                    I_DL1_CH1, 1, 0),
 119};
 120
 121static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
 122        /* inter-connections */
 123        SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
 124                           mtk_pcm_1_playback_ch1_mix,
 125                           ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
 126        SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
 127                           mtk_pcm_1_playback_ch2_mix,
 128                           ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
 129        SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
 130                           mtk_pcm_1_playback_ch4_mix,
 131                           ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
 132        SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
 133                           mtk_pcm_2_playback_ch1_mix,
 134                           ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
 135        SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
 136                           mtk_pcm_2_playback_ch2_mix,
 137                           ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
 138        SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
 139                           mtk_pcm_2_playback_ch4_mix,
 140                           ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
 141
 142        SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0,
 143                            NULL, 0),
 144
 145        SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0,
 146                            NULL, 0),
 147
 148        SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
 149        SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
 150        SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
 151        SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
 152};
 153
 154static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
 155        {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
 156        {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
 157        {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
 158        {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
 159        {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
 160        {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
 161
 162        {"PCM 1 Playback", NULL, "PCM_1_EN"},
 163        {"PCM 2 Playback", NULL, "PCM_2_EN"},
 164        {"PCM 1 Capture", NULL, "PCM_1_EN"},
 165        {"PCM 2 Capture", NULL, "PCM_2_EN"},
 166
 167        {"AFE_TO_MD1", NULL, "PCM 2 Playback"},
 168        {"AFE_TO_MD2", NULL, "PCM 1 Playback"},
 169        {"PCM 2 Capture", NULL, "MD1_TO_AFE"},
 170        {"PCM 1 Capture", NULL, "MD2_TO_AFE"},
 171
 172        {"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
 173        {"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
 174        {"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
 175        {"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
 176        {"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
 177        {"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
 178};
 179
 180/* dai ops */
 181static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
 182                                 struct snd_pcm_hw_params *params,
 183                                 struct snd_soc_dai *dai)
 184{
 185        struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 186        unsigned int rate = params_rate(params);
 187        unsigned int rate_reg = mt8183_rate_transform(afe->dev, rate, dai->id);
 188        unsigned int pcm_con = 0;
 189
 190        dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
 191                __func__,
 192                dai->id,
 193                substream->stream,
 194                rate,
 195                rate_reg,
 196                dai->playback_widget->active,
 197                dai->capture_widget->active);
 198
 199        if (dai->playback_widget->active || dai->capture_widget->active)
 200                return 0;
 201
 202        switch (dai->id) {
 203        case MT8183_DAI_PCM_1:
 204                pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
 205                pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
 206                pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
 207                pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
 208                pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
 209                pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
 210                pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
 211                pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
 212                pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
 213                pcm_con |= rate_reg << PCM_MODE_SFT;
 214                pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
 215
 216                regmap_update_bits(afe->regmap, PCM_INTF_CON1,
 217                                   0xfffffffe, pcm_con);
 218                break;
 219        case MT8183_DAI_PCM_2:
 220                pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
 221                pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
 222                pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
 223                pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
 224                pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
 225                pcm_con |= rate_reg << PCM2_MODE_SFT;
 226                pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
 227
 228                regmap_update_bits(afe->regmap, PCM2_INTF_CON,
 229                                   0xfffffffe, pcm_con);
 230                break;
 231        default:
 232                dev_warn(afe->dev, "%s(), id %d not support\n",
 233                         __func__, dai->id);
 234                return -EINVAL;
 235        }
 236
 237        return 0;
 238}
 239
 240static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
 241        .hw_params = mtk_dai_pcm_hw_params,
 242};
 243
 244/* dai driver */
 245#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
 246                       SNDRV_PCM_RATE_16000 |\
 247                       SNDRV_PCM_RATE_32000 |\
 248                       SNDRV_PCM_RATE_48000)
 249
 250#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
 251                         SNDRV_PCM_FMTBIT_S24_LE |\
 252                         SNDRV_PCM_FMTBIT_S32_LE)
 253
 254static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 255        {
 256                .name = "PCM 1",
 257                .id = MT8183_DAI_PCM_1,
 258                .playback = {
 259                        .stream_name = "PCM 1 Playback",
 260                        .channels_min = 1,
 261                        .channels_max = 2,
 262                        .rates = MTK_PCM_RATES,
 263                        .formats = MTK_PCM_FORMATS,
 264                },
 265                .capture = {
 266                        .stream_name = "PCM 1 Capture",
 267                        .channels_min = 1,
 268                        .channels_max = 2,
 269                        .rates = MTK_PCM_RATES,
 270                        .formats = MTK_PCM_FORMATS,
 271                },
 272                .ops = &mtk_dai_pcm_ops,
 273                .symmetric_rates = 1,
 274                .symmetric_samplebits = 1,
 275        },
 276        {
 277                .name = "PCM 2",
 278                .id = MT8183_DAI_PCM_2,
 279                .playback = {
 280                        .stream_name = "PCM 2 Playback",
 281                        .channels_min = 1,
 282                        .channels_max = 2,
 283                        .rates = MTK_PCM_RATES,
 284                        .formats = MTK_PCM_FORMATS,
 285                },
 286                .capture = {
 287                        .stream_name = "PCM 2 Capture",
 288                        .channels_min = 1,
 289                        .channels_max = 2,
 290                        .rates = MTK_PCM_RATES,
 291                        .formats = MTK_PCM_FORMATS,
 292                },
 293                .ops = &mtk_dai_pcm_ops,
 294                .symmetric_rates = 1,
 295                .symmetric_samplebits = 1,
 296        },
 297};
 298
 299int mt8183_dai_pcm_register(struct mtk_base_afe *afe)
 300{
 301        struct mtk_base_afe_dai *dai;
 302
 303        dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
 304        if (!dai)
 305                return -ENOMEM;
 306
 307        list_add(&dai->list, &afe->sub_dais);
 308
 309        dai->dai_drivers = mtk_dai_pcm_driver;
 310        dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
 311
 312        dai->dapm_widgets = mtk_dai_pcm_widgets;
 313        dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
 314        dai->dapm_routes = mtk_dai_pcm_routes;
 315        dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
 316
 317        return 0;
 318}
 319