~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/boards/sof_sdw.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 // Copyright (c) 2020 Intel Corporation
  3 
  4 /*
  5  *  sof_sdw - ASOC Machine driver for Intel SoundWire platforms
  6  */
  7 
  8 #include <linux/bitmap.h>
  9 #include <linux/device.h>
 10 #include <linux/dmi.h>
 11 #include <linux/module.h>
 12 #include <linux/soundwire/sdw.h>
 13 #include <linux/soundwire/sdw_type.h>
 14 #include <sound/soc.h>
 15 #include <sound/soc-acpi.h>
 16 #include "sof_sdw_common.h"
 17 #include "../../codecs/rt711.h"
 18 
 19 unsigned long sof_sdw_quirk = RT711_JD1;
 20 static int quirk_override = -1;
 21 module_param_named(quirk, quirk_override, int, 0444);
 22 MODULE_PARM_DESC(quirk, "Board-specific quirk override");
 23 
 24 static void log_quirks(struct device *dev)
 25 {
 26         if (SOF_JACK_JDSRC(sof_sdw_quirk))
 27                 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
 28                         SOF_JACK_JDSRC(sof_sdw_quirk));
 29         if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
 30                 dev_err(dev, "quirk SOF_SDW_FOUR_SPK enabled but no longer supported\n");
 31         if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
 32                 dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
 33         if (sof_sdw_quirk & SOF_SDW_PCH_DMIC)
 34                 dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n");
 35         if (SOF_SSP_GET_PORT(sof_sdw_quirk))
 36                 dev_dbg(dev, "SSP port %ld\n",
 37                         SOF_SSP_GET_PORT(sof_sdw_quirk));
 38         if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
 39                 dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n");
 40         if (sof_sdw_quirk & SOF_CODEC_SPKR)
 41                 dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n");
 42         if (sof_sdw_quirk & SOF_SIDECAR_AMPS)
 43                 dev_dbg(dev, "quirk SOF_SIDECAR_AMPS enabled\n");
 44 }
 45 
 46 static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
 47 {
 48         sof_sdw_quirk = (unsigned long)id->driver_data;
 49         return 1;
 50 }
 51 
 52 static const struct dmi_system_id sof_sdw_quirk_table[] = {
 53         /* CometLake devices */
 54         {
 55                 .callback = sof_sdw_quirk_cb,
 56                 .matches = {
 57                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 58                         DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
 59                 },
 60                 .driver_data = (void *)SOF_SDW_PCH_DMIC,
 61         },
 62         {
 63                 .callback = sof_sdw_quirk_cb,
 64                 .matches = {
 65                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 66                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
 67                 },
 68                 .driver_data = (void *)RT711_JD2,
 69         },
 70         {
 71                 /* early version of SKU 09C6 */
 72                 .callback = sof_sdw_quirk_cb,
 73                 .matches = {
 74                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 75                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
 76                 },
 77                 .driver_data = (void *)RT711_JD2,
 78         },
 79         {
 80                 .callback = sof_sdw_quirk_cb,
 81                 .matches = {
 82                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 83                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
 84                 },
 85                 .driver_data = (void *)(RT711_JD2),
 86         },
 87         {
 88                 .callback = sof_sdw_quirk_cb,
 89                 .matches = {
 90                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 91                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
 92                 },
 93                 .driver_data = (void *)(RT711_JD2),
 94         },
 95         /* IceLake devices */
 96         {
 97                 .callback = sof_sdw_quirk_cb,
 98                 .matches = {
 99                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
100                         DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
101                 },
102                 .driver_data = (void *)SOF_SDW_PCH_DMIC,
103         },
104         /* TigerLake devices */
105         {
106                 .callback = sof_sdw_quirk_cb,
107                 .matches = {
108                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
109                         DMI_MATCH(DMI_PRODUCT_NAME,
110                                   "Tiger Lake Client Platform"),
111                 },
112                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
113                                         RT711_JD1 |
114                                         SOF_SDW_PCH_DMIC |
115                                         SOF_SSP_PORT(SOF_I2S_SSP2)),
116         },
117         {
118                 .callback = sof_sdw_quirk_cb,
119                 .matches = {
120                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
121                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
122                 },
123                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
124                                         RT711_JD2),
125         },
126         {
127                 /* another SKU of Dell Latitude 9520 */
128                 .callback = sof_sdw_quirk_cb,
129                 .matches = {
130                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
131                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
132                 },
133                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
134                                         RT711_JD2),
135         },
136         {
137                 /* Dell XPS 9710 */
138                 .callback = sof_sdw_quirk_cb,
139                 .matches = {
140                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
141                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
142                 },
143                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
144                                         RT711_JD2),
145         },
146         {
147                 .callback = sof_sdw_quirk_cb,
148                 .matches = {
149                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
150                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
151                 },
152                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
153                                         RT711_JD2),
154         },
155         {
156                 .callback = sof_sdw_quirk_cb,
157                 .matches = {
158                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
159                         DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
160                 },
161                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
162                                         SOF_SDW_PCH_DMIC |
163                                         SOF_BT_OFFLOAD_SSP(2) |
164                                         SOF_SSP_BT_OFFLOAD_PRESENT),
165         },
166         {
167                 .callback = sof_sdw_quirk_cb,
168                 .matches = {
169                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
170                         DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
171                 },
172                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
173                                         SOF_SDW_PCH_DMIC),
174         },
175         {
176                 /*
177                  * this entry covers multiple HP SKUs. The family name
178                  * does not seem robust enough, so we use a partial
179                  * match that ignores the product name suffix
180                  * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
181                  */
182                 .callback = sof_sdw_quirk_cb,
183                 .matches = {
184                         DMI_MATCH(DMI_SYS_VENDOR, "HP"),
185                         DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
186                 },
187                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
188                                         SOF_SDW_PCH_DMIC |
189                                         RT711_JD1),
190         },
191         {
192                 /*
193                  * this entry covers HP Spectre x360 where the DMI information
194                  * changed somehow
195                  */
196                 .callback = sof_sdw_quirk_cb,
197                 .matches = {
198                         DMI_MATCH(DMI_SYS_VENDOR, "HP"),
199                         DMI_MATCH(DMI_BOARD_NAME, "8709"),
200                 },
201                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
202                                         SOF_SDW_PCH_DMIC |
203                                         RT711_JD1),
204         },
205         {
206                 /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
207                 .callback = sof_sdw_quirk_cb,
208                 .matches = {
209                         DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
210                         DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
211                 },
212                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
213                                         SOF_SDW_PCH_DMIC |
214                                         RT711_JD1),
215         },
216         {
217                 /* NUC15 LAPBC710 skews */
218                 .callback = sof_sdw_quirk_cb,
219                 .matches = {
220                         DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
221                         DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
222                 },
223                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
224                                         SOF_SDW_PCH_DMIC |
225                                         RT711_JD1),
226         },
227         {
228                 /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
229                 .callback = sof_sdw_quirk_cb,
230                 .matches = {
231                         DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
232                         DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
233                 },
234                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
235                                         SOF_SDW_PCH_DMIC |
236                                         RT711_JD2_100K),
237         },
238         {
239                 /* NUC15 LAPRC710 skews */
240                 .callback = sof_sdw_quirk_cb,
241                 .matches = {
242                         DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
243                         DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
244                 },
245                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
246                                         SOF_SDW_PCH_DMIC |
247                                         RT711_JD2_100K),
248         },
249         /* TigerLake-SDCA devices */
250         {
251                 .callback = sof_sdw_quirk_cb,
252                 .matches = {
253                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
254                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
255                 },
256                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
257                                         RT711_JD2),
258         },
259         {
260                 .callback = sof_sdw_quirk_cb,
261                 .matches = {
262                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
263                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
264                 },
265                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
266                                         RT711_JD2),
267         },
268         /* AlderLake devices */
269         {
270                 .callback = sof_sdw_quirk_cb,
271                 .matches = {
272                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
273                         DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
274                 },
275                 .driver_data = (void *)(RT711_JD2_100K |
276                                         SOF_SDW_TGL_HDMI |
277                                         SOF_BT_OFFLOAD_SSP(2) |
278                                         SOF_SSP_BT_OFFLOAD_PRESENT),
279         },
280         {
281                 .callback = sof_sdw_quirk_cb,
282                 .matches = {
283                         DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
284                         DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"),
285                 },
286                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
287                                         RT711_JD2_100K),
288         },
289         {
290                 .callback = sof_sdw_quirk_cb,
291                 .matches = {
292                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
293                         DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
294                 },
295                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
296                                         SOF_SDW_PCH_DMIC |
297                                         SOF_BT_OFFLOAD_SSP(2) |
298                                         SOF_SSP_BT_OFFLOAD_PRESENT),
299         },
300         {
301                 .callback = sof_sdw_quirk_cb,
302                 .matches = {
303                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
304                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
305                 },
306                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
307                                         RT711_JD2),
308         },
309         {
310                 .callback = sof_sdw_quirk_cb,
311                 .matches = {
312                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
313                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
314                 },
315                 /* No Jack */
316                 .driver_data = (void *)(SOF_SDW_TGL_HDMI),
317         },
318         {
319                 .callback = sof_sdw_quirk_cb,
320                 .matches = {
321                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
322                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
323                 },
324                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
325                                         RT711_JD2),
326         },
327         {
328                 .callback = sof_sdw_quirk_cb,
329                 .matches = {
330                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
331                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
332                 },
333                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
334                                         RT711_JD2),
335         },
336         {
337                 .callback = sof_sdw_quirk_cb,
338                 .matches = {
339                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
340                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
341                 },
342                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
343                                         RT711_JD2),
344         },
345         {
346                 .callback = sof_sdw_quirk_cb,
347                 .matches = {
348                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
349                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
350                 },
351                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
352                                         RT711_JD2),
353         },
354         {
355                 .callback = sof_sdw_quirk_cb,
356                 .matches = {
357                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
358                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
359                 },
360                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
361                                         RT711_JD2),
362         },
363         {
364                 .callback = sof_sdw_quirk_cb,
365                 .matches = {
366                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
367                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
368                 },
369                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
370                                         RT711_JD2),
371         },
372         {
373                 .callback = sof_sdw_quirk_cb,
374                 .matches = {
375                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
376                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
377                 },
378                 /* No Jack */
379                 .driver_data = (void *)SOF_SDW_TGL_HDMI,
380         },
381         {
382                 .callback = sof_sdw_quirk_cb,
383                 .matches = {
384                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
385                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
386                 },
387                 /* No Jack */
388                 .driver_data = (void *)SOF_SDW_TGL_HDMI,
389         },
390 
391         {
392                 .callback = sof_sdw_quirk_cb,
393                 .matches = {
394                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
395                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
396                 },
397                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
398                                         RT711_JD2),
399         },
400         {
401                 .callback = sof_sdw_quirk_cb,
402                 .matches = {
403                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
404                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"),
405                 },
406                 /* No Jack */
407                 .driver_data = (void *)SOF_SDW_TGL_HDMI,
408         },
409         {
410                 .callback = sof_sdw_quirk_cb,
411                 .matches = {
412                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
413                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"),
414                 },
415                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
416                                         RT711_JD2),
417         },
418         {
419                 .callback = sof_sdw_quirk_cb,
420                 .matches = {
421                         DMI_MATCH(DMI_SYS_VENDOR, "HP"),
422                         DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"),
423                 },
424                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
425                                         RT711_JD2),
426         },
427         /* RaptorLake devices */
428         {
429                 .callback = sof_sdw_quirk_cb,
430                 .matches = {
431                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
432                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")
433                 },
434                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
435                                         RT711_JD2),
436         },
437         {
438                 .callback = sof_sdw_quirk_cb,
439                 .matches = {
440                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
441                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F")
442                 },
443                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
444                                         RT711_JD2),
445         },
446         {
447                 .callback = sof_sdw_quirk_cb,
448                 .matches = {
449                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
450                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
451                 },
452                 /* No Jack */
453                 .driver_data = (void *)(SOF_SDW_TGL_HDMI),
454         },
455         {
456                 .callback = sof_sdw_quirk_cb,
457                 .matches = {
458                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
459                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
460                 },
461                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
462                                         RT711_JD2),
463         },
464         {
465                 .callback = sof_sdw_quirk_cb,
466                 .matches = {
467                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
468                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
469                 },
470                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
471                                         RT711_JD2),
472         },
473         {
474                 .callback = sof_sdw_quirk_cb,
475                 .matches = {
476                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
477                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
478                 },
479                 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
480                                         RT711_JD2),
481         },
482         /* MeteorLake devices */
483         {
484                 .callback = sof_sdw_quirk_cb,
485                 .matches = {
486                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
487                 },
488                 .driver_data = (void *)(RT711_JD1),
489         },
490         {
491                 .callback = sof_sdw_quirk_cb,
492                 .matches = {
493                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
494                         DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"),
495                 },
496                 .driver_data = (void *)(RT711_JD2_100K),
497         },
498         {
499                 .callback = sof_sdw_quirk_cb,
500                 .matches = {
501                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
502                         DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
503                 },
504                 .driver_data = (void *)(SOF_SDW_PCH_DMIC |
505                                         SOF_BT_OFFLOAD_SSP(1) |
506                                         SOF_SSP_BT_OFFLOAD_PRESENT),
507         },
508         {
509                 .callback = sof_sdw_quirk_cb,
510                 .matches = {
511                         DMI_MATCH(DMI_SYS_VENDOR, "HP"),
512                         DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"),
513                 },
514                 .driver_data = (void *)(RT711_JD2),
515         },
516 
517         /* LunarLake devices */
518         {
519                 .callback = sof_sdw_quirk_cb,
520                 .matches = {
521                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
522                         DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
523                 },
524                 .driver_data = (void *)(RT711_JD2),
525         },
526         {
527                 .callback = sof_sdw_quirk_cb,
528                 .matches = {
529                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
530                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3")
531                 },
532                 .driver_data = (void *)(SOF_SIDECAR_AMPS),
533         },
534         {
535                 .callback = sof_sdw_quirk_cb,
536                 .matches = {
537                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
538                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4")
539                 },
540                 .driver_data = (void *)(SOF_SIDECAR_AMPS),
541         },
542         {}
543 };
544 
545 static struct snd_soc_dai_link_component platform_component[] = {
546         {
547                 /* name might be overridden during probe */
548                 .name = "0000:00:1f.3"
549         }
550 };
551 
552 static const struct snd_soc_dapm_widget generic_dmic_widgets[] = {
553         SND_SOC_DAPM_MIC("DMIC", NULL),
554 };
555 
556 static const struct snd_soc_dapm_widget generic_jack_widgets[] = {
557         SND_SOC_DAPM_HP("Headphone", NULL),
558         SND_SOC_DAPM_MIC("Headset Mic", NULL),
559 };
560 
561 static const struct snd_kcontrol_new generic_jack_controls[] = {
562         SOC_DAPM_PIN_SWITCH("Headphone"),
563         SOC_DAPM_PIN_SWITCH("Headset Mic"),
564 };
565 
566 static const struct snd_soc_dapm_widget generic_spk_widgets[] = {
567         SND_SOC_DAPM_SPK("Speaker", NULL),
568 };
569 
570 static const struct snd_kcontrol_new generic_spk_controls[] = {
571         SOC_DAPM_PIN_SWITCH("Speaker"),
572 };
573 
574 static const struct snd_soc_dapm_widget maxim_widgets[] = {
575         SND_SOC_DAPM_SPK("Left Spk", NULL),
576         SND_SOC_DAPM_SPK("Right Spk", NULL),
577 };
578 
579 static const struct snd_kcontrol_new maxim_controls[] = {
580         SOC_DAPM_PIN_SWITCH("Left Spk"),
581         SOC_DAPM_PIN_SWITCH("Right Spk"),
582 };
583 
584 static const struct snd_soc_dapm_widget rt700_widgets[] = {
585         SND_SOC_DAPM_HP("Headphones", NULL),
586         SND_SOC_DAPM_MIC("AMIC", NULL),
587         SND_SOC_DAPM_SPK("Speaker", NULL),
588 };
589 
590 static const struct snd_kcontrol_new rt700_controls[] = {
591         SOC_DAPM_PIN_SWITCH("Headphones"),
592         SOC_DAPM_PIN_SWITCH("AMIC"),
593         SOC_DAPM_PIN_SWITCH("Speaker"),
594 };
595 
596 /* these wrappers are only needed to avoid typecast compilation errors */
597 int sdw_startup(struct snd_pcm_substream *substream)
598 {
599         return sdw_startup_stream(substream);
600 }
601 
602 int sdw_prepare(struct snd_pcm_substream *substream)
603 {
604         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
605         struct sdw_stream_runtime *sdw_stream;
606         struct snd_soc_dai *dai;
607 
608         /* Find stream from first CPU DAI */
609         dai = snd_soc_rtd_to_cpu(rtd, 0);
610 
611         sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
612         if (IS_ERR(sdw_stream)) {
613                 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
614                 return PTR_ERR(sdw_stream);
615         }
616 
617         return sdw_prepare_stream(sdw_stream);
618 }
619 
620 int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
621 {
622         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
623         struct sdw_stream_runtime *sdw_stream;
624         struct snd_soc_dai *dai;
625         int ret;
626 
627         /* Find stream from first CPU DAI */
628         dai = snd_soc_rtd_to_cpu(rtd, 0);
629 
630         sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
631         if (IS_ERR(sdw_stream)) {
632                 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
633                 return PTR_ERR(sdw_stream);
634         }
635 
636         switch (cmd) {
637         case SNDRV_PCM_TRIGGER_START:
638         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
639         case SNDRV_PCM_TRIGGER_RESUME:
640                 ret = sdw_enable_stream(sdw_stream);
641                 break;
642 
643         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
644         case SNDRV_PCM_TRIGGER_SUSPEND:
645         case SNDRV_PCM_TRIGGER_STOP:
646                 ret = sdw_disable_stream(sdw_stream);
647                 break;
648         default:
649                 ret = -EINVAL;
650                 break;
651         }
652 
653         if (ret)
654                 dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
655 
656         return ret;
657 }
658 
659 int sdw_hw_params(struct snd_pcm_substream *substream,
660                   struct snd_pcm_hw_params *params)
661 {
662         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
663         struct snd_soc_dai_link_ch_map *ch_maps;
664         int ch = params_channels(params);
665         unsigned int ch_mask;
666         int num_codecs;
667         int step;
668         int i;
669 
670         if (!rtd->dai_link->ch_maps)
671                 return 0;
672 
673         /* Identical data will be sent to all codecs in playback */
674         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
675                 ch_mask = GENMASK(ch - 1, 0);
676                 step = 0;
677         } else {
678                 num_codecs = rtd->dai_link->num_codecs;
679 
680                 if (ch < num_codecs || ch % num_codecs != 0) {
681                         dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
682                                 ch, num_codecs);
683                         return -EINVAL;
684                 }
685 
686                 ch_mask = GENMASK(ch / num_codecs - 1, 0);
687                 step = hweight_long(ch_mask);
688 
689         }
690 
691         /*
692          * The captured data will be combined from each cpu DAI if the dai
693          * link has more than one codec DAIs. Set codec channel mask and
694          * ASoC will set the corresponding channel numbers for each cpu dai.
695          */
696         for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
697                 ch_maps->ch_mask = ch_mask << (i * step);
698 
699         return 0;
700 }
701 
702 int sdw_hw_free(struct snd_pcm_substream *substream)
703 {
704         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
705         struct sdw_stream_runtime *sdw_stream;
706         struct snd_soc_dai *dai;
707 
708         /* Find stream from first CPU DAI */
709         dai = snd_soc_rtd_to_cpu(rtd, 0);
710 
711         sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
712         if (IS_ERR(sdw_stream)) {
713                 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
714                 return PTR_ERR(sdw_stream);
715         }
716 
717         return sdw_deprepare_stream(sdw_stream);
718 }
719 
720 void sdw_shutdown(struct snd_pcm_substream *substream)
721 {
722         sdw_shutdown_stream(substream);
723 }
724 
725 static const struct snd_soc_ops sdw_ops = {
726         .startup = sdw_startup,
727         .prepare = sdw_prepare,
728         .trigger = sdw_trigger,
729         .hw_params = sdw_hw_params,
730         .hw_free = sdw_hw_free,
731         .shutdown = sdw_shutdown,
732 };
733 
734 static struct sof_sdw_codec_info codec_info_list[] = {
735         {
736                 .part_id = 0x700,
737                 .dais = {
738                         {
739                                 .direction = {true, true},
740                                 .dai_name = "rt700-aif1",
741                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
742                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
743                                 .rtd_init = rt700_rtd_init,
744                                 .controls = rt700_controls,
745                                 .num_controls = ARRAY_SIZE(rt700_controls),
746                                 .widgets = rt700_widgets,
747                                 .num_widgets = ARRAY_SIZE(rt700_widgets),
748                         },
749                 },
750                 .dai_num = 1,
751         },
752         {
753                 .part_id = 0x711,
754                 .version_id = 3,
755                 .dais = {
756                         {
757                                 .direction = {true, true},
758                                 .dai_name = "rt711-sdca-aif1",
759                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
760                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
761                                 .init = sof_sdw_rt_sdca_jack_init,
762                                 .exit = sof_sdw_rt_sdca_jack_exit,
763                                 .rtd_init = rt_sdca_jack_rtd_init,
764                                 .controls = generic_jack_controls,
765                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
766                                 .widgets = generic_jack_widgets,
767                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
768                         },
769                 },
770                 .dai_num = 1,
771         },
772         {
773                 .part_id = 0x711,
774                 .version_id = 2,
775                 .dais = {
776                         {
777                                 .direction = {true, true},
778                                 .dai_name = "rt711-aif1",
779                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
780                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
781                                 .init = sof_sdw_rt711_init,
782                                 .exit = sof_sdw_rt711_exit,
783                                 .rtd_init = rt711_rtd_init,
784                                 .controls = generic_jack_controls,
785                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
786                                 .widgets = generic_jack_widgets,
787                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
788                         },
789                 },
790                 .dai_num = 1,
791         },
792         {
793                 .part_id = 0x712,
794                 .version_id = 3,
795                 .dais = {
796                         {
797                                 .direction = {true, true},
798                                 .dai_name = "rt712-sdca-aif1",
799                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
800                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
801                                 .init = sof_sdw_rt_sdca_jack_init,
802                                 .exit = sof_sdw_rt_sdca_jack_exit,
803                                 .rtd_init = rt_sdca_jack_rtd_init,
804                                 .controls = generic_jack_controls,
805                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
806                                 .widgets = generic_jack_widgets,
807                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
808                         },
809                         {
810                                 .direction = {true, false},
811                                 .dai_name = "rt712-sdca-aif2",
812                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
813                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
814                                 .init = sof_sdw_rt_amp_init,
815                                 .exit = sof_sdw_rt_amp_exit,
816                                 .rtd_init = rt712_spk_rtd_init,
817                                 .controls = generic_spk_controls,
818                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
819                                 .widgets = generic_spk_widgets,
820                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
821                         },
822                 },
823                 .dai_num = 2,
824         },
825         {
826                 .part_id = 0x1712,
827                 .version_id = 3,
828                 .dais = {
829                         {
830                                 .direction = {false, true},
831                                 .dai_name = "rt712-sdca-dmic-aif1",
832                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
833                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
834                                 .rtd_init = rt_dmic_rtd_init,
835                         },
836                 },
837                 .dai_num = 1,
838         },
839         {
840                 .part_id = 0x713,
841                 .version_id = 3,
842                 .dais = {
843                         {
844                                 .direction = {true, true},
845                                 .dai_name = "rt712-sdca-aif1",
846                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
847                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
848                                 .init = sof_sdw_rt_sdca_jack_init,
849                                 .exit = sof_sdw_rt_sdca_jack_exit,
850                                 .rtd_init = rt_sdca_jack_rtd_init,
851                                 .controls = generic_jack_controls,
852                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
853                                 .widgets = generic_jack_widgets,
854                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
855                         },
856                 },
857                 .dai_num = 1,
858         },
859         {
860                 .part_id = 0x1713,
861                 .version_id = 3,
862                 .dais = {
863                         {
864                                 .direction = {false, true},
865                                 .dai_name = "rt712-sdca-dmic-aif1",
866                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
867                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
868                                 .rtd_init = rt_dmic_rtd_init,
869                         },
870                 },
871                 .dai_num = 1,
872         },
873         {
874                 .part_id = 0x1308,
875                 .acpi_id = "10EC1308",
876                 .dais = {
877                         {
878                                 .direction = {true, false},
879                                 .dai_name = "rt1308-aif",
880                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
881                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
882                                 .init = sof_sdw_rt_amp_init,
883                                 .exit = sof_sdw_rt_amp_exit,
884                                 .rtd_init = rt_amp_spk_rtd_init,
885                                 .controls = generic_spk_controls,
886                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
887                                 .widgets = generic_spk_widgets,
888                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
889                         },
890                 },
891                 .dai_num = 1,
892                 .ops = &sof_sdw_rt1308_i2s_ops,
893         },
894         {
895                 .part_id = 0x1316,
896                 .dais = {
897                         {
898                                 .direction = {true, true},
899                                 .dai_name = "rt1316-aif",
900                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
901                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
902                                 .init = sof_sdw_rt_amp_init,
903                                 .exit = sof_sdw_rt_amp_exit,
904                                 .rtd_init = rt_amp_spk_rtd_init,
905                                 .controls = generic_spk_controls,
906                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
907                                 .widgets = generic_spk_widgets,
908                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
909                         },
910                 },
911                 .dai_num = 1,
912         },
913         {
914                 .part_id = 0x1318,
915                 .dais = {
916                         {
917                                 .direction = {true, true},
918                                 .dai_name = "rt1318-aif",
919                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
920                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
921                                 .init = sof_sdw_rt_amp_init,
922                                 .exit = sof_sdw_rt_amp_exit,
923                                 .rtd_init = rt_amp_spk_rtd_init,
924                                 .controls = generic_spk_controls,
925                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
926                                 .widgets = generic_spk_widgets,
927                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
928                         },
929                 },
930                 .dai_num = 1,
931         },
932         {
933                 .part_id = 0x714,
934                 .version_id = 3,
935                 .ignore_pch_dmic = true,
936                 .dais = {
937                         {
938                                 .direction = {false, true},
939                                 .dai_name = "rt715-sdca-aif2",
940                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
941                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
942                                 .rtd_init = rt_dmic_rtd_init,
943                         },
944                 },
945                 .dai_num = 1,
946         },
947         {
948                 .part_id = 0x715,
949                 .version_id = 3,
950                 .ignore_pch_dmic = true,
951                 .dais = {
952                         {
953                                 .direction = {false, true},
954                                 .dai_name = "rt715-sdca-aif2",
955                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
956                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
957                                 .rtd_init = rt_dmic_rtd_init,
958                         },
959                 },
960                 .dai_num = 1,
961         },
962         {
963                 .part_id = 0x714,
964                 .version_id = 2,
965                 .ignore_pch_dmic = true,
966                 .dais = {
967                         {
968                                 .direction = {false, true},
969                                 .dai_name = "rt715-aif2",
970                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
971                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
972                                 .rtd_init = rt_dmic_rtd_init,
973                         },
974                 },
975                 .dai_num = 1,
976         },
977         {
978                 .part_id = 0x715,
979                 .version_id = 2,
980                 .ignore_pch_dmic = true,
981                 .dais = {
982                         {
983                                 .direction = {false, true},
984                                 .dai_name = "rt715-aif2",
985                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
986                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
987                                 .rtd_init = rt_dmic_rtd_init,
988                         },
989                 },
990                 .dai_num = 1,
991         },
992         {
993                 .part_id = 0x722,
994                 .version_id = 3,
995                 .dais = {
996                         {
997                                 .direction = {true, true},
998                                 .dai_name = "rt722-sdca-aif1",
999                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1000                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
1001                                 .init = sof_sdw_rt_sdca_jack_init,
1002                                 .exit = sof_sdw_rt_sdca_jack_exit,
1003                                 .rtd_init = rt_sdca_jack_rtd_init,
1004                                 .controls = generic_jack_controls,
1005                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
1006                                 .widgets = generic_jack_widgets,
1007                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
1008                         },
1009                         {
1010                                 .direction = {true, false},
1011                                 .dai_name = "rt722-sdca-aif2",
1012                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
1013                                 /* No feedback capability is provided by rt722-sdca codec driver*/
1014                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
1015                                 .init = sof_sdw_rt_amp_init,
1016                                 .exit = sof_sdw_rt_amp_exit,
1017                                 .rtd_init = rt722_spk_rtd_init,
1018                                 .controls = generic_spk_controls,
1019                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
1020                                 .widgets = generic_spk_widgets,
1021                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
1022                         },
1023                         {
1024                                 .direction = {false, true},
1025                                 .dai_name = "rt722-sdca-aif3",
1026                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
1027                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
1028                                 .rtd_init = rt_dmic_rtd_init,
1029                         },
1030                 },
1031                 .dai_num = 3,
1032         },
1033         {
1034                 .part_id = 0x8373,
1035                 .dais = {
1036                         {
1037                                 .direction = {true, true},
1038                                 .dai_name = "max98373-aif1",
1039                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
1040                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
1041                                 .init = sof_sdw_maxim_init,
1042                                 .rtd_init = maxim_spk_rtd_init,
1043                                 .controls = maxim_controls,
1044                                 .num_controls = ARRAY_SIZE(maxim_controls),
1045                                 .widgets = maxim_widgets,
1046                                 .num_widgets = ARRAY_SIZE(maxim_widgets),
1047                         },
1048                 },
1049                 .dai_num = 1,
1050         },
1051         {
1052                 .part_id = 0x8363,
1053                 .dais = {
1054                         {
1055                                 .direction = {true, false},
1056                                 .dai_name = "max98363-aif1",
1057                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
1058                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
1059                                 .init = sof_sdw_maxim_init,
1060                                 .rtd_init = maxim_spk_rtd_init,
1061                                 .controls = maxim_controls,
1062                                 .num_controls = ARRAY_SIZE(maxim_controls),
1063                                 .widgets = maxim_widgets,
1064                                 .num_widgets = ARRAY_SIZE(maxim_widgets),
1065                         },
1066                 },
1067                 .dai_num = 1,
1068         },
1069         {
1070                 .part_id = 0x5682,
1071                 .dais = {
1072                         {
1073                                 .direction = {true, true},
1074                                 .dai_name = "rt5682-sdw",
1075                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1076                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
1077                                 .rtd_init = rt5682_rtd_init,
1078                                 .controls = generic_jack_controls,
1079                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
1080                                 .widgets = generic_jack_widgets,
1081                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
1082                         },
1083                 },
1084                 .dai_num = 1,
1085         },
1086         {
1087                 .part_id = 0x3556,
1088                 .dais = {
1089                         {
1090                                 .direction = {true, true},
1091                                 .dai_name = "cs35l56-sdw1",
1092                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
1093                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
1094                                 .init = sof_sdw_cs_amp_init,
1095                                 .rtd_init = cs_spk_rtd_init,
1096                                 .controls = generic_spk_controls,
1097                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
1098                                 .widgets = generic_spk_widgets,
1099                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
1100                         },
1101                 },
1102                 .dai_num = 1,
1103         },
1104         {
1105                 .part_id = 0x4242,
1106                 .dais = {
1107                         {
1108                                 .direction = {true, true},
1109                                 .dai_name = "cs42l42-sdw",
1110                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1111                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
1112                                 .rtd_init = cs42l42_rtd_init,
1113                                 .controls = generic_jack_controls,
1114                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
1115                                 .widgets = generic_jack_widgets,
1116                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
1117                         },
1118                 },
1119                 .dai_num = 1,
1120         },
1121         {
1122                 .part_id = 0x4243,
1123                 .codec_name = "cs42l43-codec",
1124                 .count_sidecar = bridge_cs35l56_count_sidecar,
1125                 .add_sidecar = bridge_cs35l56_add_sidecar,
1126                 .dais = {
1127                         {
1128                                 .direction = {true, false},
1129                                 .dai_name = "cs42l43-dp5",
1130                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1131                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
1132                                 .rtd_init = cs42l43_hs_rtd_init,
1133                                 .controls = generic_jack_controls,
1134                                 .num_controls = ARRAY_SIZE(generic_jack_controls),
1135                                 .widgets = generic_jack_widgets,
1136                                 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
1137                         },
1138                         {
1139                                 .direction = {false, true},
1140                                 .dai_name = "cs42l43-dp1",
1141                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
1142                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
1143                                 .rtd_init = cs42l43_dmic_rtd_init,
1144                                 .widgets = generic_dmic_widgets,
1145                                 .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
1146                         },
1147                         {
1148                                 .direction = {false, true},
1149                                 .dai_name = "cs42l43-dp2",
1150                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1151                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID},
1152                         },
1153                         {
1154                                 .direction = {true, false},
1155                                 .dai_name = "cs42l43-dp6",
1156                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
1157                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
1158                                 .init = sof_sdw_cs42l43_spk_init,
1159                                 .rtd_init = cs42l43_spk_rtd_init,
1160                                 .controls = generic_spk_controls,
1161                                 .num_controls = ARRAY_SIZE(generic_spk_controls),
1162                                 .widgets = generic_spk_widgets,
1163                                 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
1164                                 .quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS,
1165                         },
1166                 },
1167                 .dai_num = 4,
1168         },
1169         {
1170                 .part_id = 0xaaaa, /* generic codec mockup */
1171                 .version_id = 0,
1172                 .dais = {
1173                         {
1174                                 .direction = {true, true},
1175                                 .dai_name = "sdw-mockup-aif1",
1176                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1177                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
1178                         },
1179                 },
1180                 .dai_num = 1,
1181         },
1182         {
1183                 .part_id = 0xaa55, /* headset codec mockup */
1184                 .version_id = 0,
1185                 .dais = {
1186                         {
1187                                 .direction = {true, true},
1188                                 .dai_name = "sdw-mockup-aif1",
1189                                 .dai_type = SOF_SDW_DAI_TYPE_JACK,
1190                                 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
1191                         },
1192                 },
1193                 .dai_num = 1,
1194         },
1195         {
1196                 .part_id = 0x55aa, /* amplifier mockup */
1197                 .version_id = 0,
1198                 .dais = {
1199                         {
1200                                 .direction = {true, true},
1201                                 .dai_name = "sdw-mockup-aif1",
1202                                 .dai_type = SOF_SDW_DAI_TYPE_AMP,
1203                                 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
1204                         },
1205                 },
1206                 .dai_num = 1,
1207         },
1208         {
1209                 .part_id = 0x5555,
1210                 .version_id = 0,
1211                 .dais = {
1212                         {
1213                                 .dai_name = "sdw-mockup-aif1",
1214                                 .direction = {false, true},
1215                                 .dai_type = SOF_SDW_DAI_TYPE_MIC,
1216                                 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
1217                         },
1218                 },
1219                 .dai_num = 1,
1220         },
1221 };
1222 
1223 static struct sof_sdw_codec_info *find_codec_info_part(const u64 adr)
1224 {
1225         unsigned int part_id, sdw_version;
1226         int i;
1227 
1228         part_id = SDW_PART_ID(adr);
1229         sdw_version = SDW_VERSION(adr);
1230         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1231                 /*
1232                  * A codec info is for all sdw version with the part id if
1233                  * version_id is not specified in the codec info.
1234                  */
1235                 if (part_id == codec_info_list[i].part_id &&
1236                     (!codec_info_list[i].version_id ||
1237                      sdw_version == codec_info_list[i].version_id))
1238                         return &codec_info_list[i];
1239 
1240         return NULL;
1241 
1242 }
1243 
1244 static struct sof_sdw_codec_info *find_codec_info_acpi(const u8 *acpi_id)
1245 {
1246         int i;
1247 
1248         if (!acpi_id[0])
1249                 return NULL;
1250 
1251         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1252                 if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
1253                         return &codec_info_list[i];
1254 
1255         return NULL;
1256 }
1257 
1258 static struct sof_sdw_codec_info *find_codec_info_dai(const char *dai_name,
1259                                                       int *dai_index)
1260 {
1261         int i, j;
1262 
1263         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1264                 for (j = 0; j < codec_info_list[i].dai_num; j++) {
1265                         if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
1266                                 *dai_index = j;
1267                                 return &codec_info_list[i];
1268                         }
1269                 }
1270         }
1271 
1272         return NULL;
1273 }
1274 
1275 static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1276                           int *be_id, char *name, int playback, int capture,
1277                           struct snd_soc_dai_link_component *cpus, int cpus_num,
1278                           struct snd_soc_dai_link_component *codecs, int codecs_num,
1279                           int (*init)(struct snd_soc_pcm_runtime *rtd),
1280                           const struct snd_soc_ops *ops)
1281 {
1282         dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id);
1283         dai_links->id = (*be_id)++;
1284         dai_links->name = name;
1285         dai_links->platforms = platform_component;
1286         dai_links->num_platforms = ARRAY_SIZE(platform_component);
1287         dai_links->no_pcm = 1;
1288         dai_links->cpus = cpus;
1289         dai_links->num_cpus = cpus_num;
1290         dai_links->codecs = codecs;
1291         dai_links->num_codecs = codecs_num;
1292         dai_links->dpcm_playback = playback;
1293         dai_links->dpcm_capture = capture;
1294         dai_links->init = init;
1295         dai_links->ops = ops;
1296 }
1297 
1298 static int init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1299                                 int *be_id, char *name, int playback, int capture,
1300                                 const char *cpu_dai_name,
1301                                 const char *codec_name, const char *codec_dai_name,
1302                                 int (*init)(struct snd_soc_pcm_runtime *rtd),
1303                                 const struct snd_soc_ops *ops)
1304 {
1305         struct snd_soc_dai_link_component *dlc;
1306 
1307         /* Allocate two DLCs one for the CPU, one for the CODEC */
1308         dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL);
1309         if (!dlc || !name || !cpu_dai_name || !codec_name || !codec_dai_name)
1310                 return -ENOMEM;
1311 
1312         dlc[0].dai_name = cpu_dai_name;
1313 
1314         dlc[1].name = codec_name;
1315         dlc[1].dai_name = codec_dai_name;
1316 
1317         init_dai_link(dev, dai_links, be_id, name, playback, capture,
1318                       &dlc[0], 1, &dlc[1], 1, init, ops);
1319 
1320         return 0;
1321 }
1322 
1323 static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
1324                              unsigned int sdw_version,
1325                              unsigned int mfg_id,
1326                              unsigned int part_id,
1327                              unsigned int class_id,
1328                              int index_in_link)
1329 {
1330         int i;
1331 
1332         for (i = 0; i < adr_link->num_adr; i++) {
1333                 unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
1334                 u64 adr;
1335 
1336                 /* skip itself */
1337                 if (i == index_in_link)
1338                         continue;
1339 
1340                 adr = adr_link->adr_d[i].adr;
1341 
1342                 sdw1_version = SDW_VERSION(adr);
1343                 mfg1_id = SDW_MFG_ID(adr);
1344                 part1_id = SDW_PART_ID(adr);
1345                 class1_id = SDW_CLASS_ID(adr);
1346 
1347                 if (sdw_version == sdw1_version &&
1348                     mfg_id == mfg1_id &&
1349                     part_id == part1_id &&
1350                     class_id == class1_id)
1351                         return false;
1352         }
1353 
1354         return true;
1355 }
1356 
1357 static const char *get_codec_name(struct device *dev,
1358                                   const struct sof_sdw_codec_info *codec_info,
1359                                   const struct snd_soc_acpi_link_adr *adr_link,
1360                                   int adr_index)
1361 {
1362         u64 adr = adr_link->adr_d[adr_index].adr;
1363         unsigned int sdw_version = SDW_VERSION(adr);
1364         unsigned int link_id = SDW_DISCO_LINK_ID(adr);
1365         unsigned int unique_id = SDW_UNIQUE_ID(adr);
1366         unsigned int mfg_id = SDW_MFG_ID(adr);
1367         unsigned int part_id = SDW_PART_ID(adr);
1368         unsigned int class_id = SDW_CLASS_ID(adr);
1369 
1370         if (codec_info->codec_name)
1371                 return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL);
1372         else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
1373                                   class_id, adr_index))
1374                 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x",
1375                                       link_id, mfg_id, part_id, class_id);
1376         else
1377                 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x",
1378                                       link_id, mfg_id, part_id, class_id, unique_id);
1379 
1380         return NULL;
1381 }
1382 
1383 static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
1384 {
1385         struct snd_soc_card *card = rtd->card;
1386         struct sof_sdw_codec_info *codec_info;
1387         struct snd_soc_dai *dai;
1388         int dai_index;
1389         int ret;
1390         int i;
1391 
1392         for_each_rtd_codec_dais(rtd, i, dai) {
1393                 codec_info = find_codec_info_dai(dai->name, &dai_index);
1394                 if (!codec_info)
1395                         return -EINVAL;
1396 
1397                 /*
1398                  * A codec dai can be connected to different dai links for capture and playback,
1399                  * but we only need to call the rtd_init function once.
1400                  * The rtd_init for each codec dai is independent. So, the order of rtd_init
1401                  * doesn't matter.
1402                  */
1403                 if (codec_info->dais[dai_index].rtd_init_done)
1404                         continue;
1405 
1406                 /*
1407                  * Add card controls and dapm widgets for the first codec dai.
1408                  * The controls and widgets will be used for all codec dais.
1409                  */
1410 
1411                 if (i > 0)
1412                         goto skip_add_controls_widgets;
1413 
1414                 if (codec_info->dais[dai_index].controls) {
1415                         ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls,
1416                                                         codec_info->dais[dai_index].num_controls);
1417                         if (ret) {
1418                                 dev_err(card->dev, "%#x controls addition failed: %d\n",
1419                                         codec_info->part_id, ret);
1420                                 return ret;
1421                         }
1422                 }
1423                 if (codec_info->dais[dai_index].widgets) {
1424                         ret = snd_soc_dapm_new_controls(&card->dapm,
1425                                                         codec_info->dais[dai_index].widgets,
1426                                                         codec_info->dais[dai_index].num_widgets);
1427                         if (ret) {
1428                                 dev_err(card->dev, "%#x widgets addition failed: %d\n",
1429                                         codec_info->part_id, ret);
1430                                 return ret;
1431                         }
1432                 }
1433 
1434 skip_add_controls_widgets:
1435                 if (codec_info->dais[dai_index].rtd_init) {
1436                         ret = codec_info->dais[dai_index].rtd_init(rtd, dai);
1437                         if (ret)
1438                                 return ret;
1439                 }
1440                 codec_info->dais[dai_index].rtd_init_done = true;
1441         }
1442 
1443         return 0;
1444 }
1445 
1446 struct sof_sdw_endpoint {
1447         struct list_head list;
1448 
1449         u32 link_mask;
1450         const char *codec_name;
1451         const char *name_prefix;
1452         bool include_sidecar;
1453 
1454         struct sof_sdw_codec_info *codec_info;
1455         const struct sof_sdw_dai_info *dai_info;
1456 };
1457 
1458 struct sof_sdw_dailink {
1459         bool initialised;
1460 
1461         u8 group_id;
1462         u32 link_mask[SNDRV_PCM_STREAM_LAST + 1];
1463         int num_devs[SNDRV_PCM_STREAM_LAST + 1];
1464         struct list_head endpoints;
1465 };
1466 
1467 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
1468 
1469 static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends)
1470 {
1471         struct device *dev = card->dev;
1472         struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
1473         struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1474         const struct snd_soc_acpi_link_adr *adr_link;
1475         int i;
1476 
1477         for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
1478                 *num_devs += adr_link->num_adr;
1479 
1480                 for (i = 0; i < adr_link->num_adr; i++)
1481                         *num_ends += adr_link->adr_d[i].num_endpoints;
1482         }
1483 
1484         dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
1485 
1486         return 0;
1487 }
1488 
1489 static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks,
1490                                             const struct snd_soc_acpi_endpoint *new)
1491 {
1492         while (dailinks->initialised) {
1493                 if (new->aggregated && dailinks->group_id == new->group_id)
1494                         return dailinks;
1495 
1496                 dailinks++;
1497         }
1498 
1499         INIT_LIST_HEAD(&dailinks->endpoints);
1500         dailinks->group_id = new->group_id;
1501         dailinks->initialised = true;
1502 
1503         return dailinks;
1504 }
1505 
1506 static int parse_sdw_endpoints(struct snd_soc_card *card,
1507                                struct sof_sdw_dailink *sof_dais,
1508                                struct sof_sdw_endpoint *sof_ends,
1509                                int *num_devs)
1510 {
1511         struct device *dev = card->dev;
1512         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1513         struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
1514         struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1515         const struct snd_soc_acpi_link_adr *adr_link;
1516         struct sof_sdw_endpoint *sof_end = sof_ends;
1517         int num_dais = 0;
1518         int i, j;
1519         int ret;
1520 
1521         for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
1522                 int num_link_dailinks = 0;
1523 
1524                 if (!is_power_of_2(adr_link->mask)) {
1525                         dev_err(dev, "link with multiple mask bits: 0x%x\n",
1526                                 adr_link->mask);
1527                         return -EINVAL;
1528                 }
1529 
1530                 for (i = 0; i < adr_link->num_adr; i++) {
1531                         const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
1532                         struct sof_sdw_codec_info *codec_info;
1533                         const char *codec_name;
1534 
1535                         if (!adr_dev->name_prefix) {
1536                                 dev_err(dev, "codec 0x%llx does not have a name prefix\n",
1537                                         adr_dev->adr);
1538                                 return -EINVAL;
1539                         }
1540 
1541                         codec_info = find_codec_info_part(adr_dev->adr);
1542                         if (!codec_info)
1543                                 return -EINVAL;
1544 
1545                         ctx->ignore_pch_dmic |= codec_info->ignore_pch_dmic;
1546 
1547                         codec_name = get_codec_name(dev, codec_info, adr_link, i);
1548                         if (!codec_name)
1549                                 return -ENOMEM;
1550 
1551                         dev_dbg(dev, "Adding prefix %s for %s\n",
1552                                 adr_dev->name_prefix, codec_name);
1553 
1554                         sof_end->name_prefix = adr_dev->name_prefix;
1555 
1556                         if (codec_info->count_sidecar && codec_info->add_sidecar) {
1557                                 ret = codec_info->count_sidecar(card, &num_dais, num_devs);
1558                                 if (ret)
1559                                         return ret;
1560 
1561                                 sof_end->include_sidecar = true;
1562                         }
1563 
1564                         for (j = 0; j < adr_dev->num_endpoints; j++) {
1565                                 const struct snd_soc_acpi_endpoint *adr_end;
1566                                 const struct sof_sdw_dai_info *dai_info;
1567                                 struct sof_sdw_dailink *sof_dai;
1568                                 int stream;
1569 
1570                                 adr_end = &adr_dev->endpoints[j];
1571                                 dai_info = &codec_info->dais[adr_end->num];
1572                                 sof_dai = find_dailink(sof_dais, adr_end);
1573 
1574                                 if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk))
1575                                         continue;
1576 
1577                                 dev_dbg(dev,
1578                                         "Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n",
1579                                         ffs(adr_link->mask) - 1, adr_dev->adr,
1580                                         adr_end->num, type_strings[dai_info->dai_type],
1581                                         dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
1582                                         dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
1583                                         adr_end->aggregated ? "group" : "solo",
1584                                         adr_end->group_id);
1585 
1586                                 if (adr_end->num >= codec_info->dai_num) {
1587                                         dev_err(dev,
1588                                                 "%d is too many endpoints for codec: 0x%x\n",
1589                                                 adr_end->num, codec_info->part_id);
1590                                         return -EINVAL;
1591                                 }
1592 
1593                                 for_each_pcm_streams(stream) {
1594                                         if (dai_info->direction[stream] &&
1595                                             dai_info->dailink[stream] < 0) {
1596                                                 dev_err(dev,
1597                                                         "Invalid dailink id %d for codec: 0x%x\n",
1598                                                         dai_info->dailink[stream],
1599                                                         codec_info->part_id);
1600                                                 return -EINVAL;
1601                                         }
1602 
1603                                         if (dai_info->direction[stream]) {
1604                                                 num_dais += !sof_dai->num_devs[stream];
1605                                                 sof_dai->num_devs[stream]++;
1606                                                 sof_dai->link_mask[stream] |= adr_link->mask;
1607                                         }
1608                                 }
1609 
1610                                 num_link_dailinks += !!list_empty(&sof_dai->endpoints);
1611                                 list_add_tail(&sof_end->list, &sof_dai->endpoints);
1612 
1613                                 sof_end->link_mask = adr_link->mask;
1614                                 sof_end->codec_name = codec_name;
1615                                 sof_end->codec_info = codec_info;
1616                                 sof_end->dai_info = dai_info;
1617                                 sof_end++;
1618                         }
1619                 }
1620 
1621                 ctx->append_dai_type |= (num_link_dailinks > 1);
1622         }
1623 
1624         return num_dais;
1625 }
1626 
1627 static int create_sdw_dailink(struct snd_soc_card *card,
1628                               struct sof_sdw_dailink *sof_dai,
1629                               struct snd_soc_dai_link **dai_links,
1630                               int *be_id, struct snd_soc_codec_conf **codec_conf)
1631 {
1632         struct device *dev = card->dev;
1633         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1634         struct sof_sdw_endpoint *sof_end;
1635         int stream;
1636         int ret;
1637 
1638         list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
1639                 if (sof_end->name_prefix) {
1640                         (*codec_conf)->dlc.name = sof_end->codec_name;
1641                         (*codec_conf)->name_prefix = sof_end->name_prefix;
1642                         (*codec_conf)++;
1643                 }
1644 
1645                 if (sof_end->include_sidecar) {
1646                         ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
1647                         if (ret)
1648                                 return ret;
1649                 }
1650         }
1651 
1652         for_each_pcm_streams(stream) {
1653                 static const char * const sdw_stream_name[] = {
1654                         "SDW%d-Playback",
1655                         "SDW%d-Capture",
1656                         "SDW%d-Playback-%s",
1657                         "SDW%d-Capture-%s",
1658                 };
1659                 struct snd_soc_dai_link_ch_map *codec_maps;
1660                 struct snd_soc_dai_link_component *codecs;
1661                 struct snd_soc_dai_link_component *cpus;
1662                 int num_cpus = hweight32(sof_dai->link_mask[stream]);
1663                 int num_codecs = sof_dai->num_devs[stream];
1664                 int playback, capture;
1665                 int cur_link = 0;
1666                 int i = 0, j = 0;
1667                 char *name;
1668 
1669                 if (!sof_dai->num_devs[stream])
1670                         continue;
1671 
1672                 sof_end = list_first_entry(&sof_dai->endpoints,
1673                                            struct sof_sdw_endpoint, list);
1674 
1675                 *be_id = sof_end->dai_info->dailink[stream];
1676                 if (*be_id < 0) {
1677                         dev_err(dev, "Invalid dailink id %d\n", *be_id);
1678                         return -EINVAL;
1679                 }
1680 
1681                 /* create stream name according to first link id */
1682                 if (ctx->append_dai_type)
1683                         name = devm_kasprintf(dev, GFP_KERNEL,
1684                                               sdw_stream_name[stream + 2],
1685                                               ffs(sof_end->link_mask) - 1,
1686                                               type_strings[sof_end->dai_info->dai_type]);
1687                 else
1688                         name = devm_kasprintf(dev, GFP_KERNEL,
1689                                               sdw_stream_name[stream],
1690                                               ffs(sof_end->link_mask) - 1);
1691                 if (!name)
1692                         return -ENOMEM;
1693 
1694                 cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
1695                 if (!cpus)
1696                         return -ENOMEM;
1697 
1698                 codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
1699                 if (!codecs)
1700                         return -ENOMEM;
1701 
1702                 codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
1703                 if (!codec_maps)
1704                         return -ENOMEM;
1705 
1706                 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
1707                         if (!sof_end->dai_info->direction[stream])
1708                                 continue;
1709 
1710                         if (cur_link != sof_end->link_mask) {
1711                                 int link_num = ffs(sof_end->link_mask) - 1;
1712                                 int pin_num = ctx->sdw_pin_index[link_num]++;
1713 
1714                                 cur_link = sof_end->link_mask;
1715 
1716                                 cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
1717                                                                   "SDW%d Pin%d",
1718                                                                   link_num, pin_num);
1719                                 if (!cpus[i].dai_name)
1720                                         return -ENOMEM;
1721                                 i++;
1722                         }
1723 
1724                         codec_maps[j].cpu = i - 1;
1725                         codec_maps[j].codec = j;
1726 
1727                         codecs[j].name = sof_end->codec_name;
1728                         codecs[j].dai_name = sof_end->dai_info->dai_name;
1729                         j++;
1730                 }
1731 
1732                 WARN_ON(i != num_cpus || j != num_codecs);
1733 
1734                 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
1735                 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
1736 
1737                 init_dai_link(dev, *dai_links, be_id, name, playback, capture,
1738                               cpus, num_cpus, codecs, num_codecs,
1739                               sof_sdw_rtd_init, &sdw_ops);
1740 
1741                 /*
1742                  * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
1743                  * based on wait_for_completion(), tag them as 'nonatomic'.
1744                  */
1745                 (*dai_links)->nonatomic = true;
1746                 (*dai_links)->ch_maps = codec_maps;
1747 
1748                 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
1749                         if (sof_end->dai_info->init)
1750                                 sof_end->dai_info->init(card, *dai_links,
1751                                                         sof_end->codec_info,
1752                                                         playback);
1753                 }
1754 
1755                 (*dai_links)++;
1756         }
1757 
1758         return 0;
1759 }
1760 
1761 static int create_sdw_dailinks(struct snd_soc_card *card,
1762                                struct snd_soc_dai_link **dai_links, int *be_id,
1763                                struct sof_sdw_dailink *sof_dais,
1764                                struct snd_soc_codec_conf **codec_conf)
1765 {
1766         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1767         int ret, i;
1768 
1769         for (i = 0; i < SDW_MAX_LINKS; i++)
1770                 ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
1771 
1772         /* generate DAI links by each sdw link */
1773         while (sof_dais->initialised) {
1774                 int current_be_id;
1775 
1776                 ret = create_sdw_dailink(card, sof_dais, dai_links,
1777                                          &current_be_id, codec_conf);
1778                 if (ret)
1779                         return ret;
1780 
1781                 /* Update the be_id to match the highest ID used for SDW link */
1782                 if (*be_id < current_be_id)
1783                         *be_id = current_be_id;
1784 
1785                 sof_dais++;
1786         }
1787 
1788         return 0;
1789 }
1790 
1791 static int create_ssp_dailinks(struct snd_soc_card *card,
1792                                struct snd_soc_dai_link **dai_links, int *be_id,
1793                                struct sof_sdw_codec_info *ssp_info,
1794                                unsigned long ssp_mask)
1795 {
1796         struct device *dev = card->dev;
1797         int i, j = 0;
1798         int ret;
1799 
1800         for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
1801                 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
1802                 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1803                 char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1804                                                   ssp_info->acpi_id, j++);
1805                 int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
1806                 int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
1807 
1808                 ret = init_simple_dai_link(dev, *dai_links, be_id, name,
1809                                            playback, capture, cpu_dai_name,
1810                                            codec_name, ssp_info->dais[0].dai_name,
1811                                            NULL, ssp_info->ops);
1812                 if (ret)
1813                         return ret;
1814 
1815                 ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
1816                 if (ret < 0)
1817                         return ret;
1818 
1819                 (*dai_links)++;
1820         }
1821 
1822         return 0;
1823 }
1824 
1825 static int create_dmic_dailinks(struct snd_soc_card *card,
1826                                 struct snd_soc_dai_link **dai_links, int *be_id)
1827 {
1828         struct device *dev = card->dev;
1829         int ret;
1830 
1831         ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
1832                                    0, 1, // DMIC only supports capture
1833                                    "DMIC01 Pin", "dmic-codec", "dmic-hifi",
1834                                    sof_sdw_dmic_init, NULL);
1835         if (ret)
1836                 return ret;
1837 
1838         (*dai_links)++;
1839 
1840         ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
1841                                    0, 1, // DMIC only supports capture
1842                                    "DMIC16k Pin", "dmic-codec", "dmic-hifi",
1843                                    /* don't call sof_sdw_dmic_init() twice */
1844                                    NULL, NULL);
1845         if (ret)
1846                 return ret;
1847 
1848         (*dai_links)++;
1849 
1850         return 0;
1851 }
1852 
1853 static int create_hdmi_dailinks(struct snd_soc_card *card,
1854                                 struct snd_soc_dai_link **dai_links, int *be_id,
1855                                 int hdmi_num)
1856 {
1857         struct device *dev = card->dev;
1858         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1859         int i, ret;
1860 
1861         for (i = 0; i < hdmi_num; i++) {
1862                 char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
1863                 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
1864                 char *codec_name, *codec_dai_name;
1865 
1866                 if (ctx->hdmi.idisp_codec) {
1867                         codec_name = "ehdaudio0D2";
1868                         codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
1869                                                         "intel-hdmi-hifi%d", i + 1);
1870                 } else {
1871                         codec_name = "snd-soc-dummy";
1872                         codec_dai_name = "snd-soc-dummy-dai";
1873                 }
1874 
1875                 ret = init_simple_dai_link(dev, *dai_links, be_id, name,
1876                                            1, 0, // HDMI only supports playback
1877                                            cpu_dai_name, codec_name, codec_dai_name,
1878                                            i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
1879                 if (ret)
1880                         return ret;
1881 
1882                 (*dai_links)++;
1883         }
1884 
1885         return 0;
1886 }
1887 
1888 static int create_bt_dailinks(struct snd_soc_card *card,
1889                               struct snd_soc_dai_link **dai_links, int *be_id)
1890 {
1891         struct device *dev = card->dev;
1892         int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1893                         SOF_BT_OFFLOAD_SSP_SHIFT;
1894         char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1895         char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1896         int ret;
1897 
1898         ret = init_simple_dai_link(dev, *dai_links, be_id, name,
1899                                    1, 1, cpu_dai_name, snd_soc_dummy_dlc.name,
1900                                    snd_soc_dummy_dlc.dai_name, NULL, NULL);
1901         if (ret)
1902                 return ret;
1903 
1904         (*dai_links)++;
1905 
1906         return 0;
1907 }
1908 
1909 static int sof_card_dai_links_create(struct snd_soc_card *card)
1910 {
1911         struct device *dev = card->dev;
1912         struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
1913         int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
1914         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1915         struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1916         struct snd_soc_codec_conf *codec_conf;
1917         struct sof_sdw_codec_info *ssp_info;
1918         struct sof_sdw_endpoint *sof_ends;
1919         struct sof_sdw_dailink *sof_dais;
1920         int num_devs = 0;
1921         int num_ends = 0;
1922         struct snd_soc_dai_link *dai_links;
1923         int num_links;
1924         int be_id = 0;
1925         int hdmi_num;
1926         unsigned long ssp_mask;
1927         int ret;
1928 
1929         ret = count_sdw_endpoints(card, &num_devs, &num_ends);
1930         if (ret < 0) {
1931                 dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
1932                 return ret;
1933         }
1934 
1935         /* One per DAI link, worst case is a DAI link for every endpoint */
1936         sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL);
1937         if (!sof_dais)
1938                 return -ENOMEM;
1939 
1940         /* One per endpoint, ie. each DAI on each codec/amp */
1941         sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
1942         if (!sof_ends) {
1943                 ret = -ENOMEM;
1944                 goto err_dai;
1945         }
1946 
1947         ret = parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs);
1948         if (ret < 0)
1949                 goto err_end;
1950 
1951         sdw_be_num = ret;
1952 
1953         /*
1954          * on generic tgl platform, I2S or sdw mode is supported
1955          * based on board rework. A ACPI device is registered in
1956          * system only when I2S mode is supported, not sdw mode.
1957          * Here check ACPI ID to confirm I2S is supported.
1958          */
1959         ssp_info = find_codec_info_acpi(mach->id);
1960         if (ssp_info) {
1961                 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1962                 ssp_num = hweight_long(ssp_mask);
1963         }
1964 
1965         if (mach_params->codec_mask & IDISP_CODEC_MASK)
1966                 ctx->hdmi.idisp_codec = true;
1967 
1968         if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1969                 hdmi_num = SOF_TGL_HDMI_COUNT;
1970         else
1971                 hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1972 
1973         /* enable dmic01 & dmic16k */
1974         if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num)
1975                 dmic_num = 2;
1976 
1977         if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1978                 bt_num = 1;
1979 
1980         dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
1981                 sdw_be_num, ssp_num, dmic_num,
1982                 ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
1983 
1984         codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
1985         if (!codec_conf) {
1986                 ret = -ENOMEM;
1987                 goto err_end;
1988         }
1989 
1990         /* allocate BE dailinks */
1991         num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
1992         dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
1993         if (!dai_links) {
1994                 ret = -ENOMEM;
1995                 goto err_end;
1996         }
1997 
1998         card->codec_conf = codec_conf;
1999         card->num_configs = num_devs;
2000         card->dai_link = dai_links;
2001         card->num_links = num_links;
2002 
2003         /* SDW */
2004         if (sdw_be_num) {
2005                 ret = create_sdw_dailinks(card, &dai_links, &be_id,
2006                                           sof_dais, &codec_conf);
2007                 if (ret)
2008                         goto err_end;
2009         }
2010 
2011         /* SSP */
2012         if (ssp_num) {
2013                 ret = create_ssp_dailinks(card, &dai_links, &be_id,
2014                                           ssp_info, ssp_mask);
2015                 if (ret)
2016                         goto err_end;
2017         }
2018 
2019         /* dmic */
2020         if (dmic_num > 0) {
2021                 if (ctx->ignore_pch_dmic) {
2022                         dev_warn(dev, "Ignoring PCH DMIC\n");
2023                 } else {
2024                         ret = create_dmic_dailinks(card, &dai_links, &be_id);
2025                         if (ret)
2026                                 goto err_end;
2027                 }
2028         }
2029 
2030         /* HDMI */
2031         ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
2032         if (ret)
2033                 goto err_end;
2034 
2035         /* BT */
2036         if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
2037                 ret = create_bt_dailinks(card, &dai_links, &be_id);
2038                 if (ret)
2039                         goto err_end;
2040         }
2041 
2042         WARN_ON(codec_conf != card->codec_conf + card->num_configs);
2043         WARN_ON(dai_links != card->dai_link + card->num_links);
2044 
2045 err_end:
2046         kfree(sof_ends);
2047 err_dai:
2048         kfree(sof_dais);
2049 
2050         return ret;
2051 }
2052 
2053 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
2054 {
2055         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
2056         int ret = 0;
2057         int i;
2058 
2059         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
2060                 if (codec_info_list[i].codec_card_late_probe) {
2061                         ret = codec_info_list[i].codec_card_late_probe(card);
2062 
2063                         if (ret < 0)
2064                                 return ret;
2065                 }
2066         }
2067 
2068         if (ctx->hdmi.idisp_codec)
2069                 ret = sof_sdw_hdmi_card_late_probe(card);
2070 
2071         return ret;
2072 }
2073 
2074 /* helper to get the link that the codec DAI is used */
2075 static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
2076                                                        const char *dai_name)
2077 {
2078         struct snd_soc_dai_link *dai_link;
2079         int i;
2080         int j;
2081 
2082         for_each_card_prelinks(card, i, dai_link) {
2083                 for (j = 0; j < dai_link->num_codecs; j++) {
2084                         /* Check each codec in a link */
2085                         if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
2086                                 return dai_link;
2087                 }
2088         }
2089         return NULL;
2090 }
2091 
2092 static void mc_dailink_exit_loop(struct snd_soc_card *card)
2093 {
2094         struct snd_soc_dai_link *dai_link;
2095         int ret;
2096         int i, j;
2097 
2098         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
2099                 for (j = 0; j < codec_info_list[i].dai_num; j++) {
2100                         codec_info_list[i].dais[j].rtd_init_done = false;
2101                         /* Check each dai in codec_info_lis to see if it is used in the link */
2102                         if (!codec_info_list[i].dais[j].exit)
2103                                 continue;
2104                         /*
2105                          * We don't need to call .exit function if there is no matched
2106                          * dai link found.
2107                          */
2108                         dai_link = mc_find_codec_dai_used(card,
2109                                                           codec_info_list[i].dais[j].dai_name);
2110                         if (dai_link) {
2111                                 /* Do the .exit function if the codec dai is used in the link */
2112                                 ret = codec_info_list[i].dais[j].exit(card, dai_link);
2113                                 if (ret)
2114                                         dev_warn(card->dev,
2115                                                  "codec exit failed %d\n",
2116                                                  ret);
2117                                 break;
2118                         }
2119                 }
2120         }
2121 }
2122 
2123 static int mc_probe(struct platform_device *pdev)
2124 {
2125         struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
2126         struct snd_soc_card *card;
2127         struct mc_private *ctx;
2128         int amp_num = 0, i;
2129         int ret;
2130 
2131         dev_dbg(&pdev->dev, "Entry\n");
2132 
2133         ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
2134         if (!ctx)
2135                 return -ENOMEM;
2136 
2137         card = &ctx->card;
2138         card->dev = &pdev->dev;
2139         card->name = "soundwire";
2140         card->owner = THIS_MODULE;
2141         card->late_probe = sof_sdw_card_late_probe;
2142 
2143         snd_soc_card_set_drvdata(card, ctx);
2144 
2145         dmi_check_system(sof_sdw_quirk_table);
2146 
2147         if (quirk_override != -1) {
2148                 dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
2149                          sof_sdw_quirk, quirk_override);
2150                 sof_sdw_quirk = quirk_override;
2151         }
2152 
2153         log_quirks(card->dev);
2154 
2155         /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
2156         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
2157                 codec_info_list[i].amp_num = 0;
2158 
2159         if (mach->mach_params.subsystem_id_set) {
2160                 snd_soc_card_set_pci_ssid(card,
2161                                           mach->mach_params.subsystem_vendor,
2162                                           mach->mach_params.subsystem_device);
2163         }
2164 
2165         ret = sof_card_dai_links_create(card);
2166         if (ret < 0)
2167                 return ret;
2168 
2169         /*
2170          * the default amp_num is zero for each codec and
2171          * amp_num will only be increased for active amp
2172          * codecs on used platform
2173          */
2174         for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
2175                 amp_num += codec_info_list[i].amp_num;
2176 
2177         card->components = devm_kasprintf(card->dev, GFP_KERNEL,
2178                                           " cfg-amp:%d", amp_num);
2179         if (!card->components)
2180                 return -ENOMEM;
2181 
2182         if (mach->mach_params.dmic_num) {
2183                 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
2184                                                   "%s mic:dmic cfg-mics:%d",
2185                                                   card->components,
2186                                                   mach->mach_params.dmic_num);
2187                 if (!card->components)
2188                         return -ENOMEM;
2189         }
2190 
2191         /* Register the card */
2192         ret = devm_snd_soc_register_card(card->dev, card);
2193         if (ret) {
2194                 dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
2195                 mc_dailink_exit_loop(card);
2196                 return ret;
2197         }
2198 
2199         platform_set_drvdata(pdev, card);
2200 
2201         return ret;
2202 }
2203 
2204 static void mc_remove(struct platform_device *pdev)
2205 {
2206         struct snd_soc_card *card = platform_get_drvdata(pdev);
2207 
2208         mc_dailink_exit_loop(card);
2209 }
2210 
2211 static const struct platform_device_id mc_id_table[] = {
2212         { "sof_sdw", },
2213         {}
2214 };
2215 MODULE_DEVICE_TABLE(platform, mc_id_table);
2216 
2217 static struct platform_driver sof_sdw_driver = {
2218         .driver = {
2219                 .name = "sof_sdw",
2220                 .pm = &snd_soc_pm_ops,
2221         },
2222         .probe = mc_probe,
2223         .remove_new = mc_remove,
2224         .id_table = mc_id_table,
2225 };
2226 
2227 module_platform_driver(sof_sdw_driver);
2228 
2229 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
2230 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
2231 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
2232 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
2233 MODULE_LICENSE("GPL v2");
2234 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
2235 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php