1313#include <linux/errno.h>
1414#include <linux/firmware.h>
1515#include <linux/workqueue.h>
16+ #include <sound/soc_sdw_utils.h>
1617#include <sound/tlv.h>
1718#include <uapi/sound/sof/tokens.h>
1819#include "sof-priv.h"
@@ -2288,7 +2289,7 @@ static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = {
22882289 {SOF_TPLG_KCTL_BYTES_VOLATILE_RO , snd_sof_bytes_ext_volatile_get },
22892290};
22902291
2291- static const struct snd_soc_tplg_ops sof_tplg_ops = {
2292+ static struct snd_soc_tplg_ops sof_tplg_ops = {
22922293 /* external kcontrol init - used for any driver specific init */
22932294 .control_load = sof_control_load ,
22942295 .control_unload = sof_control_unload ,
@@ -2311,7 +2312,7 @@ static const struct snd_soc_tplg_ops sof_tplg_ops = {
23112312 .link_unload = sof_link_unload ,
23122313
23132314 /* completion - called at completion of firmware loading */
2314- . complete = sof_complete ,
2315+ /* complete will be added in the last tplg ops */
23152316
23162317 /* manifest - optional to inform component of manifest */
23172318 .manifest = sof_manifest ,
@@ -2464,15 +2465,191 @@ static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
24642465 .bytes_ext_ops_count = ARRAY_SIZE (sof_dspless_bytes_ext_ops ),
24652466};
24662467
2468+ enum tplg_device_id {
2469+ TPLG_DEVICE_SDW_JACK ,
2470+ TPLG_DEVICE_SDW_AMP ,
2471+ TPLG_DEVICE_SDW_MIC ,
2472+ TPLG_DEVICE_PCH_DMIC ,
2473+ TPLG_DEVICE_HDMI ,
2474+ TPLG_DEVICE_MAX
2475+ };
2476+
2477+ #define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDW_JACK) | BIT(TPLG_DEVICE_SDW_AMP) | \
2478+ BIT(TPLG_DEVICE_SDW_MIC))
2479+
2480+ struct topology_file {
2481+ char * device ;
2482+ char * file ;
2483+ int be_id ;
2484+ int dev ;
2485+ };
2486+
2487+ /* The code is from https://stackoverflow.com/questions/47116974/remove-a-substring-from-a-string-in-c */
2488+ static char * strremove (char * str , const char * sub )
2489+ {
2490+ size_t len = strlen (sub );
2491+
2492+ if (len > 0 ) {
2493+ char * p = str ;
2494+ size_t size = 0 ;
2495+
2496+ while ((p = strstr (p , sub )) != NULL ) {
2497+ size = (size == 0 ) ? (p - str ) + strlen (p + len ) + 1 : size - len ;
2498+ memmove (p , p + len , size - (p - str ));
2499+ }
2500+ }
2501+ return str ;
2502+ }
2503+
24672504int snd_sof_load_topology (struct snd_soc_component * scomp , const char * file )
24682505{
24692506 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
2507+ struct topology_file tplg_files [TPLG_DEVICE_MAX ];
2508+ struct snd_sof_pdata * sof_pdata = sdev -> pdata ;
2509+ struct snd_soc_dai_link * dai_link ;
24702510 const struct firmware * fw ;
2511+ bool load_default_tplg = false;
2512+ unsigned long tplg_mask = 0 ;
2513+ char platform [4 ];
2514+ int tplg_num = 0 ;
2515+ char * tplg_name ;
2516+ int tplg_dev ;
24712517 int ret ;
2518+ int i ;
24722519
24732520 dev_dbg (scomp -> dev , "loading topology:%s\n" , file );
24742521
2475- ret = request_firmware (& fw , file , scomp -> dev );
2522+ tplg_name = devm_kasprintf (sdev -> dev , GFP_KERNEL , "%s" , file );
2523+ if (sdev -> pdata -> ipc_type == SOF_IPC_TYPE_3 )
2524+ goto legacy_tplg ;
2525+
2526+ ret = sscanf (sof_pdata -> tplg_filename , "sof-%3s-*.tplg" , platform );
2527+ if (ret != 1 )
2528+ goto legacy_tplg ;
2529+
2530+ for_each_card_prelinks (scomp -> card , i , dai_link ) {
2531+ char * tplg_device ;
2532+
2533+ if (tplg_num >= TPLG_DEVICE_MAX ) {
2534+ dev_err (scomp -> dev ,
2535+ "Invalid tplg_num %d, check what happened\n" , tplg_num );
2536+ return - EINVAL ;
2537+ }
2538+
2539+ dev_dbg (scomp -> dev , "dai_link %s id %d\n" , dai_link -> name , dai_link -> id );
2540+ if (strstr (dai_link -> name , "SimpleJack" )) {
2541+ tplg_dev = TPLG_DEVICE_SDW_JACK ;
2542+ tplg_device = "sdca-jack" ;
2543+ } else if (strstr (dai_link -> name , "SmartAmp" )) {
2544+ tplg_dev = TPLG_DEVICE_SDW_AMP ;
2545+ tplg_device = devm_kasprintf (sdev -> dev , GFP_KERNEL ,
2546+ "sdca-%damp" , dai_link -> num_cpus );
2547+ if (!tplg_device )
2548+ return - ENOMEM ;
2549+ } else if (strstr (dai_link -> name , "SmartMic" )) {
2550+ tplg_dev = TPLG_DEVICE_SDW_MIC ;
2551+ tplg_device = "sdca-mic" ;
2552+ } else if (strstr (dai_link -> name , "dmic" )) {
2553+ if (strstr (file , "-2ch" )) {
2554+ tplg_device = "dmic-2ch" ;
2555+ tplg_name = strremove (tplg_name , "-2ch" );
2556+ } else if (strstr (file , "-4ch" )) {
2557+ tplg_device = "dmic-4ch" ;
2558+ tplg_name = strremove (tplg_name , "-4ch" );
2559+ } else {
2560+ dev_warn (scomp -> dev ,
2561+ "only -2ch and -4ch are supported for dmic\n" );
2562+ continue ;
2563+ }
2564+ tplg_dev = TPLG_DEVICE_PCH_DMIC ;
2565+ } else if (strstr (dai_link -> name , "iDisp" )) {
2566+ tplg_dev = TPLG_DEVICE_HDMI ;
2567+ tplg_device = "sdca-hdmi" ;
2568+
2569+ } else {
2570+ /* The dai link is not supported by sperated tplg yet */
2571+ load_default_tplg = true;
2572+ continue ;
2573+ }
2574+ if (tplg_mask & BIT (tplg_dev ))
2575+ continue ;
2576+
2577+ tplg_mask |= BIT (tplg_dev );
2578+ tplg_files [tplg_num ].be_id = dai_link -> id ;
2579+ tplg_files [tplg_num ].device = tplg_device ;
2580+ tplg_files [tplg_num ].dev = tplg_dev ;
2581+ tplg_num ++ ;
2582+ }
2583+ dev_dbg (scomp -> dev , "tplg_mask %#lx tplg_num %d\n" , tplg_mask , tplg_num );
2584+
2585+ /* Currently, only SDCA topology supported */
2586+ if (!(tplg_mask & SDCA_DEVICE_MASK )) {
2587+ /* Restore the default firmware name */
2588+ tplg_name = (char * )file ;
2589+ goto legacy_tplg ;
2590+ }
2591+
2592+ for (i = 0 ; i < tplg_num ; i ++ ) {
2593+ switch (tplg_files [i ].dev ) {
2594+ case TPLG_DEVICE_SDW_JACK :
2595+ case TPLG_DEVICE_SDW_AMP :
2596+ case TPLG_DEVICE_SDW_MIC :
2597+ case TPLG_DEVICE_HDMI :
2598+ tplg_files [i ].file = devm_kasprintf (sdev -> dev , GFP_KERNEL ,
2599+ "%s/sof-%s-id%d.tplg" ,
2600+ sof_pdata -> tplg_filename_prefix ,
2601+ tplg_files [i ].device ,
2602+ tplg_files [i ].be_id );
2603+ break ;
2604+ default :
2605+ tplg_files [i ].file = devm_kasprintf (sdev -> dev , GFP_KERNEL ,
2606+ "%s/sof-%s-%s-id%d.tplg" ,
2607+ sof_pdata -> tplg_filename_prefix ,
2608+ platform ,
2609+ tplg_files [i ].device ,
2610+ tplg_files [i ].be_id );
2611+ break ;
2612+ }
2613+ if (!tplg_files [i ].file )
2614+ return - ENOMEM ;
2615+
2616+ dev_dbg (scomp -> dev , "Requesting %d %s\n" , i , tplg_files [i ].file );
2617+ ret = firmware_request_nowarn (& fw , tplg_files [i ].file , scomp -> dev );
2618+ if (ret < 0 ) {
2619+ if (i == 0 ) {
2620+ /* Restore the default firmware name */
2621+ tplg_name = (char * )file ;
2622+ dev_dbg (scomp -> dev , "Fail back to %s\n" , tplg_name );
2623+ goto legacy_tplg ;
2624+ }
2625+
2626+ dev_err (scomp -> dev , "tplg request firmware %s failed err: %d\n" ,
2627+ tplg_files [i ].file , ret );
2628+ goto out ;
2629+ }
2630+ /* set complete = sof_complete if it is the last topology */
2631+ if (!load_default_tplg && i == tplg_num - 1 )
2632+ sof_tplg_ops .complete = sof_complete ;
2633+
2634+ if (sdev -> dspless_mode_selected )
2635+ ret = snd_soc_tplg_component_load (scomp , & sof_dspless_tplg_ops , fw );
2636+ else
2637+ ret = snd_soc_tplg_component_load (scomp , & sof_tplg_ops , fw );
2638+
2639+ release_firmware (fw );
2640+
2641+ if (ret < 0 ) {
2642+ dev_err (scomp -> dev , "tplg component load failed %d\n" ,
2643+ ret );
2644+ return ret ;
2645+ }
2646+ }
2647+ /* Load topology successfully, goto out */
2648+ if (!load_default_tplg )
2649+ goto out ;
2650+
2651+ legacy_tplg :
2652+ ret = request_firmware (& fw , tplg_name , scomp -> dev );
24762653 if (ret < 0 ) {
24772654 dev_err (scomp -> dev , "error: tplg request firmware %s failed err: %d\n" ,
24782655 file , ret );
@@ -2481,6 +2658,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24812658 return ret ;
24822659 }
24832660
2661+ sof_tplg_ops .complete = sof_complete ;
24842662 if (sdev -> dspless_mode_selected )
24852663 ret = snd_soc_tplg_component_load (scomp , & sof_dspless_tplg_ops , fw );
24862664 else
@@ -2492,6 +2670,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
24922670
24932671 release_firmware (fw );
24942672
2673+ out :
24952674 if (ret >= 0 && sdev -> led_present )
24962675 ret = snd_ctl_led_request ();
24972676
0 commit comments