Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // Copyright(c) 2020 Intel Corporation. All rights reserved.
0004 
0005 #include <linux/device.h>
0006 #include <linux/kernel.h>
0007 #include <sound/pcm.h>
0008 #include <sound/pcm_params.h>
0009 #include <sound/soc.h>
0010 #include <sound/soc-acpi.h>
0011 #include <sound/soc-dai.h>
0012 #include <sound/soc-dapm.h>
0013 #include <sound/sof.h>
0014 #include <uapi/sound/asound.h>
0015 #include "../../codecs/rt1011.h"
0016 #include "../../codecs/rt1015.h"
0017 #include "../../codecs/rt1308.h"
0018 #include "sof_realtek_common.h"
0019 
0020 /*
0021  * Current only 2-amp configuration is supported for rt1011
0022  */
0023 static const struct snd_soc_dapm_route speaker_map_lr[] = {
0024     /* speaker */
0025     { "Left Spk", NULL, "Left SPO" },
0026     { "Right Spk", NULL, "Right SPO" },
0027 };
0028 
0029 /*
0030  * Make sure device's Unique ID follows this configuration:
0031  *
0032  * Two speakers:
0033  *         0: left, 1: right
0034  * Four speakers:
0035  *         0: Woofer left, 1: Woofer right
0036  *         2: Tweeter left, 3: Tweeter right
0037  */
0038 static struct snd_soc_codec_conf rt1011_codec_confs[] = {
0039     {
0040         .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),
0041         .name_prefix = "Left",
0042     },
0043     {
0044         .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),
0045         .name_prefix = "Right",
0046     },
0047 };
0048 
0049 static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {
0050     {
0051         .name = RT1011_DEV0_NAME,
0052         .dai_name = RT1011_CODEC_DAI,
0053     },
0054     {
0055         .name = RT1011_DEV1_NAME,
0056         .dai_name = RT1011_CODEC_DAI,
0057     },
0058 };
0059 
0060 static const struct {
0061     unsigned int tx;
0062     unsigned int rx;
0063 } rt1011_tdm_mask[] = {
0064     {.tx = 0x4, .rx = 0x1},
0065     {.tx = 0x8, .rx = 0x2},
0066 };
0067 
0068 static int rt1011_hw_params(struct snd_pcm_substream *substream,
0069                 struct snd_pcm_hw_params *params)
0070 {
0071     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0072     struct snd_soc_dai *codec_dai;
0073     int srate, i, ret = 0;
0074 
0075     srate = params_rate(params);
0076 
0077     for_each_rtd_codec_dais(rtd, i, codec_dai) {
0078         /* 100 Fs to drive 24 bit data */
0079         ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,
0080                       100 * srate, 256 * srate);
0081         if (ret < 0) {
0082             dev_err(codec_dai->dev, "fail to set pll, ret %d\n",
0083                 ret);
0084             return ret;
0085         }
0086 
0087         ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,
0088                          256 * srate, SND_SOC_CLOCK_IN);
0089         if (ret < 0) {
0090             dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",
0091                 ret);
0092             return ret;
0093         }
0094 
0095         if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {
0096             dev_err(codec_dai->dev, "invalid codec index %d\n",
0097                 i);
0098             return -ENODEV;
0099         }
0100 
0101         ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,
0102                            rt1011_tdm_mask[i].rx, 4,
0103                            params_width(params));
0104         if (ret < 0) {
0105             dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
0106                 ret);
0107             return ret;
0108         }
0109     }
0110 
0111     return 0;
0112 }
0113 
0114 static const struct snd_soc_ops rt1011_ops = {
0115     .hw_params = rt1011_hw_params,
0116 };
0117 
0118 static int rt1011_init(struct snd_soc_pcm_runtime *rtd)
0119 {
0120     struct snd_soc_card *card = rtd->card;
0121     int ret;
0122 
0123     ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr,
0124                       ARRAY_SIZE(speaker_map_lr));
0125     if (ret)
0126         dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
0127     return ret;
0128 }
0129 
0130 void sof_rt1011_dai_link(struct snd_soc_dai_link *link)
0131 {
0132     link->codecs = rt1011_dai_link_components;
0133     link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components);
0134     link->init = rt1011_init;
0135     link->ops = &rt1011_ops;
0136 }
0137 EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0138 
0139 void sof_rt1011_codec_conf(struct snd_soc_card *card)
0140 {
0141     card->codec_conf = rt1011_codec_confs;
0142     card->num_configs = ARRAY_SIZE(rt1011_codec_confs);
0143 }
0144 EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0145 
0146 /*
0147  * rt1015:  i2c mode driver for ALC1015 and ALC1015Q
0148  * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB
0149  *
0150  * For stereo output, there are always two amplifiers on the board.
0151  * However, the ACPI implements only one device instance (UID=0) if they
0152  * are sharing the same enable pin. The code will detect the number of
0153  * device instance and use corresponding DAPM structures for
0154  * initialization.
0155  */
0156 static const struct snd_soc_dapm_route rt1015p_1dev_dapm_routes[] = {
0157     /* speaker */
0158     { "Left Spk", NULL, "Speaker" },
0159     { "Right Spk", NULL, "Speaker" },
0160 };
0161 
0162 static const struct snd_soc_dapm_route rt1015p_2dev_dapm_routes[] = {
0163     /* speaker */
0164     { "Left Spk", NULL, "Left Speaker" },
0165     { "Right Spk", NULL, "Right Speaker" },
0166 };
0167 
0168 static struct snd_soc_codec_conf rt1015p_codec_confs[] = {
0169     {
0170         .dlc = COMP_CODEC_CONF(RT1015P_DEV0_NAME),
0171         .name_prefix = "Left",
0172     },
0173     {
0174         .dlc = COMP_CODEC_CONF(RT1015P_DEV1_NAME),
0175         .name_prefix = "Right",
0176     },
0177 };
0178 
0179 static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = {
0180     {
0181         .name = RT1015P_DEV0_NAME,
0182         .dai_name = RT1015P_CODEC_DAI,
0183     },
0184     {
0185         .name = RT1015P_DEV1_NAME,
0186         .dai_name = RT1015P_CODEC_DAI,
0187     },
0188 };
0189 
0190 static int rt1015p_get_num_codecs(void)
0191 {
0192     static int dev_num;
0193 
0194     if (dev_num)
0195         return dev_num;
0196 
0197     if (!acpi_dev_present("RTL1015", "1", -1))
0198         dev_num = 1;
0199     else
0200         dev_num = 2;
0201 
0202     return dev_num;
0203 }
0204 
0205 static int rt1015p_hw_params(struct snd_pcm_substream *substream,
0206                  struct snd_pcm_hw_params *params)
0207 {
0208     /* reserved for debugging purpose */
0209 
0210     return 0;
0211 }
0212 
0213 static const struct snd_soc_ops rt1015p_ops = {
0214     .hw_params = rt1015p_hw_params,
0215 };
0216 
0217 static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)
0218 {
0219     struct snd_soc_card *card = rtd->card;
0220     int ret;
0221 
0222     if (rt1015p_get_num_codecs() == 1)
0223         ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_1dev_dapm_routes,
0224                           ARRAY_SIZE(rt1015p_1dev_dapm_routes));
0225     else
0226         ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_2dev_dapm_routes,
0227                           ARRAY_SIZE(rt1015p_2dev_dapm_routes));
0228     if (ret)
0229         dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
0230     return ret;
0231 }
0232 
0233 void sof_rt1015p_dai_link(struct snd_soc_dai_link *link)
0234 {
0235     link->codecs = rt1015p_dai_link_components;
0236     link->num_codecs = rt1015p_get_num_codecs();
0237     link->init = rt1015p_init;
0238     link->ops = &rt1015p_ops;
0239 }
0240 EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0241 
0242 void sof_rt1015p_codec_conf(struct snd_soc_card *card)
0243 {
0244     if (rt1015p_get_num_codecs() == 1)
0245         return;
0246 
0247     card->codec_conf = rt1015p_codec_confs;
0248     card->num_configs = ARRAY_SIZE(rt1015p_codec_confs);
0249 }
0250 EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0251 
0252 /*
0253  * RT1015 audio amplifier
0254  */
0255 
0256 static int rt1015_hw_params(struct snd_pcm_substream *substream,
0257                 struct snd_pcm_hw_params *params)
0258 {
0259     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0260     struct snd_soc_dai *codec_dai;
0261     int i, fs = 64, ret;
0262 
0263     for_each_rtd_codec_dais(rtd, i, codec_dai) {
0264         ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
0265                       params_rate(params) * fs,
0266                       params_rate(params) * 256);
0267         if (ret)
0268             return ret;
0269 
0270         ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,
0271                          params_rate(params) * 256,
0272                          SND_SOC_CLOCK_IN);
0273         if (ret)
0274             return ret;
0275     }
0276 
0277     return 0;
0278 }
0279 
0280 static int rt1015_hw_params_pll_and_tdm(struct snd_pcm_substream *substream,
0281                      struct snd_pcm_hw_params *params)
0282 {
0283     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0284     struct snd_soc_dai *codec_dai;
0285     int i, fs = 100, ret;
0286 
0287     for_each_rtd_codec_dais(rtd, i, codec_dai) {
0288         ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
0289                       params_rate(params) * fs,
0290                       params_rate(params) * 256);
0291         if (ret)
0292             return ret;
0293 
0294         ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,
0295                          params_rate(params) * 256,
0296                          SND_SOC_CLOCK_IN);
0297         if (ret)
0298             return ret;
0299     }
0300     /* rx slot 1 for RT1015_DEV0_NAME */
0301     ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0),
0302                        0x0, 0x1, 4, 24);
0303     if (ret)
0304         return ret;
0305 
0306     /* rx slot 2 for RT1015_DEV1_NAME */
0307     ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 1),
0308                        0x0, 0x2, 4, 24);
0309     if (ret)
0310         return ret;
0311 
0312     return 0;
0313 }
0314 
0315 static struct snd_soc_ops rt1015_ops = {
0316     .hw_params = rt1015_hw_params,
0317 };
0318 
0319 static struct snd_soc_codec_conf rt1015_amp_conf[] = {
0320     {
0321         .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),
0322         .name_prefix = "Left",
0323     },
0324     {
0325         .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),
0326         .name_prefix = "Right",
0327     },
0328 };
0329 
0330 static struct snd_soc_dai_link_component rt1015_components[] = {
0331     {
0332         .name = RT1015_DEV0_NAME,
0333         .dai_name = RT1015_CODEC_DAI,
0334     },
0335     {
0336         .name = RT1015_DEV1_NAME,
0337         .dai_name = RT1015_CODEC_DAI,
0338     },
0339 };
0340 
0341 static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd)
0342 {
0343     return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr,
0344                     ARRAY_SIZE(speaker_map_lr));
0345 }
0346 
0347 void sof_rt1015_codec_conf(struct snd_soc_card *card)
0348 {
0349     card->codec_conf = rt1015_amp_conf;
0350     card->num_configs = ARRAY_SIZE(rt1015_amp_conf);
0351 }
0352 EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0353 
0354 void sof_rt1015_dai_link(struct snd_soc_dai_link *link, unsigned int fs)
0355 {
0356     link->codecs = rt1015_components;
0357     link->num_codecs = ARRAY_SIZE(rt1015_components);
0358     link->init = speaker_codec_init_lr;
0359     link->ops = &rt1015_ops;
0360 
0361     if (fs == 100)
0362         rt1015_ops.hw_params = rt1015_hw_params_pll_and_tdm;
0363 }
0364 EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0365 
0366 /*
0367  * RT1308 audio amplifier
0368  */
0369 static const struct snd_kcontrol_new rt1308_kcontrols[] = {
0370     SOC_DAPM_PIN_SWITCH("Speakers"),
0371 };
0372 
0373 static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = {
0374     SND_SOC_DAPM_SPK("Speakers", NULL),
0375 };
0376 
0377 static const struct snd_soc_dapm_route rt1308_dapm_routes[] = {
0378     /* speaker */
0379     {"Speakers", NULL, "SPOL"},
0380     {"Speakers", NULL, "SPOR"},
0381 };
0382 
0383 static struct snd_soc_dai_link_component rt1308_components[] = {
0384     {
0385         .name = RT1308_DEV0_NAME,
0386         .dai_name = RT1308_CODEC_DAI,
0387     }
0388 };
0389 
0390 static int rt1308_init(struct snd_soc_pcm_runtime *rtd)
0391 {
0392     struct snd_soc_card *card = rtd->card;
0393     int ret;
0394 
0395     ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets,
0396                     ARRAY_SIZE(rt1308_dapm_widgets));
0397     if (ret) {
0398         dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);
0399         return ret;
0400     }
0401 
0402     ret = snd_soc_add_card_controls(card, rt1308_kcontrols,
0403                     ARRAY_SIZE(rt1308_kcontrols));
0404     if (ret) {
0405         dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret);
0406         return ret;
0407     }
0408 
0409     ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes,
0410                       ARRAY_SIZE(rt1308_dapm_routes));
0411 
0412     if (ret)
0413         dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret);
0414 
0415     return ret;
0416 }
0417 
0418 static int rt1308_hw_params(struct snd_pcm_substream *substream,
0419                 struct snd_pcm_hw_params *params)
0420 {
0421     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0422     struct snd_soc_card *card = rtd->card;
0423     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0424     int clk_id, clk_freq, pll_out;
0425     int ret;
0426 
0427     clk_id = RT1308_PLL_S_MCLK;
0428     /* get the tplg configured mclk. */
0429     clk_freq = sof_dai_get_mclk(rtd);
0430 
0431     pll_out = params_rate(params) * 512;
0432 
0433     /* Set rt1308 pll */
0434     ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
0435     if (ret < 0) {
0436         dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", ret);
0437         return ret;
0438     }
0439 
0440     /* Set rt1308 sysclk */
0441     ret = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,
0442                      SND_SOC_CLOCK_IN);
0443     if (ret < 0)
0444         dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", ret);
0445 
0446     return ret;
0447 }
0448 
0449 static const struct snd_soc_ops rt1308_ops = {
0450     .hw_params = rt1308_hw_params,
0451 };
0452 
0453 void sof_rt1308_dai_link(struct snd_soc_dai_link *link)
0454 {
0455     link->codecs = rt1308_components;
0456     link->num_codecs = ARRAY_SIZE(rt1308_components);
0457     link->init = rt1308_init;
0458     link->ops = &rt1308_ops;
0459 }
0460 EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0461 
0462 /*
0463  * 2-amp Configuration for RT1019
0464  */
0465 
0466 static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {
0467     /* speaker */
0468     { "Left Spk", NULL, "Speaker" },
0469     { "Right Spk", NULL, "Speaker" },
0470 };
0471 
0472 static struct snd_soc_dai_link_component rt1019p_components[] = {
0473     {
0474         .name = RT1019P_DEV0_NAME,
0475         .dai_name = RT1019P_CODEC_DAI,
0476     },
0477 };
0478 
0479 static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)
0480 {
0481     struct snd_soc_card *card = rtd->card;
0482     int ret;
0483 
0484     ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,
0485                       ARRAY_SIZE(rt1019p_dapm_routes));
0486     if (ret) {
0487         dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
0488         return ret;
0489     }
0490     return ret;
0491 }
0492 
0493 void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)
0494 {
0495     link->codecs = rt1019p_components;
0496     link->num_codecs = ARRAY_SIZE(rt1019p_components);
0497     link->init = rt1019p_init;
0498 }
0499 EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
0500 
0501 MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");
0502 MODULE_LICENSE("GPL");