linux/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2// This file incorporates work covered by the following copyright notice:
   3// Copyright (c) 2024 Intel Corporation
   4// Copyright (c) 2024 Advanced Micro Devices, Inc.
   5
   6/*
   7 * soc_sdw_bridge_cs35l56 - codec helper functions for handling CS35L56 Smart AMP
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/platform_device.h>
  12#include <sound/core.h>
  13#include <sound/pcm.h>
  14#include <sound/pcm_params.h>
  15#include <sound/soc.h>
  16#include <sound/soc-acpi.h>
  17#include <sound/soc_sdw_utils.h>
  18
  19static const struct snd_soc_dapm_widget bridge_widgets[] = {
  20        SND_SOC_DAPM_SPK("Bridge Speaker", NULL),
  21};
  22
  23static const struct snd_soc_dapm_route bridge_map[] = {
  24        {"Bridge Speaker", NULL, "AMPL SPK"},
  25        {"Bridge Speaker", NULL, "AMPR SPK"},
  26};
  27
  28static const char * const bridge_cs35l56_name_prefixes[] = {
  29        "AMPL",
  30        "AMPR",
  31};
  32
  33static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
  34{
  35        struct snd_soc_card *card = rtd->card;
  36        int i, ret;
  37        unsigned int rx_mask = 3; // ASP RX1, RX2
  38        unsigned int tx_mask = 3; // ASP TX1, TX2
  39        struct snd_soc_dai *codec_dai;
  40        struct snd_soc_dai *cpu_dai;
  41
  42        card->components = devm_kasprintf(card->dev, GFP_KERNEL,
  43                                          "%s spk:cs35l56-bridge",
  44                                          card->components);
  45        if (!card->components)
  46                return -ENOMEM;
  47
  48        ret = snd_soc_dapm_new_controls(&card->dapm, bridge_widgets,
  49                                        ARRAY_SIZE(bridge_widgets));
  50        if (ret) {
  51                dev_err(card->dev, "widgets addition failed: %d\n", ret);
  52                return ret;
  53        }
  54
  55        ret = snd_soc_dapm_add_routes(&card->dapm, bridge_map, ARRAY_SIZE(bridge_map));
  56        if (ret) {
  57                dev_err(card->dev, "map addition failed: %d\n", ret);
  58                return ret;
  59        }
  60
  61        /* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */
  62        for_each_rtd_codec_dais(rtd, i, codec_dai) {
  63                ret = asoc_sdw_cs35l56_volume_limit(card, codec_dai->component->name_prefix);
  64                if (ret)
  65                        return ret;
  66
  67                ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16);
  68                if (ret < 0)
  69                        return ret;
  70
  71                ret = snd_soc_dai_set_sysclk(codec_dai, 0, 3072000, SND_SOC_CLOCK_IN);
  72                if (ret < 0)
  73                        return ret;
  74        }
  75
  76        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
  77                ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, 4, 16);
  78                if (ret < 0)
  79                        return ret;
  80        }
  81
  82        return 0;
  83}
  84
  85static const struct snd_soc_pcm_stream asoc_sdw_bridge_params = {
  86        .formats = SNDRV_PCM_FMTBIT_S16_LE,
  87        .rate_min = 48000,
  88        .rate_max = 48000,
  89        .channels_min = 2,
  90        .channels_max = 2,
  91};
  92
  93SND_SOC_DAILINK_DEFS(asoc_sdw_bridge_dai,
  94                     DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")),
  95                     DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"),
  96                                        COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")),
  97                     DAILINK_COMP_ARRAY(COMP_PLATFORM("cs42l43-codec")));
  98
  99static const struct snd_soc_dai_link bridge_dai_template = {
 100        .name = "cs42l43-cs35l56",
 101        .init = asoc_sdw_bridge_cs35l56_asp_init,
 102        .c2c_params = &asoc_sdw_bridge_params,
 103        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC,
 104        SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai),
 105};
 106
 107int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
 108                                          int *num_dais, int *num_devs)
 109{
 110        struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
 111
 112        if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
 113                (*num_dais)++;
 114                (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
 115        }
 116
 117        return 0;
 118}
 119EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_count_sidecar, "SND_SOC_SDW_UTILS");
 120
 121int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
 122                                        struct snd_soc_dai_link **dai_links,
 123                                        struct snd_soc_codec_conf **codec_conf)
 124{
 125        struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
 126
 127        if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
 128                **dai_links = bridge_dai_template;
 129
 130                for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) {
 131                        (*codec_conf)->dlc.name = (*dai_links)->codecs[i].name;
 132                        (*codec_conf)->name_prefix = bridge_cs35l56_name_prefixes[i];
 133                        (*codec_conf)++;
 134                }
 135
 136                (*dai_links)++;
 137        }
 138
 139        return 0;
 140}
 141EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_add_sidecar, "SND_SOC_SDW_UTILS");
 142
 143int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card,
 144                                     struct snd_soc_dai_link *dai_links,
 145                                     struct asoc_sdw_codec_info *info,
 146                                     bool playback)
 147{
 148        struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
 149
 150        if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)
 151                info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
 152
 153        return 0;
 154}
 155EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_spk_init, "SND_SOC_SDW_UTILS");
 156