18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Stereo and SAP detection for cx88 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009 Marton Balint <cus@fazekas.hu> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "cx88.h" 98c2ecf20Sopenharmony_ci#include "cx88-reg.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 158c2ecf20Sopenharmony_ci#include <asm/div64.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define INT_PI ((s32)(3.141592653589 * 32768.0)) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define compat_remainder(a, b) \ 208c2ecf20Sopenharmony_ci ((float)(((s32)((a) * 100)) % ((s32)((b) * 100))) / 100.0) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define baseband_freq(carrier, srate, tone) ((s32)( \ 238c2ecf20Sopenharmony_ci (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * We calculate the baseband frequencies of the carrier and the pilot tones 278c2ecf20Sopenharmony_ci * based on the the sampling rate of the audio rds fifo. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) 318c2ecf20Sopenharmony_ci#define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1) 328c2ecf20Sopenharmony_ci#define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * The frequencies below are from the reference driver. They probably need 368c2ecf20Sopenharmony_ci * further adjustments, because they are not tested at all. You may even need 378c2ecf20Sopenharmony_ci * to play a bit with the registers of the chip to select the proper signal 388c2ecf20Sopenharmony_ci * for the input of the audio rds fifo, and measure it's sampling rate to 398c2ecf20Sopenharmony_ci * calculate the proper baseband frequencies... 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0)) 438c2ecf20Sopenharmony_ci#define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0)) 448c2ecf20Sopenharmony_ci#define FREQ_A2M_STEREO ((s32)(2.462326 * 32768.0)) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define FREQ_EIAJ_CARRIER ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ 478c2ecf20Sopenharmony_ci#define FREQ_EIAJ_DUAL ((s32)(2.562118 * 32768.0)) 488c2ecf20Sopenharmony_ci#define FREQ_EIAJ_STEREO ((s32)(2.601053 * 32768.0)) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define FREQ_BTSC_DUAL ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ 518c2ecf20Sopenharmony_ci#define FREQ_BTSC_DUAL_REF ((s32)(1.374446 * 32768.0)) /* 7pi/16 */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define FREQ_BTSC_SAP ((s32)(2.471532 * 32768.0)) 548c2ecf20Sopenharmony_ci#define FREQ_BTSC_SAP_REF ((s32)(1.730072 * 32768.0)) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* The spectrum of the signal should be empty between these frequencies. */ 578c2ecf20Sopenharmony_ci#define FREQ_NOISE_START ((s32)(0.100000 * 32768.0)) 588c2ecf20Sopenharmony_ci#define FREQ_NOISE_END ((s32)(1.200000 * 32768.0)) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic unsigned int dsp_debug; 618c2ecf20Sopenharmony_cimodule_param(dsp_debug, int, 0644); 628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages"); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) do { \ 658c2ecf20Sopenharmony_ci if (dsp_debug >= level) \ 668c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: dsp:" fmt), \ 678c2ecf20Sopenharmony_ci __func__, ##arg); \ 688c2ecf20Sopenharmony_ci} while (0) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic s32 int_cos(u32 x) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci u32 t2, t4, t6, t8; 738c2ecf20Sopenharmony_ci s32 ret; 748c2ecf20Sopenharmony_ci u16 period = x / INT_PI; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (period % 2) 778c2ecf20Sopenharmony_ci return -int_cos(x - INT_PI); 788c2ecf20Sopenharmony_ci x = x % INT_PI; 798c2ecf20Sopenharmony_ci if (x > INT_PI / 2) 808c2ecf20Sopenharmony_ci return -int_cos(INT_PI / 2 - (x % (INT_PI / 2))); 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * Now x is between 0 and INT_PI/2. 838c2ecf20Sopenharmony_ci * To calculate cos(x) we use it's Taylor polinom. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci t2 = x * x / 32768 / 2; 868c2ecf20Sopenharmony_ci t4 = t2 * x / 32768 * x / 32768 / 3 / 4; 878c2ecf20Sopenharmony_ci t6 = t4 * x / 32768 * x / 32768 / 5 / 6; 888c2ecf20Sopenharmony_ci t8 = t6 * x / 32768 * x / 32768 / 7 / 8; 898c2ecf20Sopenharmony_ci ret = 32768 - t2 + t4 - t6 + t8; 908c2ecf20Sopenharmony_ci return ret; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic u32 int_goertzel(s16 x[], u32 N, u32 freq) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * We use the Goertzel algorithm to determine the power of the 978c2ecf20Sopenharmony_ci * given frequency in the signal 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci s32 s_prev = 0; 1008c2ecf20Sopenharmony_ci s32 s_prev2 = 0; 1018c2ecf20Sopenharmony_ci s32 coeff = 2 * int_cos(freq); 1028c2ecf20Sopenharmony_ci u32 i; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci u64 tmp; 1058c2ecf20Sopenharmony_ci u32 divisor; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for (i = 0; i < N; i++) { 1088c2ecf20Sopenharmony_ci s32 s = x[i] + ((s64)coeff * s_prev / 32768) - s_prev2; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci s_prev2 = s_prev; 1118c2ecf20Sopenharmony_ci s_prev = s; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev - 1158c2ecf20Sopenharmony_ci (s64)coeff * s_prev2 * s_prev / 32768; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * XXX: N must be low enough so that N*N fits in s32. 1198c2ecf20Sopenharmony_ci * Else we need two divisions. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci divisor = N * N; 1228c2ecf20Sopenharmony_ci do_div(tmp, divisor); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return (u32)tmp; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic u32 freq_magnitude(s16 x[], u32 N, u32 freq) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci u32 sum = int_goertzel(x, N, freq); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return (u32)int_sqrt(sum); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci int i; 1378c2ecf20Sopenharmony_ci u32 sum = 0; 1388c2ecf20Sopenharmony_ci u32 freq_step; 1398c2ecf20Sopenharmony_ci int samples = 5; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (N > 192) { 1428c2ecf20Sopenharmony_ci /* The last 192 samples are enough for noise detection */ 1438c2ecf20Sopenharmony_ci x += (N - 192); 1448c2ecf20Sopenharmony_ci N = 192; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci freq_step = (freq_end - freq_start) / (samples - 1); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci for (i = 0; i < samples; i++) { 1508c2ecf20Sopenharmony_ci sum += int_goertzel(x, N, freq_start); 1518c2ecf20Sopenharmony_ci freq_start += freq_step; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return (u32)int_sqrt(sum / samples); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci s32 carrier, stereo, dual, noise; 1608c2ecf20Sopenharmony_ci s32 carrier_freq, stereo_freq, dual_freq; 1618c2ecf20Sopenharmony_ci s32 ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci switch (core->tvaudio) { 1648c2ecf20Sopenharmony_ci case WW_BG: 1658c2ecf20Sopenharmony_ci case WW_DK: 1668c2ecf20Sopenharmony_ci carrier_freq = FREQ_A2_CARRIER; 1678c2ecf20Sopenharmony_ci stereo_freq = FREQ_A2_STEREO; 1688c2ecf20Sopenharmony_ci dual_freq = FREQ_A2_DUAL; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case WW_M: 1718c2ecf20Sopenharmony_ci carrier_freq = FREQ_A2M_CARRIER; 1728c2ecf20Sopenharmony_ci stereo_freq = FREQ_A2M_STEREO; 1738c2ecf20Sopenharmony_ci dual_freq = FREQ_A2M_DUAL; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case WW_EIAJ: 1768c2ecf20Sopenharmony_ci carrier_freq = FREQ_EIAJ_CARRIER; 1778c2ecf20Sopenharmony_ci stereo_freq = FREQ_EIAJ_STEREO; 1788c2ecf20Sopenharmony_ci dual_freq = FREQ_EIAJ_DUAL; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci default: 1818c2ecf20Sopenharmony_ci pr_warn("unsupported audio mode %d for %s\n", 1828c2ecf20Sopenharmony_ci core->tvaudio, __func__); 1838c2ecf20Sopenharmony_ci return UNSET; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci carrier = freq_magnitude(x, N, carrier_freq); 1878c2ecf20Sopenharmony_ci stereo = freq_magnitude(x, N, stereo_freq); 1888c2ecf20Sopenharmony_ci dual = freq_magnitude(x, N, dual_freq); 1898c2ecf20Sopenharmony_ci noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci dprintk(1, 1928c2ecf20Sopenharmony_ci "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, noise=%d\n", 1938c2ecf20Sopenharmony_ci carrier, stereo, dual, noise); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (stereo > dual) 1968c2ecf20Sopenharmony_ci ret = V4L2_TUNER_SUB_STEREO; 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (core->tvaudio == WW_EIAJ) { 2018c2ecf20Sopenharmony_ci /* EIAJ checks may need adjustments */ 2028c2ecf20Sopenharmony_ci if ((carrier > max(stereo, dual) * 2) && 2038c2ecf20Sopenharmony_ci (carrier < max(stereo, dual) * 6) && 2048c2ecf20Sopenharmony_ci (carrier > 20 && carrier < 200) && 2058c2ecf20Sopenharmony_ci (max(stereo, dual) > min(stereo, dual))) { 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * For EIAJ the carrier is always present, 2088c2ecf20Sopenharmony_ci * so we probably don't need noise detection 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci if ((carrier > max(stereo, dual) * 2) && 2148c2ecf20Sopenharmony_ci (carrier < max(stereo, dual) * 8) && 2158c2ecf20Sopenharmony_ci (carrier > 20 && carrier < 200) && 2168c2ecf20Sopenharmony_ci (noise < 10) && 2178c2ecf20Sopenharmony_ci (max(stereo, dual) > min(stereo, dual) * 2)) { 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci return V4L2_TUNER_SUB_MONO; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF); 2278c2ecf20Sopenharmony_ci s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); 2288c2ecf20Sopenharmony_ci s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); 2298c2ecf20Sopenharmony_ci s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d\n", 2328c2ecf20Sopenharmony_ci dual_ref, dual, sap_ref, sap); 2338c2ecf20Sopenharmony_ci /* FIXME: Currently not supported */ 2348c2ecf20Sopenharmony_ci return UNSET; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic s16 *read_rds_samples(struct cx88_core *core, u32 *N) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27]; 2408c2ecf20Sopenharmony_ci s16 *samples; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci unsigned int i; 2438c2ecf20Sopenharmony_ci unsigned int bpl = srch->fifo_size / AUD_RDS_LINES; 2448c2ecf20Sopenharmony_ci unsigned int spl = bpl / 4; 2458c2ecf20Sopenharmony_ci unsigned int sample_count = spl * (AUD_RDS_LINES - 1); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci u32 current_address = cx_read(srch->ptr1_reg); 2488c2ecf20Sopenharmony_ci u32 offset = (current_address - srch->fifo_start + bpl); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci dprintk(1, 2518c2ecf20Sopenharmony_ci "read RDS samples: current_address=%08x (offset=%08x), sample_count=%d, aud_intstat=%08x\n", 2528c2ecf20Sopenharmony_ci current_address, 2538c2ecf20Sopenharmony_ci current_address - srch->fifo_start, sample_count, 2548c2ecf20Sopenharmony_ci cx_read(MO_AUD_INTSTAT)); 2558c2ecf20Sopenharmony_ci samples = kmalloc_array(sample_count, sizeof(*samples), GFP_KERNEL); 2568c2ecf20Sopenharmony_ci if (!samples) 2578c2ecf20Sopenharmony_ci return NULL; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci *N = sample_count; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci for (i = 0; i < sample_count; i++) { 2628c2ecf20Sopenharmony_ci offset = offset % (AUD_RDS_LINES * bpl); 2638c2ecf20Sopenharmony_ci samples[i] = cx_read(srch->fifo_start + offset); 2648c2ecf20Sopenharmony_ci offset += 4; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dprintk(2, "RDS samples dump: %*ph\n", sample_count, samples); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return samples; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cis32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci s16 *samples; 2758c2ecf20Sopenharmony_ci u32 N = 0; 2768c2ecf20Sopenharmony_ci s32 ret = UNSET; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* If audio RDS fifo is disabled, we can't read the samples */ 2798c2ecf20Sopenharmony_ci if (!(cx_read(MO_AUD_DMACNTRL) & 0x04)) 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS)) 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Wait at least 500 ms after an audio standard change */ 2858c2ecf20Sopenharmony_ci if (time_before(jiffies, core->last_change + msecs_to_jiffies(500))) 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci samples = read_rds_samples(core, &N); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (!samples) 2918c2ecf20Sopenharmony_ci return ret; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci switch (core->tvaudio) { 2948c2ecf20Sopenharmony_ci case WW_BG: 2958c2ecf20Sopenharmony_ci case WW_DK: 2968c2ecf20Sopenharmony_ci case WW_EIAJ: 2978c2ecf20Sopenharmony_ci case WW_M: 2988c2ecf20Sopenharmony_ci ret = detect_a2_a2m_eiaj(core, samples, N); 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci case WW_BTSC: 3018c2ecf20Sopenharmony_ci ret = detect_btsc(core, samples, N); 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci case WW_NONE: 3048c2ecf20Sopenharmony_ci case WW_I: 3058c2ecf20Sopenharmony_ci case WW_L: 3068c2ecf20Sopenharmony_ci case WW_I2SPT: 3078c2ecf20Sopenharmony_ci case WW_FM: 3088c2ecf20Sopenharmony_ci case WW_I2SADC: 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci kfree(samples); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (ret != UNSET) 3158c2ecf20Sopenharmony_ci dprintk(1, "stereo/sap detection result:%s%s%s\n", 3168c2ecf20Sopenharmony_ci (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", 3178c2ecf20Sopenharmony_ci (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", 3188c2ecf20Sopenharmony_ci (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return ret; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx88_dsp_detect_stereo_sap); 3238c2ecf20Sopenharmony_ci 324