1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
4 //
5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7 //
8
9 #include <linux/acpi.h>
10 #include <linux/module.h>
11 #include <linux/dmi.h>
12 #include <linux/pci.h>
13 #include <linux/platform_device.h>
14 #include <sound/hda_codec.h>
15 #include <sound/hda_register.h>
16 #include <sound/intel-nhlt.h>
17 #include <sound/soc-acpi.h>
18 #include <sound/soc-component.h>
19 #include "avs.h"
20
21 static bool i2s_test;
22 module_param(i2s_test, bool, 0444);
23 MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
24
25 static const struct dmi_system_id kbl_dmi_table[] = {
26 {
27 .matches = {
28 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
29 DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
30 },
31 },
32 {}
33 };
34
35 static const struct dmi_system_id kblr_dmi_table[] = {
36 {
37 .matches = {
38 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
39 DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
40 },
41 },
42 {}
43 };
44
dmi_match_quirk(void * arg)45 static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
46 {
47 struct snd_soc_acpi_mach *mach = arg;
48 const struct dmi_system_id *dmi_id;
49 struct dmi_system_id *dmi_table;
50
51 if (mach->quirk_data == NULL)
52 return mach;
53
54 dmi_table = (struct dmi_system_id *)mach->quirk_data;
55
56 dmi_id = dmi_first_match(dmi_table);
57 if (!dmi_id)
58 return NULL;
59
60 return mach;
61 }
62
63 #define AVS_SSP(x) (BIT(x))
64 #define AVS_SSP_RANGE(a, b) (GENMASK(b, a))
65
66 /* supported I2S board codec configurations */
67 static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {
68 {
69 .id = "INT343A",
70 .drv_name = "avs_rt286",
71 .mach_params = {
72 .i2s_link_mask = AVS_SSP(0),
73 },
74 .tplg_filename = "rt286-tplg.bin",
75 },
76 {
77 .id = "10508825",
78 .drv_name = "avs_nau8825",
79 .mach_params = {
80 .i2s_link_mask = AVS_SSP(1),
81 },
82 .tplg_filename = "nau8825-tplg.bin",
83 },
84 {
85 .id = "INT343B",
86 .drv_name = "avs_ssm4567",
87 .mach_params = {
88 .i2s_link_mask = AVS_SSP(0),
89 },
90 .tplg_filename = "ssm4567-tplg.bin",
91 },
92 {
93 .id = "MX98357A",
94 .drv_name = "avs_max98357a",
95 .mach_params = {
96 .i2s_link_mask = AVS_SSP(0),
97 },
98 .tplg_filename = "max98357a-tplg.bin",
99 },
100 {},
101 };
102
103 static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
104 {
105 .id = "INT343A",
106 .drv_name = "avs_rt286",
107 .mach_params = {
108 .i2s_link_mask = AVS_SSP(0),
109 },
110 .quirk_data = &kbl_dmi_table,
111 .machine_quirk = dmi_match_quirk,
112 .tplg_filename = "rt286-tplg.bin",
113 },
114 {
115 .id = "INT343A",
116 .drv_name = "avs_rt298",
117 .mach_params = {
118 .i2s_link_mask = AVS_SSP(0),
119 },
120 .quirk_data = &kblr_dmi_table,
121 .machine_quirk = dmi_match_quirk,
122 .tplg_filename = "rt298-tplg.bin",
123 },
124 {
125 .id = "MX98373",
126 .drv_name = "avs_max98373",
127 .mach_params = {
128 .i2s_link_mask = AVS_SSP(0),
129 },
130 .tplg_filename = "max98373-tplg.bin",
131 },
132 {
133 .id = "DLGS7219",
134 .drv_name = "avs_da7219",
135 .mach_params = {
136 .i2s_link_mask = AVS_SSP(1),
137 },
138 .tplg_filename = "da7219-tplg.bin",
139 },
140 {},
141 };
142
143 static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
144 {
145 .id = "INT343A",
146 .drv_name = "avs_rt298",
147 .mach_params = {
148 .i2s_link_mask = AVS_SSP(5),
149 },
150 .tplg_filename = "rt298-tplg.bin",
151 },
152 {
153 .id = "INT34C3",
154 .drv_name = "avs_tdf8532",
155 .mach_params = {
156 .i2s_link_mask = AVS_SSP_RANGE(0, 5),
157 },
158 .pdata = (unsigned long[]){ 0, 0, 0x14, 0, 0, 0 }, /* SSP2 TDMs */
159 .tplg_filename = "tdf8532-tplg.bin",
160 },
161 {
162 .id = "MX98357A",
163 .drv_name = "avs_max98357a",
164 .mach_params = {
165 .i2s_link_mask = AVS_SSP(5),
166 },
167 .tplg_filename = "max98357a-tplg.bin",
168 },
169 {
170 .id = "DLGS7219",
171 .drv_name = "avs_da7219",
172 .mach_params = {
173 .i2s_link_mask = AVS_SSP(1),
174 },
175 .tplg_filename = "da7219-tplg.bin",
176 },
177 {},
178 };
179
180 static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
181 {
182 .id = "INT343A",
183 .drv_name = "avs_rt298",
184 .mach_params = {
185 .i2s_link_mask = AVS_SSP(2),
186 },
187 .tplg_filename = "rt298-tplg.bin",
188 },
189 {},
190 };
191
192 static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
193 {
194 .drv_name = "avs_i2s_test",
195 .mach_params = {
196 .i2s_link_mask = AVS_SSP(0),
197 },
198 .tplg_filename = "i2s-test-tplg.bin",
199 },
200 {
201 .drv_name = "avs_i2s_test",
202 .mach_params = {
203 .i2s_link_mask = AVS_SSP(1),
204 },
205 .tplg_filename = "i2s-test-tplg.bin",
206 },
207 {
208 .drv_name = "avs_i2s_test",
209 .mach_params = {
210 .i2s_link_mask = AVS_SSP(2),
211 },
212 .tplg_filename = "i2s-test-tplg.bin",
213 },
214 {
215 .drv_name = "avs_i2s_test",
216 .mach_params = {
217 .i2s_link_mask = AVS_SSP(3),
218 },
219 .tplg_filename = "i2s-test-tplg.bin",
220 },
221 {
222 .drv_name = "avs_i2s_test",
223 .mach_params = {
224 .i2s_link_mask = AVS_SSP(4),
225 },
226 .tplg_filename = "i2s-test-tplg.bin",
227 },
228 {
229 .drv_name = "avs_i2s_test",
230 .mach_params = {
231 .i2s_link_mask = AVS_SSP(5),
232 },
233 .tplg_filename = "i2s-test-tplg.bin",
234 },
235 /* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */
236 };
237
238 struct avs_acpi_boards {
239 int id;
240 struct snd_soc_acpi_mach *machs;
241 };
242
243 #define AVS_MACH_ENTRY(_id, _mach) \
244 { .id = (_id), .machs = (_mach), }
245
246 /* supported I2S boards per platform */
247 static const struct avs_acpi_boards i2s_boards[] = {
248 AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */
249 AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */
250 AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */
251 AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */
252 {},
253 };
254
avs_get_i2s_boards(struct avs_dev * adev)255 static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
256 {
257 int id, i;
258
259 id = adev->base.pci->device;
260 for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
261 if (i2s_boards[i].id == id)
262 return &i2s_boards[i];
263 return NULL;
264 }
265
266 /* platform devices owned by AVS audio are removed with this hook */
board_pdev_unregister(void * data)267 static void board_pdev_unregister(void *data)
268 {
269 platform_device_unregister(data);
270 }
271
avs_register_dmic_board(struct avs_dev * adev)272 static int avs_register_dmic_board(struct avs_dev *adev)
273 {
274 struct platform_device *codec, *board;
275 struct snd_soc_acpi_mach mach = {{0}};
276 int ret;
277
278 if (!adev->nhlt ||
279 !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_DMIC)) {
280 dev_dbg(adev->dev, "no DMIC endpoints present\n");
281 return 0;
282 }
283
284 codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
285 if (IS_ERR(codec)) {
286 dev_err(adev->dev, "dmic codec register failed\n");
287 return PTR_ERR(codec);
288 }
289
290 ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
291 if (ret < 0) {
292 platform_device_unregister(codec);
293 return ret;
294 }
295
296 ret = avs_dmic_platform_register(adev, "dmic-platform");
297 if (ret < 0)
298 return ret;
299
300 mach.tplg_filename = "dmic-tplg.bin";
301 mach.mach_params.platform = "dmic-platform";
302
303 board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
304 (const void *)&mach, sizeof(mach));
305 if (IS_ERR(board)) {
306 dev_err(adev->dev, "dmic board register failed\n");
307 return PTR_ERR(board);
308 }
309
310 ret = devm_add_action(adev->dev, board_pdev_unregister, board);
311 if (ret < 0) {
312 platform_device_unregister(board);
313 return ret;
314 }
315
316 return 0;
317 }
318
avs_register_i2s_board(struct avs_dev * adev,struct snd_soc_acpi_mach * mach)319 static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
320 {
321 struct platform_device *board;
322 int num_ssps;
323 char *name;
324 int ret;
325
326 num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
327 if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
328 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
329 num_ssps, mach->drv_name,
330 (unsigned long)__fls(mach->mach_params.i2s_link_mask));
331 return -ENODEV;
332 }
333
334 name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
335 mach->mach_params.i2s_link_mask);
336 if (!name)
337 return -ENOMEM;
338
339 ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
340 if (ret < 0)
341 return ret;
342
343 mach->mach_params.platform = name;
344
345 board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
346 (const void *)mach, sizeof(*mach));
347 if (IS_ERR(board)) {
348 dev_err(adev->dev, "ssp board register failed\n");
349 return PTR_ERR(board);
350 }
351
352 ret = devm_add_action(adev->dev, board_pdev_unregister, board);
353 if (ret < 0) {
354 platform_device_unregister(board);
355 return ret;
356 }
357
358 return 0;
359 }
360
avs_register_i2s_boards(struct avs_dev * adev)361 static int avs_register_i2s_boards(struct avs_dev *adev)
362 {
363 const struct avs_acpi_boards *boards;
364 struct snd_soc_acpi_mach *mach;
365 int ret;
366
367 if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) {
368 dev_dbg(adev->dev, "no I2S endpoints present\n");
369 return 0;
370 }
371
372 if (i2s_test) {
373 int i, num_ssps;
374
375 num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
376 /* constrain just in case FW says there can be more SSPs than possible */
377 num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
378
379 mach = avs_test_i2s_machines;
380
381 for (i = 0; i < num_ssps; i++) {
382 ret = avs_register_i2s_board(adev, &mach[i]);
383 if (ret < 0)
384 dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
385 ret);
386 }
387 return 0;
388 }
389
390 boards = avs_get_i2s_boards(adev);
391 if (!boards) {
392 dev_dbg(adev->dev, "no I2S endpoints supported\n");
393 return 0;
394 }
395
396 for (mach = boards->machs; mach->id[0]; mach++) {
397 if (!acpi_dev_present(mach->id, NULL, -1))
398 continue;
399
400 if (mach->machine_quirk)
401 if (!mach->machine_quirk(mach))
402 continue;
403
404 ret = avs_register_i2s_board(adev, mach);
405 if (ret < 0)
406 dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
407 }
408
409 return 0;
410 }
411
avs_register_hda_board(struct avs_dev * adev,struct hda_codec * codec)412 static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
413 {
414 struct snd_soc_acpi_mach mach = {{0}};
415 struct platform_device *board;
416 struct hdac_device *hdev = &codec->core;
417 char *pname;
418 int ret, id;
419
420 pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
421 if (!pname)
422 return -ENOMEM;
423
424 ret = avs_hda_platform_register(adev, pname);
425 if (ret < 0)
426 return ret;
427
428 mach.pdata = codec;
429 mach.mach_params.platform = pname;
430 mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
431 hdev->vendor_id);
432 if (!mach.tplg_filename)
433 return -ENOMEM;
434
435 id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
436 board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
437 sizeof(mach));
438 if (IS_ERR(board)) {
439 dev_err(adev->dev, "hda board register failed\n");
440 return PTR_ERR(board);
441 }
442
443 ret = devm_add_action(adev->dev, board_pdev_unregister, board);
444 if (ret < 0) {
445 platform_device_unregister(board);
446 return ret;
447 }
448
449 return 0;
450 }
451
avs_register_hda_boards(struct avs_dev * adev)452 static int avs_register_hda_boards(struct avs_dev *adev)
453 {
454 struct hdac_bus *bus = &adev->base.core;
455 struct hdac_device *hdev;
456 int ret;
457
458 if (!bus->num_codecs) {
459 dev_dbg(adev->dev, "no HDA endpoints present\n");
460 return 0;
461 }
462
463 list_for_each_entry(hdev, &bus->codec_list, list) {
464 struct hda_codec *codec;
465
466 codec = dev_to_hda_codec(&hdev->dev);
467
468 ret = avs_register_hda_board(adev, codec);
469 if (ret < 0)
470 dev_warn(adev->dev, "register hda-%08x failed: %d\n",
471 codec->core.vendor_id, ret);
472 }
473
474 return 0;
475 }
476
avs_register_all_boards(struct avs_dev * adev)477 int avs_register_all_boards(struct avs_dev *adev)
478 {
479 int ret;
480
481 ret = avs_register_dmic_board(adev);
482 if (ret < 0)
483 dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
484 ret);
485
486 ret = avs_register_i2s_boards(adev);
487 if (ret < 0)
488 dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
489 ret);
490
491 ret = avs_register_hda_boards(adev);
492 if (ret < 0)
493 dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
494 ret);
495
496 return 0;
497 }
498
avs_unregister_all_boards(struct avs_dev * adev)499 void avs_unregister_all_boards(struct avs_dev *adev)
500 {
501 snd_soc_unregister_component(adev->dev);
502 }
503