Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * This file defines data structures and functions used in Machine
0004  * Driver for Intel platforms with Cirrus Logic Codecs.
0005  *
0006  * Copyright 2022 Intel Corporation.
0007  */
0008 #include <linux/module.h>
0009 #include <sound/sof.h>
0010 #include "../../codecs/cs35l41.h"
0011 #include "sof_cirrus_common.h"
0012 
0013 /*
0014  * Cirrus Logic CS35L41/CS35L53
0015  */
0016 static const struct snd_kcontrol_new cs35l41_kcontrols[] = {
0017     SOC_DAPM_PIN_SWITCH("WL Spk"),
0018     SOC_DAPM_PIN_SWITCH("WR Spk"),
0019     SOC_DAPM_PIN_SWITCH("TL Spk"),
0020     SOC_DAPM_PIN_SWITCH("TR Spk"),
0021 };
0022 
0023 static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = {
0024     SND_SOC_DAPM_SPK("WL Spk", NULL),
0025     SND_SOC_DAPM_SPK("WR Spk", NULL),
0026     SND_SOC_DAPM_SPK("TL Spk", NULL),
0027     SND_SOC_DAPM_SPK("TR Spk", NULL),
0028 };
0029 
0030 static const struct snd_soc_dapm_route cs35l41_dapm_routes[] = {
0031     /* speaker */
0032     {"WL Spk", NULL, "WL SPK"},
0033     {"WR Spk", NULL, "WR SPK"},
0034     {"TL Spk", NULL, "TL SPK"},
0035     {"TR Spk", NULL, "TR SPK"},
0036 };
0037 
0038 static struct snd_soc_dai_link_component cs35l41_components[] = {
0039     {
0040         .name = CS35L41_DEV0_NAME,
0041         .dai_name = CS35L41_CODEC_DAI,
0042     },
0043     {
0044         .name = CS35L41_DEV1_NAME,
0045         .dai_name = CS35L41_CODEC_DAI,
0046     },
0047     {
0048         .name = CS35L41_DEV2_NAME,
0049         .dai_name = CS35L41_CODEC_DAI,
0050     },
0051     {
0052         .name = CS35L41_DEV3_NAME,
0053         .dai_name = CS35L41_CODEC_DAI,
0054     },
0055 };
0056 
0057 /*
0058  * Mapping between ACPI instance id and speaker position.
0059  *
0060  * Four speakers:
0061  *         0: Tweeter left, 1: Woofer left
0062  *         2: Tweeter right, 3: Woofer right
0063  */
0064 static struct snd_soc_codec_conf cs35l41_codec_conf[] = {
0065     {
0066         .dlc = COMP_CODEC_CONF(CS35L41_DEV0_NAME),
0067         .name_prefix = "TL",
0068     },
0069     {
0070         .dlc = COMP_CODEC_CONF(CS35L41_DEV1_NAME),
0071         .name_prefix = "WL",
0072     },
0073     {
0074         .dlc = COMP_CODEC_CONF(CS35L41_DEV2_NAME),
0075         .name_prefix = "TR",
0076     },
0077     {
0078         .dlc = COMP_CODEC_CONF(CS35L41_DEV3_NAME),
0079         .name_prefix = "WR",
0080     },
0081 };
0082 
0083 static int cs35l41_init(struct snd_soc_pcm_runtime *rtd)
0084 {
0085     struct snd_soc_card *card = rtd->card;
0086     int ret;
0087 
0088     ret = snd_soc_dapm_new_controls(&card->dapm, cs35l41_dapm_widgets,
0089                     ARRAY_SIZE(cs35l41_dapm_widgets));
0090     if (ret) {
0091         dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);
0092         return ret;
0093     }
0094 
0095     ret = snd_soc_add_card_controls(card, cs35l41_kcontrols,
0096                     ARRAY_SIZE(cs35l41_kcontrols));
0097     if (ret) {
0098         dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret);
0099         return ret;
0100     }
0101 
0102     ret = snd_soc_dapm_add_routes(&card->dapm, cs35l41_dapm_routes,
0103                       ARRAY_SIZE(cs35l41_dapm_routes));
0104 
0105     if (ret)
0106         dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret);
0107 
0108     return ret;
0109 }
0110 
0111 /*
0112  * Channel map:
0113  *
0114  * TL/WL: ASPRX1 on slot 0, ASPRX2 on slot 1 (default)
0115  * TR/WR: ASPRX1 on slot 1, ASPRX2 on slot 0
0116  */
0117 static const struct {
0118     unsigned int rx[2];
0119 } cs35l41_channel_map[] = {
0120     {.rx = {0, 1}}, /* TL */
0121     {.rx = {0, 1}}, /* WL */
0122     {.rx = {1, 0}}, /* TR */
0123     {.rx = {1, 0}}, /* WR */
0124 };
0125 
0126 static int cs35l41_hw_params(struct snd_pcm_substream *substream,
0127                  struct snd_pcm_hw_params *params)
0128 {
0129     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0130     struct snd_soc_dai *codec_dai;
0131     int clk_freq, i, ret;
0132 
0133     clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
0134 
0135     if (clk_freq <= 0) {
0136         dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq);
0137         return -EINVAL;
0138     }
0139 
0140     for_each_rtd_codec_dais(rtd, i, codec_dai) {
0141         /* call dai driver's set_sysclk() callback */
0142         ret = snd_soc_dai_set_sysclk(codec_dai, CS35L41_CLKID_SCLK,
0143                          clk_freq, SND_SOC_CLOCK_IN);
0144         if (ret < 0) {
0145             dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",
0146                 ret);
0147             return ret;
0148         }
0149 
0150         /* call component driver's set_sysclk() callback */
0151         ret = snd_soc_component_set_sysclk(codec_dai->component,
0152                            CS35L41_CLKID_SCLK, 0,
0153                            clk_freq, SND_SOC_CLOCK_IN);
0154         if (ret < 0) {
0155             dev_err(codec_dai->dev, "fail to set component sysclk, ret %d\n",
0156                 ret);
0157             return ret;
0158         }
0159 
0160         /* setup channel map */
0161         ret = snd_soc_dai_set_channel_map(codec_dai, 0, NULL,
0162                           ARRAY_SIZE(cs35l41_channel_map[i].rx),
0163                           (unsigned int *)cs35l41_channel_map[i].rx);
0164         if (ret < 0) {
0165             dev_err(codec_dai->dev, "fail to set channel map, ret %d\n",
0166                 ret);
0167             return ret;
0168         }
0169     }
0170 
0171     return 0;
0172 }
0173 
0174 static const struct snd_soc_ops cs35l41_ops = {
0175     .hw_params = cs35l41_hw_params,
0176 };
0177 
0178 void cs35l41_set_dai_link(struct snd_soc_dai_link *link)
0179 {
0180     link->codecs = cs35l41_components;
0181     link->num_codecs = ARRAY_SIZE(cs35l41_components);
0182     link->init = cs35l41_init;
0183     link->ops = &cs35l41_ops;
0184 }
0185 EXPORT_SYMBOL_NS(cs35l41_set_dai_link, SND_SOC_INTEL_SOF_CIRRUS_COMMON);
0186 
0187 void cs35l41_set_codec_conf(struct snd_soc_card *card)
0188 {
0189     card->codec_conf = cs35l41_codec_conf;
0190     card->num_configs = ARRAY_SIZE(cs35l41_codec_conf);
0191 }
0192 EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, SND_SOC_INTEL_SOF_CIRRUS_COMMON);
0193 
0194 MODULE_DESCRIPTION("ASoC Intel SOF Cirrus Logic helpers");
0195 MODULE_LICENSE("GPL");