soc_sdw_utils.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // This file incorporates work covered by the following copyright notice:
  3. // Copyright (c) 2020 Intel Corporation
  4. // Copyright(c) 2024 Advanced Micro Devices, Inc.
  5. /*
  6. * soc-sdw-utils.c - common SoundWire machine driver helper functions
  7. */
  8. #include <linux/device.h>
  9. #include <linux/module.h>
  10. #include <linux/soundwire/sdw.h>
  11. #include <linux/soundwire/sdw_type.h>
  12. #include <sound/sdca_function.h>
  13. #include <sound/soc_sdw_utils.h>
  14. static const struct snd_soc_dapm_widget generic_dmic_widgets[] = {
  15. SND_SOC_DAPM_MIC("DMIC", NULL),
  16. };
  17. static const struct snd_soc_dapm_widget generic_jack_widgets[] = {
  18. SND_SOC_DAPM_HP("Headphone", NULL),
  19. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  20. };
  21. static const struct snd_kcontrol_new generic_jack_controls[] = {
  22. SOC_DAPM_PIN_SWITCH("Headphone"),
  23. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  24. };
  25. static const struct snd_soc_dapm_widget generic_spk_widgets[] = {
  26. SND_SOC_DAPM_SPK("Speaker", NULL),
  27. };
  28. static const struct snd_kcontrol_new generic_spk_controls[] = {
  29. SOC_DAPM_PIN_SWITCH("Speaker"),
  30. };
  31. static const struct snd_soc_dapm_widget lr_spk_widgets[] = {
  32. SND_SOC_DAPM_SPK("Left Spk", NULL),
  33. SND_SOC_DAPM_SPK("Right Spk", NULL),
  34. };
  35. static const struct snd_soc_dapm_widget lr_4spk_widgets[] = {
  36. SND_SOC_DAPM_SPK("Left Spk", NULL),
  37. SND_SOC_DAPM_SPK("Right Spk", NULL),
  38. SND_SOC_DAPM_SPK("Left Spk2", NULL),
  39. SND_SOC_DAPM_SPK("Right Spk2", NULL),
  40. };
  41. static const struct snd_kcontrol_new lr_spk_controls[] = {
  42. SOC_DAPM_PIN_SWITCH("Left Spk"),
  43. SOC_DAPM_PIN_SWITCH("Right Spk"),
  44. };
  45. static const struct snd_kcontrol_new lr_4spk_controls[] = {
  46. SOC_DAPM_PIN_SWITCH("Left Spk"),
  47. SOC_DAPM_PIN_SWITCH("Right Spk"),
  48. SOC_DAPM_PIN_SWITCH("Left Spk2"),
  49. SOC_DAPM_PIN_SWITCH("Right Spk2"),
  50. };
  51. static const struct snd_soc_dapm_widget rt700_widgets[] = {
  52. SND_SOC_DAPM_HP("Headphones", NULL),
  53. SND_SOC_DAPM_MIC("AMIC", NULL),
  54. SND_SOC_DAPM_SPK("Speaker", NULL),
  55. };
  56. static const struct snd_kcontrol_new rt700_controls[] = {
  57. SOC_DAPM_PIN_SWITCH("Headphones"),
  58. SOC_DAPM_PIN_SWITCH("AMIC"),
  59. SOC_DAPM_PIN_SWITCH("Speaker"),
  60. };
  61. struct asoc_sdw_codec_info codec_info_list[] = {
  62. {
  63. .part_id = 0x0000, /* TAS2783A */
  64. .name_prefix = "tas2783",
  65. .dais = {
  66. {
  67. .direction = {true, true},
  68. .dai_name = "tas2783-codec",
  69. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  70. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  71. .init = asoc_sdw_ti_amp_init,
  72. .rtd_init = asoc_sdw_ti_spk_rtd_init,
  73. .controls = lr_4spk_controls,
  74. .num_controls = ARRAY_SIZE(lr_4spk_controls),
  75. .widgets = lr_4spk_widgets,
  76. .num_widgets = ARRAY_SIZE(lr_4spk_widgets),
  77. },
  78. },
  79. .dai_num = 1,
  80. },
  81. {
  82. .part_id = 0x700,
  83. .name_prefix = "rt700",
  84. .dais = {
  85. {
  86. .direction = {true, true},
  87. .dai_name = "rt700-aif1",
  88. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  89. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  90. .rtd_init = asoc_sdw_rt700_rtd_init,
  91. .controls = rt700_controls,
  92. .num_controls = ARRAY_SIZE(rt700_controls),
  93. .widgets = rt700_widgets,
  94. .num_widgets = ARRAY_SIZE(rt700_widgets),
  95. },
  96. },
  97. .dai_num = 1,
  98. },
  99. {
  100. .part_id = 0x711,
  101. .name_prefix = "rt711",
  102. .version_id = 3,
  103. .dais = {
  104. {
  105. .direction = {true, true},
  106. .dai_name = "rt711-sdca-aif1",
  107. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  108. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  109. .init = asoc_sdw_rt_sdca_jack_init,
  110. .exit = asoc_sdw_rt_sdca_jack_exit,
  111. .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
  112. .controls = generic_jack_controls,
  113. .num_controls = ARRAY_SIZE(generic_jack_controls),
  114. .widgets = generic_jack_widgets,
  115. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  116. },
  117. },
  118. .dai_num = 1,
  119. },
  120. {
  121. .part_id = 0x711,
  122. .name_prefix = "rt711",
  123. .version_id = 2,
  124. .dais = {
  125. {
  126. .direction = {true, true},
  127. .dai_name = "rt711-aif1",
  128. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  129. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  130. .init = asoc_sdw_rt711_init,
  131. .exit = asoc_sdw_rt711_exit,
  132. .rtd_init = asoc_sdw_rt711_rtd_init,
  133. .controls = generic_jack_controls,
  134. .num_controls = ARRAY_SIZE(generic_jack_controls),
  135. .widgets = generic_jack_widgets,
  136. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  137. },
  138. },
  139. .dai_num = 1,
  140. },
  141. {
  142. .part_id = 0x712,
  143. .name_prefix = "rt712",
  144. .version_id = 3,
  145. .dais = {
  146. {
  147. .direction = {true, true},
  148. .dai_name = "rt712-sdca-aif1",
  149. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  150. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  151. .init = asoc_sdw_rt_sdca_jack_init,
  152. .exit = asoc_sdw_rt_sdca_jack_exit,
  153. .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
  154. .controls = generic_jack_controls,
  155. .num_controls = ARRAY_SIZE(generic_jack_controls),
  156. .widgets = generic_jack_widgets,
  157. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  158. },
  159. {
  160. .direction = {true, false},
  161. .dai_name = "rt712-sdca-aif2",
  162. .component_name = "rt712",
  163. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  164. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  165. .init = asoc_sdw_rt_amp_init,
  166. .exit = asoc_sdw_rt_amp_exit,
  167. .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
  168. .controls = generic_spk_controls,
  169. .num_controls = ARRAY_SIZE(generic_spk_controls),
  170. .widgets = generic_spk_widgets,
  171. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  172. },
  173. {
  174. .direction = {false, true},
  175. .dai_name = "rt712-sdca-aif3",
  176. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  177. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  178. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  179. },
  180. },
  181. .dai_num = 3,
  182. },
  183. {
  184. .part_id = 0x1712,
  185. .name_prefix = "rt712-dmic",
  186. .version_id = 3,
  187. .dais = {
  188. {
  189. .direction = {false, true},
  190. .dai_name = "rt712-sdca-dmic-aif1",
  191. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  192. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  193. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  194. },
  195. },
  196. .dai_num = 1,
  197. },
  198. {
  199. .part_id = 0x713,
  200. .name_prefix = "rt713",
  201. .version_id = 3,
  202. .dais = {
  203. {
  204. .direction = {true, true},
  205. .dai_name = "rt712-sdca-aif1",
  206. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  207. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  208. .init = asoc_sdw_rt_sdca_jack_init,
  209. .exit = asoc_sdw_rt_sdca_jack_exit,
  210. .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
  211. .controls = generic_jack_controls,
  212. .num_controls = ARRAY_SIZE(generic_jack_controls),
  213. .widgets = generic_jack_widgets,
  214. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  215. },
  216. {
  217. .direction = {false, true},
  218. .dai_name = "rt712-sdca-aif3",
  219. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  220. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  221. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  222. },
  223. },
  224. .dai_num = 2,
  225. },
  226. {
  227. .part_id = 0x1713,
  228. .name_prefix = "rt713-dmic",
  229. .version_id = 3,
  230. .dais = {
  231. {
  232. .direction = {false, true},
  233. .dai_name = "rt712-sdca-dmic-aif1",
  234. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  235. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  236. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  237. },
  238. },
  239. .dai_num = 1,
  240. },
  241. {
  242. .part_id = 0x1308,
  243. .name_prefix = "rt1308",
  244. .acpi_id = "10EC1308",
  245. .dais = {
  246. {
  247. .direction = {true, false},
  248. .dai_name = "rt1308-aif",
  249. .component_name = "rt1308",
  250. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  251. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  252. .init = asoc_sdw_rt_amp_init,
  253. .exit = asoc_sdw_rt_amp_exit,
  254. .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
  255. .controls = generic_spk_controls,
  256. .num_controls = ARRAY_SIZE(generic_spk_controls),
  257. .widgets = generic_spk_widgets,
  258. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  259. },
  260. },
  261. .dai_num = 1,
  262. .ops = &soc_sdw_rt1308_i2s_ops,
  263. },
  264. {
  265. .part_id = 0x1316,
  266. .name_prefix = "rt1316",
  267. .dais = {
  268. {
  269. .direction = {true, true},
  270. .dai_name = "rt1316-aif",
  271. .component_name = "rt1316",
  272. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  273. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  274. .init = asoc_sdw_rt_amp_init,
  275. .exit = asoc_sdw_rt_amp_exit,
  276. .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
  277. .controls = generic_spk_controls,
  278. .num_controls = ARRAY_SIZE(generic_spk_controls),
  279. .widgets = generic_spk_widgets,
  280. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  281. },
  282. },
  283. .dai_num = 1,
  284. },
  285. {
  286. .part_id = 0x1318,
  287. .name_prefix = "rt1318",
  288. .dais = {
  289. {
  290. .direction = {true, true},
  291. .dai_name = "rt1318-aif",
  292. .component_name = "rt1318",
  293. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  294. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  295. .init = asoc_sdw_rt_amp_init,
  296. .exit = asoc_sdw_rt_amp_exit,
  297. .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
  298. .controls = generic_spk_controls,
  299. .num_controls = ARRAY_SIZE(generic_spk_controls),
  300. .widgets = generic_spk_widgets,
  301. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  302. },
  303. },
  304. .dai_num = 1,
  305. },
  306. {
  307. .part_id = 0x1320,
  308. .name_prefix = "rt1320",
  309. .dais = {
  310. {
  311. .direction = {true, false},
  312. .dai_name = "rt1320-aif1",
  313. .component_name = "rt1320",
  314. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  315. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  316. .init = asoc_sdw_rt_amp_init,
  317. .exit = asoc_sdw_rt_amp_exit,
  318. .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
  319. .controls = generic_spk_controls,
  320. .num_controls = ARRAY_SIZE(generic_spk_controls),
  321. .widgets = generic_spk_widgets,
  322. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  323. },
  324. },
  325. .dai_num = 1,
  326. },
  327. {
  328. .part_id = 0x1321,
  329. .name_prefix = "rt1320",
  330. .dais = {
  331. {
  332. .direction = {true, false},
  333. .dai_name = "rt1320-aif1",
  334. .component_name = "rt1320",
  335. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  336. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  337. .init = asoc_sdw_rt_amp_init,
  338. .exit = asoc_sdw_rt_amp_exit,
  339. .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
  340. .controls = generic_spk_controls,
  341. .num_controls = ARRAY_SIZE(generic_spk_controls),
  342. .widgets = generic_spk_widgets,
  343. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  344. },
  345. },
  346. .dai_num = 1,
  347. },
  348. {
  349. .part_id = 0x714,
  350. .name_prefix = "rt714",
  351. .version_id = 3,
  352. .ignore_internal_dmic = true,
  353. .dais = {
  354. {
  355. .direction = {false, true},
  356. .dai_name = "rt715-sdca-aif2",
  357. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  358. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  359. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  360. },
  361. },
  362. .dai_num = 1,
  363. },
  364. {
  365. .part_id = 0x715,
  366. .name_prefix = "rt715",
  367. .version_id = 3,
  368. .ignore_internal_dmic = true,
  369. .dais = {
  370. {
  371. .direction = {false, true},
  372. .dai_name = "rt715-sdca-aif2",
  373. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  374. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  375. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  376. },
  377. },
  378. .dai_num = 1,
  379. },
  380. {
  381. .part_id = 0x714,
  382. .name_prefix = "rt714",
  383. .version_id = 2,
  384. .ignore_internal_dmic = true,
  385. .dais = {
  386. {
  387. .direction = {false, true},
  388. .dai_name = "rt715-aif2",
  389. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  390. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  391. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  392. },
  393. },
  394. .dai_num = 1,
  395. },
  396. {
  397. .part_id = 0x715,
  398. .name_prefix = "rt715",
  399. .version_id = 2,
  400. .ignore_internal_dmic = true,
  401. .dais = {
  402. {
  403. .direction = {false, true},
  404. .dai_name = "rt715-aif2",
  405. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  406. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  407. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  408. },
  409. },
  410. .dai_num = 1,
  411. },
  412. {
  413. .part_id = 0x721,
  414. .name_prefix = "rt721",
  415. .version_id = 3,
  416. .dais = {
  417. {
  418. .direction = {true, true},
  419. .dai_name = "rt721-sdca-aif1",
  420. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  421. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  422. .init = asoc_sdw_rt_sdca_jack_init,
  423. .exit = asoc_sdw_rt_sdca_jack_exit,
  424. .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
  425. .controls = generic_jack_controls,
  426. .num_controls = ARRAY_SIZE(generic_jack_controls),
  427. .widgets = generic_jack_widgets,
  428. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  429. },
  430. {
  431. .direction = {true, false},
  432. .dai_name = "rt721-sdca-aif2",
  433. .component_name = "rt721",
  434. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  435. /* No feedback capability is provided by rt721-sdca codec driver*/
  436. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  437. .init = asoc_sdw_rt_amp_init,
  438. .exit = asoc_sdw_rt_amp_exit,
  439. .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
  440. .controls = generic_spk_controls,
  441. .num_controls = ARRAY_SIZE(generic_spk_controls),
  442. .widgets = generic_spk_widgets,
  443. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  444. },
  445. {
  446. .direction = {false, true},
  447. .dai_name = "rt721-sdca-aif3",
  448. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  449. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  450. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  451. },
  452. },
  453. .dai_num = 3,
  454. },
  455. {
  456. .part_id = 0x722,
  457. .name_prefix = "rt722",
  458. .version_id = 3,
  459. .dais = {
  460. {
  461. .direction = {true, true},
  462. .dai_name = "rt722-sdca-aif1",
  463. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  464. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  465. .init = asoc_sdw_rt_sdca_jack_init,
  466. .exit = asoc_sdw_rt_sdca_jack_exit,
  467. .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
  468. .controls = generic_jack_controls,
  469. .num_controls = ARRAY_SIZE(generic_jack_controls),
  470. .widgets = generic_jack_widgets,
  471. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  472. },
  473. {
  474. .direction = {true, false},
  475. .dai_name = "rt722-sdca-aif2",
  476. .component_name = "rt722",
  477. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  478. /* No feedback capability is provided by rt722-sdca codec driver*/
  479. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  480. .init = asoc_sdw_rt_amp_init,
  481. .exit = asoc_sdw_rt_amp_exit,
  482. .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
  483. .controls = generic_spk_controls,
  484. .num_controls = ARRAY_SIZE(generic_spk_controls),
  485. .widgets = generic_spk_widgets,
  486. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  487. .quirk = SOC_SDW_CODEC_SPKR,
  488. .quirk_exclude = true,
  489. },
  490. {
  491. .direction = {false, true},
  492. .dai_name = "rt722-sdca-aif3",
  493. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  494. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  495. .rtd_init = asoc_sdw_rt_dmic_rtd_init,
  496. .quirk = SOC_SDW_CODEC_MIC,
  497. .quirk_exclude = true,
  498. },
  499. },
  500. .dai_num = 3,
  501. },
  502. {
  503. .part_id = 0x8373,
  504. .name_prefix = "Left",
  505. .dais = {
  506. {
  507. .direction = {true, true},
  508. .dai_name = "max98373-aif1",
  509. .component_name = "mx8373",
  510. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  511. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  512. .init = asoc_sdw_maxim_init,
  513. .rtd_init = asoc_sdw_maxim_spk_rtd_init,
  514. .controls = lr_spk_controls,
  515. .num_controls = ARRAY_SIZE(lr_spk_controls),
  516. .widgets = lr_spk_widgets,
  517. .num_widgets = ARRAY_SIZE(lr_spk_widgets),
  518. },
  519. },
  520. .dai_num = 1,
  521. },
  522. {
  523. .part_id = 0x8363,
  524. .name_prefix = "Left",
  525. .dais = {
  526. {
  527. .direction = {true, false},
  528. .dai_name = "max98363-aif1",
  529. .component_name = "mx8363",
  530. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  531. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  532. .init = asoc_sdw_maxim_init,
  533. .rtd_init = asoc_sdw_maxim_spk_rtd_init,
  534. .controls = lr_spk_controls,
  535. .num_controls = ARRAY_SIZE(lr_spk_controls),
  536. .widgets = lr_spk_widgets,
  537. .num_widgets = ARRAY_SIZE(lr_spk_widgets),
  538. },
  539. },
  540. .dai_num = 1,
  541. },
  542. {
  543. .part_id = 0x5682,
  544. .name_prefix = "rt5682",
  545. .dais = {
  546. {
  547. .direction = {true, true},
  548. .dai_name = "rt5682-sdw",
  549. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  550. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  551. .rtd_init = asoc_sdw_rt5682_rtd_init,
  552. .controls = generic_jack_controls,
  553. .num_controls = ARRAY_SIZE(generic_jack_controls),
  554. .widgets = generic_jack_widgets,
  555. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  556. },
  557. },
  558. .dai_num = 1,
  559. },
  560. {
  561. .part_id = 0x3556,
  562. .name_prefix = "AMP",
  563. .dais = {
  564. {
  565. .direction = {true, false},
  566. .dai_name = "cs35l56-sdw1",
  567. .component_name = "cs35l56",
  568. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  569. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  570. .init = asoc_sdw_cs_amp_init,
  571. .rtd_init = asoc_sdw_cs_spk_rtd_init,
  572. .controls = generic_spk_controls,
  573. .num_controls = ARRAY_SIZE(generic_spk_controls),
  574. .widgets = generic_spk_widgets,
  575. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  576. },
  577. {
  578. .direction = {false, true},
  579. .dai_name = "cs35l56-sdw1c",
  580. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  581. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  582. .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
  583. },
  584. },
  585. .dai_num = 2,
  586. },
  587. {
  588. .part_id = 0x3557,
  589. .name_prefix = "AMP",
  590. .dais = {
  591. {
  592. .direction = {true, false},
  593. .dai_name = "cs35l56-sdw1",
  594. .component_name = "cs35l56",
  595. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  596. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  597. .init = asoc_sdw_cs_amp_init,
  598. .rtd_init = asoc_sdw_cs_spk_rtd_init,
  599. .controls = generic_spk_controls,
  600. .num_controls = ARRAY_SIZE(generic_spk_controls),
  601. .widgets = generic_spk_widgets,
  602. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  603. },
  604. {
  605. .direction = {false, true},
  606. .dai_name = "cs35l56-sdw1c",
  607. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  608. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  609. .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
  610. },
  611. },
  612. .dai_num = 2,
  613. },
  614. {
  615. .part_id = 0x3563,
  616. .name_prefix = "AMP",
  617. .dais = {
  618. {
  619. .direction = {true, false},
  620. .dai_name = "cs35l56-sdw1",
  621. .component_name = "cs35l56",
  622. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  623. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  624. .init = asoc_sdw_cs_amp_init,
  625. .rtd_init = asoc_sdw_cs_spk_rtd_init,
  626. .controls = generic_spk_controls,
  627. .num_controls = ARRAY_SIZE(generic_spk_controls),
  628. .widgets = generic_spk_widgets,
  629. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  630. },
  631. {
  632. .direction = {false, true},
  633. .dai_name = "cs35l56-sdw1c",
  634. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  635. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  636. .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
  637. },
  638. },
  639. .dai_num = 2,
  640. },
  641. {
  642. .part_id = 0x4242,
  643. .name_prefix = "cs42l42",
  644. .dais = {
  645. {
  646. .direction = {true, true},
  647. .dai_name = "cs42l42-sdw",
  648. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  649. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  650. .rtd_init = asoc_sdw_cs42l42_rtd_init,
  651. .controls = generic_jack_controls,
  652. .num_controls = ARRAY_SIZE(generic_jack_controls),
  653. .widgets = generic_jack_widgets,
  654. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  655. },
  656. },
  657. .dai_num = 1,
  658. },
  659. {
  660. .part_id = 0x4243,
  661. .name_prefix = "cs42l43",
  662. .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
  663. .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar,
  664. .dais = {
  665. {
  666. .direction = {true, false},
  667. .codec_name = "cs42l43-codec",
  668. .dai_name = "cs42l43-dp5",
  669. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  670. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  671. .rtd_init = asoc_sdw_cs42l43_hs_rtd_init,
  672. .controls = generic_jack_controls,
  673. .num_controls = ARRAY_SIZE(generic_jack_controls),
  674. .widgets = generic_jack_widgets,
  675. .num_widgets = ARRAY_SIZE(generic_jack_widgets),
  676. },
  677. {
  678. .direction = {false, true},
  679. .codec_name = "cs42l43-codec",
  680. .dai_name = "cs42l43-dp1",
  681. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  682. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  683. .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init,
  684. .widgets = generic_dmic_widgets,
  685. .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
  686. .quirk = SOC_SDW_CODEC_MIC,
  687. .quirk_exclude = true,
  688. },
  689. {
  690. .direction = {false, true},
  691. .codec_name = "cs42l43-codec",
  692. .dai_name = "cs42l43-dp2",
  693. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  694. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  695. },
  696. {
  697. .direction = {true, false},
  698. .codec_name = "cs42l43-codec",
  699. .dai_name = "cs42l43-dp6",
  700. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  701. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  702. .init = asoc_sdw_cs42l43_spk_init,
  703. .rtd_init = asoc_sdw_cs42l43_spk_rtd_init,
  704. .controls = generic_spk_controls,
  705. .num_controls = ARRAY_SIZE(generic_spk_controls),
  706. .widgets = generic_spk_widgets,
  707. .num_widgets = ARRAY_SIZE(generic_spk_widgets),
  708. .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS,
  709. },
  710. },
  711. .dai_num = 4,
  712. },
  713. {
  714. .part_id = 0x4245,
  715. .name_prefix = "cs42l45",
  716. .dais = {
  717. {
  718. .direction = {true, false},
  719. .codec_name = "snd_soc_sdca.UAJ.1",
  720. .dai_name = "IT 41",
  721. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  722. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  723. .rtd_init = asoc_sdw_cs42l45_hs_rtd_init,
  724. },
  725. {
  726. .direction = {false, true},
  727. .codec_name = "snd_soc_sdca.SmartMic.0",
  728. .dai_name = "OT 113",
  729. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  730. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  731. .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init,
  732. },
  733. {
  734. .direction = {false, true},
  735. .codec_name = "snd_soc_sdca.UAJ.1",
  736. .dai_name = "OT 36",
  737. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  738. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  739. },
  740. },
  741. .dai_num = 3,
  742. .auxs = {
  743. {
  744. .codec_name = "snd_soc_sdca.HID.2",
  745. },
  746. },
  747. .aux_num = 1,
  748. },
  749. {
  750. .part_id = 0xaaaa, /* generic codec mockup */
  751. .name_prefix = "sdw_mockup_mmulti-function",
  752. .version_id = 0,
  753. .dais = {
  754. {
  755. .direction = {true, true},
  756. .dai_name = "sdw-mockup-aif1",
  757. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  758. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  759. },
  760. {
  761. .direction = {true, false},
  762. .dai_name = "sdw-mockup-aif1",
  763. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  764. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
  765. },
  766. {
  767. .direction = {false, true},
  768. .dai_name = "sdw-mockup-aif1",
  769. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  770. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  771. },
  772. },
  773. .dai_num = 3,
  774. },
  775. {
  776. .part_id = 0xaa55, /* headset codec mockup */
  777. .name_prefix = "sdw_mockup_headset0",
  778. .version_id = 0,
  779. .dais = {
  780. {
  781. .direction = {true, true},
  782. .dai_name = "sdw-mockup-aif1",
  783. .dai_type = SOC_SDW_DAI_TYPE_JACK,
  784. .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
  785. },
  786. },
  787. .dai_num = 1,
  788. },
  789. {
  790. .part_id = 0x55aa, /* amplifier mockup */
  791. .name_prefix = "sdw_mockup_amp1",
  792. .version_id = 0,
  793. .dais = {
  794. {
  795. .direction = {true, true},
  796. .dai_name = "sdw-mockup-aif1",
  797. .dai_type = SOC_SDW_DAI_TYPE_AMP,
  798. .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
  799. },
  800. },
  801. .dai_num = 1,
  802. },
  803. {
  804. .part_id = 0x5555,
  805. .name_prefix = "sdw_mockup_mic0",
  806. .version_id = 0,
  807. .dais = {
  808. {
  809. .dai_name = "sdw-mockup-aif1",
  810. .direction = {false, true},
  811. .dai_type = SOC_SDW_DAI_TYPE_MIC,
  812. .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
  813. },
  814. },
  815. .dai_num = 1,
  816. },
  817. };
  818. EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS");
  819. int asoc_sdw_get_codec_info_list_count(void)
  820. {
  821. return ARRAY_SIZE(codec_info_list);
  822. };
  823. EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS");
  824. struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr)
  825. {
  826. unsigned int part_id, sdw_version;
  827. int i;
  828. part_id = SDW_PART_ID(adr);
  829. sdw_version = SDW_VERSION(adr);
  830. for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
  831. /*
  832. * A codec info is for all sdw version with the part id if
  833. * version_id is not specified in the codec info.
  834. */
  835. if (part_id == codec_info_list[i].part_id &&
  836. (!codec_info_list[i].version_id ||
  837. sdw_version == codec_info_list[i].version_id))
  838. return &codec_info_list[i];
  839. return NULL;
  840. }
  841. EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS");
  842. static struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_sdw_id(const struct sdw_slave_id *id)
  843. {
  844. int i;
  845. for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
  846. if (id->part_id == codec_info_list[i].part_id &&
  847. (!codec_info_list[i].version_id ||
  848. id->sdw_version == codec_info_list[i].version_id))
  849. return &codec_info_list[i];
  850. return NULL;
  851. }
  852. struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id)
  853. {
  854. int i;
  855. if (!acpi_id[0])
  856. return NULL;
  857. for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
  858. if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
  859. return &codec_info_list[i];
  860. return NULL;
  861. }
  862. EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS");
  863. struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index)
  864. {
  865. int i, j;
  866. for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
  867. for (j = 0; j < codec_info_list[i].dai_num; j++) {
  868. if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
  869. *dai_index = j;
  870. return &codec_info_list[i];
  871. }
  872. }
  873. }
  874. return NULL;
  875. }
  876. EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS");
  877. static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *codec_info,
  878. const char *dai_name)
  879. {
  880. int i;
  881. for (i = 0; i < codec_info->dai_num; i++) {
  882. if (!strcmp(codec_info->dais[i].dai_name, dai_name))
  883. return i;
  884. }
  885. return -ENOENT;
  886. }
  887. int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
  888. {
  889. struct snd_soc_card *card = rtd->card;
  890. struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
  891. struct asoc_sdw_codec_info *codec_info;
  892. struct snd_soc_dai *dai;
  893. struct sdw_slave *sdw_peripheral;
  894. const char *spk_components="";
  895. int dai_index;
  896. int ret;
  897. int i;
  898. for_each_rtd_codec_dais(rtd, i, dai) {
  899. if (is_sdw_slave(dai->component->dev))
  900. sdw_peripheral = dev_to_sdw_dev(dai->component->dev);
  901. else if (dai->component->dev->parent && is_sdw_slave(dai->component->dev->parent))
  902. sdw_peripheral = dev_to_sdw_dev(dai->component->dev->parent);
  903. else
  904. continue;
  905. codec_info = asoc_sdw_find_codec_info_sdw_id(&sdw_peripheral->id);
  906. if (!codec_info)
  907. return -EINVAL;
  908. dai_index = asoc_sdw_find_codec_info_dai_index(codec_info, dai->name);
  909. WARN_ON(dai_index < 0);
  910. /*
  911. * A codec dai can be connected to different dai links for capture and playback,
  912. * but we only need to call the rtd_init function once.
  913. * The rtd_init for each codec dai is independent. So, the order of rtd_init
  914. * doesn't matter.
  915. */
  916. if (codec_info->dais[dai_index].rtd_init_done)
  917. continue;
  918. dev_dbg(card->dev, "%#x/%s initializing for %s/%s\n",
  919. codec_info->part_id, codec_info->dais[dai_index].dai_name,
  920. dai->component->name, dai->name);
  921. /*
  922. * Add card controls and dapm widgets for the first codec dai.
  923. * The controls and widgets will be used for all codec dais.
  924. */
  925. if (i > 0)
  926. goto skip_add_controls_widgets;
  927. if (codec_info->dais[dai_index].controls) {
  928. ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls,
  929. codec_info->dais[dai_index].num_controls);
  930. if (ret) {
  931. dev_err(card->dev, "%#x controls addition failed: %d\n",
  932. codec_info->part_id, ret);
  933. return ret;
  934. }
  935. }
  936. if (codec_info->dais[dai_index].widgets) {
  937. ret = snd_soc_dapm_new_controls(dapm,
  938. codec_info->dais[dai_index].widgets,
  939. codec_info->dais[dai_index].num_widgets);
  940. if (ret) {
  941. dev_err(card->dev, "%#x widgets addition failed: %d\n",
  942. codec_info->part_id, ret);
  943. return ret;
  944. }
  945. }
  946. skip_add_controls_widgets:
  947. if (codec_info->dais[dai_index].rtd_init) {
  948. ret = codec_info->dais[dai_index].rtd_init(rtd, dai);
  949. if (ret)
  950. return ret;
  951. }
  952. /* Generate the spk component string for card->components string */
  953. if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP &&
  954. codec_info->dais[dai_index].component_name) {
  955. if (strlen (spk_components) == 0)
  956. spk_components =
  957. devm_kasprintf(card->dev, GFP_KERNEL, "%s",
  958. codec_info->dais[dai_index].component_name);
  959. else
  960. /* Append component name to spk_components */
  961. spk_components =
  962. devm_kasprintf(card->dev, GFP_KERNEL,
  963. "%s+%s", spk_components,
  964. codec_info->dais[dai_index].component_name);
  965. }
  966. codec_info->dais[dai_index].rtd_init_done = true;
  967. }
  968. if (strlen (spk_components) > 0) {
  969. /* Update card components for speaker components */
  970. card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s",
  971. card->components, spk_components);
  972. if (!card->components)
  973. return -ENOMEM;
  974. }
  975. return 0;
  976. }
  977. EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS");
  978. /* these wrappers are only needed to avoid typecast compilation errors */
  979. int asoc_sdw_startup(struct snd_pcm_substream *substream)
  980. {
  981. return sdw_startup_stream(substream);
  982. }
  983. EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS");
  984. int asoc_sdw_prepare(struct snd_pcm_substream *substream)
  985. {
  986. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  987. struct sdw_stream_runtime *sdw_stream;
  988. struct snd_soc_dai *dai;
  989. /* Find stream from first CPU DAI */
  990. dai = snd_soc_rtd_to_cpu(rtd, 0);
  991. sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
  992. if (IS_ERR(sdw_stream)) {
  993. dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
  994. return PTR_ERR(sdw_stream);
  995. }
  996. return sdw_prepare_stream(sdw_stream);
  997. }
  998. EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS");
  999. int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
  1000. {
  1001. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  1002. struct sdw_stream_runtime *sdw_stream;
  1003. struct snd_soc_dai *dai;
  1004. int ret;
  1005. /* Find stream from first CPU DAI */
  1006. dai = snd_soc_rtd_to_cpu(rtd, 0);
  1007. sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
  1008. if (IS_ERR(sdw_stream)) {
  1009. dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
  1010. return PTR_ERR(sdw_stream);
  1011. }
  1012. switch (cmd) {
  1013. case SNDRV_PCM_TRIGGER_START:
  1014. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  1015. case SNDRV_PCM_TRIGGER_RESUME:
  1016. ret = sdw_enable_stream(sdw_stream);
  1017. break;
  1018. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  1019. case SNDRV_PCM_TRIGGER_SUSPEND:
  1020. case SNDRV_PCM_TRIGGER_STOP:
  1021. ret = sdw_disable_stream(sdw_stream);
  1022. break;
  1023. default:
  1024. ret = -EINVAL;
  1025. break;
  1026. }
  1027. if (ret)
  1028. dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
  1029. return ret;
  1030. }
  1031. EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS");
  1032. int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
  1033. struct snd_pcm_hw_params *params)
  1034. {
  1035. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  1036. struct snd_soc_dai_link_ch_map *ch_maps;
  1037. int ch = params_channels(params);
  1038. unsigned int ch_mask;
  1039. int num_codecs;
  1040. int step;
  1041. int i;
  1042. if (!rtd->dai_link->ch_maps)
  1043. return 0;
  1044. /* Identical data will be sent to all codecs in playback */
  1045. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  1046. ch_mask = GENMASK(ch - 1, 0);
  1047. step = 0;
  1048. } else {
  1049. num_codecs = rtd->dai_link->num_codecs;
  1050. if (ch < num_codecs || ch % num_codecs != 0) {
  1051. dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
  1052. ch, num_codecs);
  1053. return -EINVAL;
  1054. }
  1055. ch_mask = GENMASK(ch / num_codecs - 1, 0);
  1056. step = hweight_long(ch_mask);
  1057. }
  1058. /*
  1059. * The captured data will be combined from each cpu DAI if the dai
  1060. * link has more than one codec DAIs. Set codec channel mask and
  1061. * ASoC will set the corresponding channel numbers for each cpu dai.
  1062. */
  1063. for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
  1064. ch_maps->ch_mask = ch_mask << (i * step);
  1065. return 0;
  1066. }
  1067. EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS");
  1068. int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
  1069. {
  1070. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  1071. struct sdw_stream_runtime *sdw_stream;
  1072. struct snd_soc_dai *dai;
  1073. /* Find stream from first CPU DAI */
  1074. dai = snd_soc_rtd_to_cpu(rtd, 0);
  1075. sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
  1076. if (IS_ERR(sdw_stream)) {
  1077. dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
  1078. return PTR_ERR(sdw_stream);
  1079. }
  1080. return sdw_deprepare_stream(sdw_stream);
  1081. }
  1082. EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS");
  1083. void asoc_sdw_shutdown(struct snd_pcm_substream *substream)
  1084. {
  1085. sdw_shutdown_stream(substream);
  1086. }
  1087. EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS");
  1088. static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
  1089. unsigned int sdw_version,
  1090. unsigned int mfg_id,
  1091. unsigned int part_id,
  1092. unsigned int class_id,
  1093. int index_in_link)
  1094. {
  1095. int i;
  1096. for (i = 0; i < adr_link->num_adr; i++) {
  1097. unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
  1098. u64 adr;
  1099. /* skip itself */
  1100. if (i == index_in_link)
  1101. continue;
  1102. adr = adr_link->adr_d[i].adr;
  1103. sdw1_version = SDW_VERSION(adr);
  1104. mfg1_id = SDW_MFG_ID(adr);
  1105. part1_id = SDW_PART_ID(adr);
  1106. class1_id = SDW_CLASS_ID(adr);
  1107. if (sdw_version == sdw1_version &&
  1108. mfg_id == mfg1_id &&
  1109. part_id == part1_id &&
  1110. class_id == class1_id)
  1111. return false;
  1112. }
  1113. return true;
  1114. }
  1115. static const char *_asoc_sdw_get_codec_name(struct device *dev,
  1116. const struct snd_soc_acpi_link_adr *adr_link,
  1117. int adr_index)
  1118. {
  1119. u64 adr = adr_link->adr_d[adr_index].adr;
  1120. unsigned int sdw_version = SDW_VERSION(adr);
  1121. unsigned int link_id = SDW_DISCO_LINK_ID(adr);
  1122. unsigned int unique_id = SDW_UNIQUE_ID(adr);
  1123. unsigned int mfg_id = SDW_MFG_ID(adr);
  1124. unsigned int part_id = SDW_PART_ID(adr);
  1125. unsigned int class_id = SDW_CLASS_ID(adr);
  1126. if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id,
  1127. class_id, adr_index))
  1128. return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x",
  1129. link_id, mfg_id, part_id, class_id);
  1130. return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x",
  1131. link_id, mfg_id, part_id, class_id, unique_id);
  1132. }
  1133. const char *asoc_sdw_get_codec_name(struct device *dev,
  1134. const struct asoc_sdw_dai_info *dai_info,
  1135. const struct snd_soc_acpi_link_adr *adr_link,
  1136. int adr_index)
  1137. {
  1138. if (dai_info->codec_name)
  1139. return devm_kstrdup(dev, dai_info->codec_name, GFP_KERNEL);
  1140. return _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
  1141. }
  1142. EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS");
  1143. /* helper to get the link that the codec DAI is used */
  1144. struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card,
  1145. const char *dai_name)
  1146. {
  1147. struct snd_soc_dai_link *dai_link;
  1148. int i;
  1149. int j;
  1150. for_each_card_prelinks(card, i, dai_link) {
  1151. for (j = 0; j < dai_link->num_codecs; j++) {
  1152. /* Check each codec in a link */
  1153. if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
  1154. return dai_link;
  1155. }
  1156. }
  1157. return NULL;
  1158. }
  1159. EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS");
  1160. void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card)
  1161. {
  1162. struct snd_soc_dai_link *dai_link;
  1163. struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
  1164. int ret;
  1165. int i, j;
  1166. for (i = 0; i < ctx->codec_info_list_count; i++) {
  1167. for (j = 0; j < codec_info_list[i].dai_num; j++) {
  1168. codec_info_list[i].dais[j].rtd_init_done = false;
  1169. /* Check each dai in codec_info_lis to see if it is used in the link */
  1170. if (!codec_info_list[i].dais[j].exit)
  1171. continue;
  1172. /*
  1173. * We don't need to call .exit function if there is no matched
  1174. * dai link found.
  1175. */
  1176. dai_link = asoc_sdw_mc_find_codec_dai_used(card,
  1177. codec_info_list[i].dais[j].dai_name);
  1178. if (dai_link) {
  1179. /* Do the .exit function if the codec dai is used in the link */
  1180. ret = codec_info_list[i].dais[j].exit(card, dai_link);
  1181. if (ret)
  1182. dev_warn(card->dev,
  1183. "codec exit failed %d\n",
  1184. ret);
  1185. break;
  1186. }
  1187. }
  1188. }
  1189. }
  1190. EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS");
  1191. int asoc_sdw_card_late_probe(struct snd_soc_card *card)
  1192. {
  1193. int ret = 0;
  1194. int i;
  1195. for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
  1196. if (codec_info_list[i].codec_card_late_probe) {
  1197. ret = codec_info_list[i].codec_card_late_probe(card);
  1198. if (ret < 0)
  1199. return ret;
  1200. }
  1201. }
  1202. return ret;
  1203. }
  1204. EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS");
  1205. void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
  1206. int *be_id, char *name, int playback, int capture,
  1207. struct snd_soc_dai_link_component *cpus, int cpus_num,
  1208. struct snd_soc_dai_link_component *platform_component,
  1209. int num_platforms, struct snd_soc_dai_link_component *codecs,
  1210. int codecs_num, int no_pcm,
  1211. int (*init)(struct snd_soc_pcm_runtime *rtd),
  1212. const struct snd_soc_ops *ops)
  1213. {
  1214. dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id);
  1215. dai_links->id = (*be_id)++;
  1216. dai_links->name = name;
  1217. dai_links->stream_name = name;
  1218. dai_links->platforms = platform_component;
  1219. dai_links->num_platforms = num_platforms;
  1220. dai_links->no_pcm = no_pcm;
  1221. dai_links->cpus = cpus;
  1222. dai_links->num_cpus = cpus_num;
  1223. dai_links->codecs = codecs;
  1224. dai_links->num_codecs = codecs_num;
  1225. dai_links->playback_only = playback && !capture;
  1226. dai_links->capture_only = !playback && capture;
  1227. dai_links->init = init;
  1228. dai_links->ops = ops;
  1229. }
  1230. EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS");
  1231. int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
  1232. int *be_id, char *name, int playback, int capture,
  1233. const char *cpu_dai_name, const char *platform_comp_name,
  1234. const char *codec_name, const char *codec_dai_name,
  1235. int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd),
  1236. const struct snd_soc_ops *ops)
  1237. {
  1238. struct snd_soc_dai_link_component *dlc;
  1239. /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */
  1240. dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL);
  1241. if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name)
  1242. return -ENOMEM;
  1243. dlc[0].dai_name = cpu_dai_name;
  1244. dlc[1].name = platform_comp_name;
  1245. dlc[2].name = codec_name;
  1246. dlc[2].dai_name = codec_dai_name;
  1247. asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture,
  1248. &dlc[0], 1, &dlc[1], 1, &dlc[2], 1,
  1249. no_pcm, init, ops);
  1250. return 0;
  1251. }
  1252. EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS");
  1253. int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card,
  1254. int *num_devs, int *num_ends, int *num_aux)
  1255. {
  1256. struct device *dev = card->dev;
  1257. struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
  1258. struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
  1259. const struct snd_soc_acpi_link_adr *adr_link;
  1260. int i;
  1261. for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
  1262. *num_devs += adr_link->num_adr;
  1263. for (i = 0; i < adr_link->num_adr; i++) {
  1264. const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
  1265. struct asoc_sdw_codec_info *codec_info;
  1266. *num_ends += adr_dev->num_endpoints;
  1267. codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
  1268. if (!codec_info)
  1269. return -EINVAL;
  1270. *num_aux += codec_info->aux_num;
  1271. }
  1272. }
  1273. dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
  1274. return 0;
  1275. }
  1276. EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS");
  1277. struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
  1278. const struct snd_soc_acpi_endpoint *new)
  1279. {
  1280. while (dailinks->initialised) {
  1281. if (new->aggregated && dailinks->group_id == new->group_id)
  1282. return dailinks;
  1283. dailinks++;
  1284. }
  1285. INIT_LIST_HEAD(&dailinks->endpoints);
  1286. dailinks->group_id = new->group_id;
  1287. dailinks->initialised = true;
  1288. return dailinks;
  1289. }
  1290. EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS");
  1291. int asoc_sdw_get_dai_type(u32 type)
  1292. {
  1293. switch (type) {
  1294. case SDCA_FUNCTION_TYPE_SMART_AMP:
  1295. case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
  1296. return SOC_SDW_DAI_TYPE_AMP;
  1297. case SDCA_FUNCTION_TYPE_SMART_MIC:
  1298. case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
  1299. case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
  1300. return SOC_SDW_DAI_TYPE_MIC;
  1301. case SDCA_FUNCTION_TYPE_UAJ:
  1302. case SDCA_FUNCTION_TYPE_RJ:
  1303. case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
  1304. return SOC_SDW_DAI_TYPE_JACK;
  1305. default:
  1306. return -EINVAL;
  1307. }
  1308. }
  1309. EXPORT_SYMBOL_NS(asoc_sdw_get_dai_type, "SND_SOC_SDW_UTILS");
  1310. /*
  1311. * Check if the SDCA endpoint is present by the SDW peripheral
  1312. *
  1313. * @dev: Device pointer
  1314. * @codec_info: Codec info pointer
  1315. * @adr_link: ACPI link address
  1316. * @adr_index: Index of the ACPI link address
  1317. * @end_index: Index of the endpoint
  1318. *
  1319. * Return: 1 if the endpoint is present,
  1320. * 0 if the endpoint is not present,
  1321. * negative error code.
  1322. */
  1323. static int is_sdca_endpoint_present(struct device *dev,
  1324. struct asoc_sdw_codec_info *codec_info,
  1325. const struct snd_soc_acpi_link_adr *adr_link,
  1326. int adr_index, int end_index)
  1327. {
  1328. const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index];
  1329. const struct snd_soc_acpi_endpoint *adr_end;
  1330. const struct asoc_sdw_dai_info *dai_info;
  1331. struct sdw_slave *slave;
  1332. struct device *sdw_dev;
  1333. const char *sdw_codec_name;
  1334. int ret, i;
  1335. adr_end = &adr_dev->endpoints[end_index];
  1336. dai_info = &codec_info->dais[adr_end->num];
  1337. sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
  1338. if (!sdw_codec_name)
  1339. return -ENOMEM;
  1340. sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
  1341. if (!sdw_dev) {
  1342. dev_err(dev, "codec %s not found\n", sdw_codec_name);
  1343. return -EINVAL;
  1344. }
  1345. slave = dev_to_sdw_dev(sdw_dev);
  1346. /* Make sure BIOS provides SDCA properties */
  1347. if (!slave->sdca_data.interface_revision) {
  1348. dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
  1349. ret = 1;
  1350. goto put_device;
  1351. }
  1352. for (i = 0; i < slave->sdca_data.num_functions; i++) {
  1353. int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type);
  1354. if (dai_type == dai_info->dai_type) {
  1355. dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
  1356. dai_type, slave->sdca_data.function[i].name);
  1357. ret = 1;
  1358. goto put_device;
  1359. }
  1360. }
  1361. dev_dbg(&slave->dev,
  1362. "SDCA device function for DAI type %d not supported, skip endpoint\n",
  1363. dai_info->dai_type);
  1364. ret = 0;
  1365. put_device:
  1366. put_device(sdw_dev);
  1367. return ret;
  1368. }
  1369. int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
  1370. struct snd_soc_aux_dev *soc_aux,
  1371. struct asoc_sdw_dailink *soc_dais,
  1372. struct asoc_sdw_endpoint *soc_ends,
  1373. int *num_devs)
  1374. {
  1375. struct device *dev = card->dev;
  1376. struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
  1377. struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
  1378. struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
  1379. const struct snd_soc_acpi_link_adr *adr_link;
  1380. struct asoc_sdw_endpoint *soc_end = soc_ends;
  1381. int num_dais = 0;
  1382. int i, j;
  1383. int ret;
  1384. for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
  1385. int num_link_dailinks = 0;
  1386. if (!is_power_of_2(adr_link->mask)) {
  1387. dev_err(dev, "link with multiple mask bits: 0x%x\n",
  1388. adr_link->mask);
  1389. return -EINVAL;
  1390. }
  1391. for (i = 0; i < adr_link->num_adr; i++) {
  1392. const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
  1393. struct asoc_sdw_codec_info *codec_info;
  1394. const char *codec_name;
  1395. bool check_sdca = false;
  1396. if (!adr_dev->name_prefix) {
  1397. dev_err(dev, "codec 0x%llx does not have a name prefix\n",
  1398. adr_dev->adr);
  1399. return -EINVAL;
  1400. }
  1401. codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
  1402. if (!codec_info)
  1403. return -EINVAL;
  1404. for (j = 0; j < codec_info->aux_num; j++) {
  1405. soc_aux->dlc.name = codec_info->auxs[j].codec_name;
  1406. soc_aux++;
  1407. }
  1408. ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
  1409. if (codec_info->count_sidecar && codec_info->add_sidecar) {
  1410. ret = codec_info->count_sidecar(card, &num_dais, num_devs);
  1411. if (ret)
  1412. return ret;
  1413. soc_end->include_sidecar = true;
  1414. }
  1415. if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
  1416. check_sdca = true;
  1417. for (j = 0; j < adr_dev->num_endpoints; j++) {
  1418. const struct snd_soc_acpi_endpoint *adr_end;
  1419. const struct asoc_sdw_dai_info *dai_info;
  1420. struct asoc_sdw_dailink *soc_dai;
  1421. int stream;
  1422. adr_end = &adr_dev->endpoints[j];
  1423. dai_info = &codec_info->dais[adr_end->num];
  1424. soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
  1425. /*
  1426. * quirk should have higher priority than the sdca properties
  1427. * in the BIOS. We can't always check the DAI quirk because we
  1428. * will set the mc_quirk when the BIOS doesn't provide the right
  1429. * information. The endpoint will be skipped if the dai_info->
  1430. * quirk_exclude and mc_quirk are both not set if we always skip
  1431. * the endpoint according to the quirk information. We need to
  1432. * keep the endpoint if it is present in the BIOS. So, only
  1433. * check the DAI quirk when the mc_quirk is set or SDCA endpoint
  1434. * present check is not needed.
  1435. */
  1436. if (dai_info->quirk & ctx->mc_quirk || !check_sdca) {
  1437. /*
  1438. * Check the endpoint if a matching quirk is set or SDCA
  1439. * endpoint check is not necessary
  1440. */
  1441. if (dai_info->quirk &&
  1442. !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) {
  1443. (*num_devs)--;
  1444. continue;
  1445. }
  1446. } else {
  1447. /* Check SDCA codec endpoint if there is no matching quirk */
  1448. ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j);
  1449. if (ret < 0)
  1450. return ret;
  1451. /* The endpoint is not present, skip */
  1452. if (!ret) {
  1453. (*num_devs)--;
  1454. continue;
  1455. }
  1456. }
  1457. dev_dbg(dev,
  1458. "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
  1459. ffs(adr_link->mask) - 1, adr_dev->adr,
  1460. adr_end->num, dai_info->dai_type,
  1461. dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
  1462. dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
  1463. adr_end->aggregated ? "group" : "solo",
  1464. adr_end->group_id);
  1465. if (adr_end->num >= codec_info->dai_num) {
  1466. dev_err(dev,
  1467. "%d is too many endpoints for codec: 0x%x\n",
  1468. adr_end->num, codec_info->part_id);
  1469. return -EINVAL;
  1470. }
  1471. for_each_pcm_streams(stream) {
  1472. if (dai_info->direction[stream] &&
  1473. dai_info->dailink[stream] < 0) {
  1474. dev_err(dev,
  1475. "Invalid dailink id %d for codec: 0x%x\n",
  1476. dai_info->dailink[stream],
  1477. codec_info->part_id);
  1478. return -EINVAL;
  1479. }
  1480. if (dai_info->direction[stream]) {
  1481. num_dais += !soc_dai->num_devs[stream];
  1482. soc_dai->num_devs[stream]++;
  1483. soc_dai->link_mask[stream] |= adr_link->mask;
  1484. }
  1485. }
  1486. num_link_dailinks += !!list_empty(&soc_dai->endpoints);
  1487. list_add_tail(&soc_end->list, &soc_dai->endpoints);
  1488. codec_name = asoc_sdw_get_codec_name(dev, dai_info,
  1489. adr_link, i);
  1490. if (!codec_name)
  1491. return -ENOMEM;
  1492. dev_dbg(dev, "Adding prefix %s for %s\n",
  1493. adr_dev->name_prefix, codec_name);
  1494. soc_end->name_prefix = adr_dev->name_prefix;
  1495. soc_end->link_mask = adr_link->mask;
  1496. soc_end->codec_name = codec_name;
  1497. soc_end->codec_info = codec_info;
  1498. soc_end->dai_info = dai_info;
  1499. soc_end++;
  1500. }
  1501. }
  1502. ctx->append_dai_type |= (num_link_dailinks > 1);
  1503. }
  1504. return num_dais;
  1505. }
  1506. EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS");
  1507. MODULE_LICENSE("GPL");
  1508. MODULE_DESCRIPTION("SoundWire ASoC helpers");