1 // SPDX-License-Identifier: GPL-2.0-only
2 // This file incorporates work covered by the following copyright notice:
3 // Copyright (c) 2022 Intel Corporation
4 // Copyright (c) 2024 Advanced Micro Devices, Inc.
7 * soc_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <sound/control.h>
13 #include <sound/soc.h>
14 #include <sound/soc-acpi.h>
15 #include <sound/soc-dapm.h>
16 #include <linux/soundwire/sdw.h>
17 #include <linux/soundwire/sdw_type.h>
18 #include <linux/dmi.h>
19 #include <sound/soc_sdw_utils.h>
20 #include "soc_sdw_rt_amp_coeff_tables.h"
21 #include "../codecs/rt1308.h"
23 #define CODEC_NAME_SIZE 7
25 /* choose a larger value to resolve compatibility issues */
26 #define RT_AMP_MAX_BQ_REG RT1316_MAX_BQ_REG
28 struct rt_amp_platform_data
{
29 const unsigned char *bq_params
;
30 const unsigned int bq_params_cnt
;
33 static const struct rt_amp_platform_data dell_0a5d_platform_data
= {
34 .bq_params
= dell_0a5d_bq_params
,
35 .bq_params_cnt
= ARRAY_SIZE(dell_0a5d_bq_params
),
38 static const struct rt_amp_platform_data dell_0b00_platform_data
= {
39 .bq_params
= dell_0b00_bq_params
,
40 .bq_params_cnt
= ARRAY_SIZE(dell_0b00_bq_params
),
43 static const struct dmi_system_id dmi_platform_data
[] = {
44 /* CometLake devices */
47 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
48 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0990")
50 .driver_data
= (void *)&dell_0a5d_platform_data
,
54 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
55 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "098F")
57 .driver_data
= (void *)&dell_0a5d_platform_data
,
59 /* TigerLake devices */
62 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
63 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0A5D")
65 .driver_data
= (void *)&dell_0a5d_platform_data
,
69 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
70 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0A5E")
72 .driver_data
= (void *)&dell_0a5d_platform_data
,
74 /* AlderLake devices */
77 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
78 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0B00")
80 .driver_data
= (void *)&dell_0b00_platform_data
,
84 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
85 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0B01")
87 .driver_data
= (void *)&dell_0b00_platform_data
,
91 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
92 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0AFF")
94 .driver_data
= (void *)&dell_0b00_platform_data
,
98 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
99 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0AFE")
101 .driver_data
= (void *)&dell_0b00_platform_data
,
106 static int rt_amp_add_device_props(struct device
*sdw_dev
)
108 struct property_entry props
[3] = {};
109 struct fwnode_handle
*fwnode
;
110 const struct dmi_system_id
*dmi_data
;
111 const struct rt_amp_platform_data
*pdata
;
112 unsigned char params
[RT_AMP_MAX_BQ_REG
];
115 dmi_data
= dmi_first_match(dmi_platform_data
);
119 pdata
= dmi_data
->driver_data
;
120 memcpy(¶ms
, pdata
->bq_params
, sizeof(unsigned char) * pdata
->bq_params_cnt
);
122 props
[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params
);
123 props
[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata
->bq_params_cnt
);
125 fwnode
= fwnode_create_software_node(props
, NULL
);
127 return PTR_ERR(fwnode
);
129 ret
= device_add_software_node(sdw_dev
, to_software_node(fwnode
));
131 fwnode_handle_put(fwnode
);
137 * dapm routes for rt1308/rt1316/rt1318 will be registered dynamically
138 * according to the number of rt1308/rt1316/rt1318 used. The first two
139 * entries will be registered for one codec case, and the last two entries
140 * are also registered if two 1308s/1316s/1318s are used.
142 static const struct snd_soc_dapm_route rt1308_map
[] = {
143 { "Speaker", NULL
, "rt1308-1 SPOL" },
144 { "Speaker", NULL
, "rt1308-1 SPOR" },
145 { "Speaker", NULL
, "rt1308-2 SPOL" },
146 { "Speaker", NULL
, "rt1308-2 SPOR" },
149 static const struct snd_soc_dapm_route rt1316_map
[] = {
150 { "Speaker", NULL
, "rt1316-1 SPOL" },
151 { "Speaker", NULL
, "rt1316-1 SPOR" },
152 { "Speaker", NULL
, "rt1316-2 SPOL" },
153 { "Speaker", NULL
, "rt1316-2 SPOR" },
156 static const struct snd_soc_dapm_route rt1318_map
[] = {
157 { "Speaker", NULL
, "rt1318-1 SPOL" },
158 { "Speaker", NULL
, "rt1318-1 SPOR" },
159 { "Speaker", NULL
, "rt1318-2 SPOL" },
160 { "Speaker", NULL
, "rt1318-2 SPOR" },
163 static const struct snd_soc_dapm_route rt1320_map
[] = {
164 { "Speaker", NULL
, "rt1320-1 SPOL" },
165 { "Speaker", NULL
, "rt1320-1 SPOR" },
166 { "Speaker", NULL
, "rt1320-2 SPOL" },
167 { "Speaker", NULL
, "rt1320-2 SPOR" },
170 static const struct snd_soc_dapm_route
*get_codec_name_and_route(struct snd_soc_dai
*dai
,
173 /* get the codec name */
174 snprintf(codec_name
, CODEC_NAME_SIZE
, "%s", dai
->name
);
176 /* choose the right codec's map */
177 if (strcmp(codec_name
, "rt1308") == 0)
179 else if (strcmp(codec_name
, "rt1316") == 0)
181 else if (strcmp(codec_name
, "rt1318") == 0)
187 int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime
*rtd
, struct snd_soc_dai
*dai
)
189 struct snd_soc_card
*card
= rtd
->card
;
190 const struct snd_soc_dapm_route
*rt_amp_map
;
191 char codec_name
[CODEC_NAME_SIZE
];
192 struct snd_soc_dai
*codec_dai
;
196 rt_amp_map
= get_codec_name_and_route(dai
, codec_name
);
198 card
->components
= devm_kasprintf(card
->dev
, GFP_KERNEL
,
200 card
->components
, codec_name
);
201 if (!card
->components
)
204 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
205 if (strstr(codec_dai
->component
->name_prefix
, "-1"))
206 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt_amp_map
, 2);
207 else if (strstr(codec_dai
->component
->name_prefix
, "-2"))
208 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt_amp_map
+ 2, 2);
213 EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_spk_rtd_init
, "SND_SOC_SDW_UTILS");
215 static int rt1308_i2s_hw_params(struct snd_pcm_substream
*substream
,
216 struct snd_pcm_hw_params
*params
)
218 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
219 struct snd_soc_card
*card
= rtd
->card
;
220 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
221 int clk_id
, clk_freq
, pll_out
;
224 clk_id
= RT1308_PLL_S_MCLK
;
227 pll_out
= params_rate(params
) * 512;
230 err
= snd_soc_dai_set_pll(codec_dai
, 0, clk_id
, clk_freq
, pll_out
);
232 dev_err(card
->dev
, "Failed to set RT1308 PLL: %d\n", err
);
236 /* Set rt1308 sysclk */
237 err
= snd_soc_dai_set_sysclk(codec_dai
, RT1308_FS_SYS_S_PLL
, pll_out
,
240 dev_err(card
->dev
, "Failed to set RT1308 SYSCLK: %d\n", err
);
247 /* machine stream operations */
248 const struct snd_soc_ops soc_sdw_rt1308_i2s_ops
= {
249 .hw_params
= rt1308_i2s_hw_params
,
251 EXPORT_SYMBOL_NS(soc_sdw_rt1308_i2s_ops
, "SND_SOC_SDW_UTILS");
253 int asoc_sdw_rt_amp_exit(struct snd_soc_card
*card
, struct snd_soc_dai_link
*dai_link
)
255 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
258 device_remove_software_node(ctx
->amp_dev1
);
259 put_device(ctx
->amp_dev1
);
263 device_remove_software_node(ctx
->amp_dev2
);
264 put_device(ctx
->amp_dev2
);
269 EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_exit
, "SND_SOC_SDW_UTILS");
271 int asoc_sdw_rt_amp_init(struct snd_soc_card
*card
,
272 struct snd_soc_dai_link
*dai_links
,
273 struct asoc_sdw_codec_info
*info
,
276 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
277 struct device
*sdw_dev1
, *sdw_dev2
;
280 /* Count amp number and do init on playback link only. */
286 if (info
->amp_num
== 2) {
287 sdw_dev1
= bus_find_device_by_name(&sdw_bus_type
, NULL
, dai_links
->codecs
[0].name
);
289 return -EPROBE_DEFER
;
291 ret
= rt_amp_add_device_props(sdw_dev1
);
293 put_device(sdw_dev1
);
296 ctx
->amp_dev1
= sdw_dev1
;
298 sdw_dev2
= bus_find_device_by_name(&sdw_bus_type
, NULL
, dai_links
->codecs
[1].name
);
300 return -EPROBE_DEFER
;
302 ret
= rt_amp_add_device_props(sdw_dev2
);
304 put_device(sdw_dev2
);
307 ctx
->amp_dev2
= sdw_dev2
;
312 EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_init
, "SND_SOC_SDW_UTILS");