|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
| 2 | +// |
| 3 | +// Intel SOF Machine Driver with Cirrus Logic CS35L56 Smart Amp |
| 4 | + |
| 5 | +#include <linux/module.h> |
| 6 | +#include <linux/platform_device.h> |
| 7 | +#include <sound/core.h> |
| 8 | +#include <sound/pcm.h> |
| 9 | +#include <sound/pcm_params.h> |
| 10 | +#include <sound/soc.h> |
| 11 | +#include <sound/soc-acpi.h> |
| 12 | +#include "sof_sdw_common.h" |
| 13 | + |
| 14 | +static const struct snd_soc_dapm_widget bridge_widgets[] = { |
| 15 | + SND_SOC_DAPM_SPK("Bridge Speaker", NULL), |
| 16 | +}; |
| 17 | + |
| 18 | +static const struct snd_soc_dapm_route bridge_map[] = { |
| 19 | + {"Bridge Speaker", NULL, "AMPL SPK"}, |
| 20 | + {"Bridge Speaker", NULL, "AMPR SPK"}, |
| 21 | +}; |
| 22 | + |
| 23 | +static const char * const bridge_cs35l56_name_prefixes[] = { |
| 24 | + "AMPL", |
| 25 | + "AMPR", |
| 26 | +}; |
| 27 | + |
| 28 | +static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) |
| 29 | +{ |
| 30 | + struct snd_soc_card *card = rtd->card; |
| 31 | + int i, ret; |
| 32 | + unsigned int rx_mask = 3; // ASP RX1, RX2 |
| 33 | + unsigned int tx_mask = 3; // ASP TX1, TX2 |
| 34 | + struct snd_soc_dai *codec_dai; |
| 35 | + struct snd_soc_dai *cpu_dai; |
| 36 | + |
| 37 | + card->components = devm_kasprintf(card->dev, GFP_KERNEL, |
| 38 | + "%s spk:cs35l56-bridge", |
| 39 | + card->components); |
| 40 | + if (!card->components) |
| 41 | + return -ENOMEM; |
| 42 | + |
| 43 | + ret = snd_soc_dapm_new_controls(&card->dapm, bridge_widgets, |
| 44 | + ARRAY_SIZE(bridge_widgets)); |
| 45 | + if (ret) { |
| 46 | + dev_err(card->dev, "widgets addition failed: %d\n", ret); |
| 47 | + return ret; |
| 48 | + } |
| 49 | + |
| 50 | + ret = snd_soc_dapm_add_routes(&card->dapm, bridge_map, ARRAY_SIZE(bridge_map)); |
| 51 | + if (ret) { |
| 52 | + dev_err(card->dev, "map addition failed: %d\n", ret); |
| 53 | + return ret; |
| 54 | + } |
| 55 | + |
| 56 | + /* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */ |
| 57 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
| 58 | + ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16); |
| 59 | + if (ret < 0) |
| 60 | + return ret; |
| 61 | + |
| 62 | + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 3072000, SND_SOC_CLOCK_IN); |
| 63 | + if (ret < 0) |
| 64 | + return ret; |
| 65 | + } |
| 66 | + |
| 67 | + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { |
| 68 | + ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, 4, 16); |
| 69 | + if (ret < 0) |
| 70 | + return ret; |
| 71 | + } |
| 72 | + |
| 73 | + return 0; |
| 74 | +} |
| 75 | + |
| 76 | +static const struct snd_soc_pcm_stream bridge_params = { |
| 77 | + .formats = SNDRV_PCM_FMTBIT_S16_LE, |
| 78 | + .rate_min = 48000, |
| 79 | + .rate_max = 48000, |
| 80 | + .channels_min = 2, |
| 81 | + .channels_max = 2, |
| 82 | +}; |
| 83 | + |
| 84 | +SND_SOC_DAILINK_DEFS(bridge_dai, |
| 85 | + DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")), |
| 86 | + DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"), |
| 87 | + COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")), |
| 88 | + DAILINK_COMP_ARRAY(COMP_PLATFORM("cs42l43-codec"))); |
| 89 | + |
| 90 | +static const struct snd_soc_dai_link bridge_dai_template = { |
| 91 | + .name = "cs42l43-cs35l56", |
| 92 | + .init = bridge_cs35l56_asp_init, |
| 93 | + .c2c_params = &bridge_params, |
| 94 | + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC, |
| 95 | + SND_SOC_DAILINK_REG(bridge_dai), |
| 96 | +}; |
| 97 | + |
| 98 | +int bridge_cs35l56_count_sidecar(struct snd_soc_card *card, |
| 99 | + int *num_dais, int *num_devs) |
| 100 | +{ |
| 101 | + if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { |
| 102 | + (*num_dais)++; |
| 103 | + (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes); |
| 104 | + } |
| 105 | + |
| 106 | + return 0; |
| 107 | +} |
| 108 | + |
| 109 | +int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, |
| 110 | + struct snd_soc_dai_link **dai_links, |
| 111 | + struct snd_soc_codec_conf **codec_conf) |
| 112 | +{ |
| 113 | + if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { |
| 114 | + **dai_links = bridge_dai_template; |
| 115 | + |
| 116 | + for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) { |
| 117 | + (*codec_conf)->dlc.name = (*dai_links)->codecs[i].name; |
| 118 | + (*codec_conf)->name_prefix = bridge_cs35l56_name_prefixes[i]; |
| 119 | + (*codec_conf)++; |
| 120 | + } |
| 121 | + |
| 122 | + (*dai_links)++; |
| 123 | + } |
| 124 | + |
| 125 | + return 0; |
| 126 | +} |
| 127 | + |
| 128 | +int bridge_cs35l56_spk_init(struct snd_soc_card *card, |
| 129 | + struct snd_soc_dai_link *dai_links, |
| 130 | + struct sof_sdw_codec_info *info, |
| 131 | + bool playback) |
| 132 | +{ |
| 133 | + if (sof_sdw_quirk & SOF_SIDECAR_AMPS) |
| 134 | + info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes); |
| 135 | + |
| 136 | + return 0; |
| 137 | +} |
0 commit comments