linux/sound/soc/intel/boards/sof_realtek_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2//
   3// Copyright(c) 2020 Intel Corporation. All rights reserved.
   4
   5#include <linux/device.h>
   6#include <linux/kernel.h>
   7#include <sound/pcm.h>
   8#include <sound/pcm_params.h>
   9#include <sound/soc.h>
  10#include <sound/soc-acpi.h>
  11#include <sound/soc-dai.h>
  12#include <sound/soc-dapm.h>
  13#include <uapi/sound/asound.h>
  14#include "../../codecs/rt1011.h"
  15#include "sof_realtek_common.h"
  16
  17/*
  18 * Current only 2-amp configuration is supported for rt1011
  19 */
  20static const struct snd_soc_dapm_route rt1011_dapm_routes[] = {
  21        /* speaker */
  22        { "Left Spk", NULL, "Left SPO" },
  23        { "Right Spk", NULL, "Right SPO" },
  24};
  25
  26/*
  27 * Make sure device's Unique ID follows this configuration:
  28 *
  29 * Two speakers:
  30 *         0: left, 1: right
  31 * Four speakers:
  32 *         0: Woofer left, 1: Woofer right
  33 *         2: Tweeter left, 3: Tweeter right
  34 */
  35static struct snd_soc_codec_conf rt1011_codec_confs[] = {
  36        {
  37                .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),
  38                .name_prefix = "Left",
  39        },
  40        {
  41                .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),
  42                .name_prefix = "Right",
  43        },
  44};
  45
  46static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {
  47        {
  48                .name = RT1011_DEV0_NAME,
  49                .dai_name = RT1011_CODEC_DAI,
  50        },
  51        {
  52                .name = RT1011_DEV1_NAME,
  53                .dai_name = RT1011_CODEC_DAI,
  54        },
  55};
  56
  57static const struct {
  58        unsigned int tx;
  59        unsigned int rx;
  60} rt1011_tdm_mask[] = {
  61        {.tx = 0x4, .rx = 0x1},
  62        {.tx = 0x8, .rx = 0x2},
  63};
  64
  65static int rt1011_hw_params(struct snd_pcm_substream *substream,
  66                            struct snd_pcm_hw_params *params)
  67{
  68        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  69        struct snd_soc_dai *codec_dai;
  70        int srate, i, ret = 0;
  71
  72        srate = params_rate(params);
  73
  74        for_each_rtd_codec_dais(rtd, i, codec_dai) {
  75                /* 100 Fs to drive 24 bit data */
  76                ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,
  77                                          100 * srate, 256 * srate);
  78                if (ret < 0) {
  79                        dev_err(codec_dai->dev, "fail to set pll, ret %d\n",
  80                                ret);
  81                        return ret;
  82                }
  83
  84                ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,
  85                                             256 * srate, SND_SOC_CLOCK_IN);
  86                if (ret < 0) {
  87                        dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",
  88                                ret);
  89                        return ret;
  90                }
  91
  92                if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {
  93                        dev_err(codec_dai->dev, "invalid codec index %d\n",
  94                                i);
  95                        return -ENODEV;
  96                }
  97
  98                ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,
  99                                               rt1011_tdm_mask[i].rx, 4,
 100                                               params_width(params));
 101                if (ret < 0) {
 102                        dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
 103                                ret);
 104                        return ret;
 105                }
 106        }
 107
 108        return 0;
 109}
 110
 111static const struct snd_soc_ops rt1011_ops = {
 112        .hw_params = rt1011_hw_params,
 113};
 114
 115static int rt1011_init(struct snd_soc_pcm_runtime *rtd)
 116{
 117        struct snd_soc_card *card = rtd->card;
 118        int ret;
 119
 120        ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_dapm_routes,
 121                                      ARRAY_SIZE(rt1011_dapm_routes));
 122        if (ret)
 123                dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
 124        return ret;
 125}
 126
 127void sof_rt1011_dai_link(struct snd_soc_dai_link *link)
 128{
 129        link->codecs = rt1011_dai_link_components;
 130        link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components);
 131        link->init = rt1011_init;
 132        link->ops = &rt1011_ops;
 133}
 134
 135void sof_rt1011_codec_conf(struct snd_soc_card *card)
 136{
 137        card->codec_conf = rt1011_codec_confs;
 138        card->num_configs = ARRAY_SIZE(rt1011_codec_confs);
 139}
 140
 141/*
 142 * rt1015:  i2c mode driver for ALC1015 and ALC1015Q
 143 * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB
 144 *
 145 * For stereo output, there are always two amplifiers on the board.
 146 * However, the ACPI implements only one device instance (UID=0) if they
 147 * are sharing the same enable pin. The code will detect the number of
 148 * device instance and use corresponding DAPM structures for
 149 * initialization.
 150 */
 151static const struct snd_soc_dapm_route rt1015p_1dev_dapm_routes[] = {
 152        /* speaker */
 153        { "Left Spk", NULL, "Speaker" },
 154        { "Right Spk", NULL, "Speaker" },
 155};
 156
 157static const struct snd_soc_dapm_route rt1015p_2dev_dapm_routes[] = {
 158        /* speaker */
 159        { "Left Spk", NULL, "Left Speaker" },
 160        { "Right Spk", NULL, "Right Speaker" },
 161};
 162
 163static struct snd_soc_codec_conf rt1015p_codec_confs[] = {
 164        {
 165                .dlc = COMP_CODEC_CONF(RT1015P_DEV0_NAME),
 166                .name_prefix = "Left",
 167        },
 168        {
 169                .dlc = COMP_CODEC_CONF(RT1015P_DEV1_NAME),
 170                .name_prefix = "Right",
 171        },
 172};
 173
 174static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = {
 175        {
 176                .name = RT1015P_DEV0_NAME,
 177                .dai_name = RT1015P_CODEC_DAI,
 178        },
 179        {
 180                .name = RT1015P_DEV1_NAME,
 181                .dai_name = RT1015P_CODEC_DAI,
 182        },
 183};
 184
 185static int rt1015p_get_num_codecs(void)
 186{
 187        static int dev_num;
 188
 189        if (dev_num)
 190                return dev_num;
 191
 192        if (!acpi_dev_present("RTL1015", "1", -1))
 193                dev_num = 1;
 194        else
 195                dev_num = 2;
 196
 197        return dev_num;
 198}
 199
 200static int rt1015p_hw_params(struct snd_pcm_substream *substream,
 201                             struct snd_pcm_hw_params *params)
 202{
 203        /* reserved for debugging purpose */
 204
 205        return 0;
 206}
 207
 208static const struct snd_soc_ops rt1015p_ops = {
 209        .hw_params = rt1015p_hw_params,
 210};
 211
 212static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)
 213{
 214        struct snd_soc_card *card = rtd->card;
 215        int ret;
 216
 217        if (rt1015p_get_num_codecs() == 1)
 218                ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_1dev_dapm_routes,
 219                                              ARRAY_SIZE(rt1015p_1dev_dapm_routes));
 220        else
 221                ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_2dev_dapm_routes,
 222                                              ARRAY_SIZE(rt1015p_2dev_dapm_routes));
 223        if (ret)
 224                dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
 225        return ret;
 226}
 227
 228void sof_rt1015p_dai_link(struct snd_soc_dai_link *link)
 229{
 230        link->codecs = rt1015p_dai_link_components;
 231        link->num_codecs = rt1015p_get_num_codecs();
 232        link->init = rt1015p_init;
 233        link->ops = &rt1015p_ops;
 234}
 235
 236void sof_rt1015p_codec_conf(struct snd_soc_card *card)
 237{
 238        if (rt1015p_get_num_codecs() == 1)
 239                return;
 240
 241        card->codec_conf = rt1015p_codec_confs;
 242        card->num_configs = ARRAY_SIZE(rt1015p_codec_confs);
 243}
 244