summaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/boards/bridge_cs35l56.c
blob: c3995e724aed9806e4b4d888066cf6987d65f61d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-License-Identifier: GPL-2.0-only
//
// Intel SOF Machine Driver with Cirrus Logic CS35L56 Smart Amp

#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "sof_sdw_common.h"

static const struct snd_soc_dapm_widget bridge_widgets[] = {
	SND_SOC_DAPM_SPK("Bridge Speaker", NULL),
};

static const struct snd_soc_dapm_route bridge_map[] = {
	{"Bridge Speaker", NULL, "AMPL SPK"},
	{"Bridge Speaker", NULL, "AMPR SPK"},
};

static const char * const bridge_cs35l56_name_prefixes[] = {
	"AMPL",
	"AMPR",
};

static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
{
	struct snd_soc_card *card = rtd->card;
	int i, ret;
	unsigned int rx_mask = 3; // ASP RX1, RX2
	unsigned int tx_mask = 3; // ASP TX1, TX2
	struct snd_soc_dai *codec_dai;
	struct snd_soc_dai *cpu_dai;

	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
					  "%s spk:cs35l56-bridge",
					  card->components);
	if (!card->components)
		return -ENOMEM;

	ret = snd_soc_dapm_new_controls(&card->dapm, bridge_widgets,
					ARRAY_SIZE(bridge_widgets));
	if (ret) {
		dev_err(card->dev, "widgets addition failed: %d\n", ret);
		return ret;
	}

	ret = snd_soc_dapm_add_routes(&card->dapm, bridge_map, ARRAY_SIZE(bridge_map));
	if (ret) {
		dev_err(card->dev, "map addition failed: %d\n", ret);
		return ret;
	}

	/* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */
	for_each_rtd_codec_dais(rtd, i, codec_dai) {
		ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16);
		if (ret < 0)
			return ret;

		ret = snd_soc_dai_set_sysclk(codec_dai, 0, 3072000, SND_SOC_CLOCK_IN);
		if (ret < 0)
			return ret;
	}

	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
		ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, 4, 16);
		if (ret < 0)
			return ret;
	}

	return 0;
}

static const struct snd_soc_pcm_stream bridge_params = {
	.formats = SNDRV_PCM_FMTBIT_S16_LE,
	.rate_min = 48000,
	.rate_max = 48000,
	.channels_min = 2,
	.channels_max = 2,
};

SND_SOC_DAILINK_DEFS(bridge_dai,
		     DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")),
		     DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"),
					COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")),
		     DAILINK_COMP_ARRAY(COMP_PLATFORM("cs42l43-codec")));

static const struct snd_soc_dai_link bridge_dai_template = {
	.name = "cs42l43-cs35l56",
	.init = bridge_cs35l56_asp_init,
	.c2c_params = &bridge_params,
	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC,
	SND_SOC_DAILINK_REG(bridge_dai),
};

int bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
				 int *num_dais, int *num_devs)
{
	if (sof_sdw_quirk & SOF_SIDECAR_AMPS) {
		(*num_dais)++;
		(*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
	}

	return 0;
}

int bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
			       struct snd_soc_dai_link **dai_links,
			       struct snd_soc_codec_conf **codec_conf)
{
	if (sof_sdw_quirk & SOF_SIDECAR_AMPS) {
		**dai_links = bridge_dai_template;

		for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) {
			(*codec_conf)->dlc.name = (*dai_links)->codecs[i].name;
			(*codec_conf)->name_prefix = bridge_cs35l56_name_prefixes[i];
			(*codec_conf)++;
		}

		(*dai_links)++;
	}

	return 0;
}

int bridge_cs35l56_spk_init(struct snd_soc_card *card,
			    struct snd_soc_dai_link *dai_links,
			    struct sof_sdw_codec_info *info,
			    bool playback)
{
	if (sof_sdw_quirk & SOF_SIDECAR_AMPS)
		info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes);

	return 0;
}