18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Renesas R-Car SRC support 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2013 Renesas Solutions Corp. 68c2ecf20Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * you can enable below define if you don't need 108c2ecf20Sopenharmony_ci * SSI interrupt status debug message when debugging 118c2ecf20Sopenharmony_ci * see rsnd_dbg_irq_status() 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * #define RSND_DEBUG_NO_IRQ_STATUS 1 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "rsnd.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define SRC_NAME "src" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* SCU_SYSTEM_STATUS0/1 */ 218c2ecf20Sopenharmony_ci#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct rsnd_src { 248c2ecf20Sopenharmony_ci struct rsnd_mod mod; 258c2ecf20Sopenharmony_ci struct rsnd_mod *dma; 268c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ 278c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s sync; /* sync convert */ 288c2ecf20Sopenharmony_ci int irq; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define RSND_SRC_NAME_SIZE 16 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) 348c2ecf20Sopenharmony_ci#define rsnd_src_nr(priv) ((priv)->src_nr) 358c2ecf20Sopenharmony_ci#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define rsnd_mod_to_src(_mod) \ 388c2ecf20Sopenharmony_ci container_of((_mod), struct rsnd_src, mod) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define for_each_rsnd_src(pos, priv, i) \ 418c2ecf20Sopenharmony_ci for ((i) = 0; \ 428c2ecf20Sopenharmony_ci ((i) < rsnd_src_nr(priv)) && \ 438c2ecf20Sopenharmony_ci ((pos) = (struct rsnd_src *)(priv)->src + i); \ 448c2ecf20Sopenharmony_ci i++) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * image of SRC (Sampling Rate Converter) 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ 518c2ecf20Sopenharmony_ci * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | 528c2ecf20Sopenharmony_ci * 44.1kHz <-> +-----+ +-----+ +-------+ 538c2ecf20Sopenharmony_ci * ... 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void rsnd_src_activation(struct rsnd_mod *mod) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SWRSR, 0); 608c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SWRSR, 1); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void rsnd_src_halt(struct rsnd_mod *mod) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SRCIR, 1); 668c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SWRSR, 0); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, 708c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 738c2ecf20Sopenharmony_ci int is_play = rsnd_io_is_play(io); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return rsnd_dma_request_channel(rsnd_src_of_node(priv), 768c2ecf20Sopenharmony_ci mod, 778c2ecf20Sopenharmony_ci is_play ? "rx" : "tx"); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, 818c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 848c2ecf20Sopenharmony_ci struct rsnd_src *src = rsnd_mod_to_src(mod); 858c2ecf20Sopenharmony_ci u32 convert_rate; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (!runtime) 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!rsnd_src_sync_is_enabled(mod)) 918c2ecf20Sopenharmony_ci return rsnd_io_converted_rate(io); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci convert_rate = src->sync.val; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!convert_rate) 968c2ecf20Sopenharmony_ci convert_rate = rsnd_io_converted_rate(io); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!convert_rate) 998c2ecf20Sopenharmony_ci convert_rate = runtime->rate; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return convert_rate; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciunsigned int rsnd_src_get_rate(struct rsnd_priv *priv, 1058c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 1068c2ecf20Sopenharmony_ci int is_in) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); 1098c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 1108c2ecf20Sopenharmony_ci unsigned int rate = 0; 1118c2ecf20Sopenharmony_ci int is_play = rsnd_io_is_play(io); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * Playback 1158c2ecf20Sopenharmony_ci * runtime_rate -> [SRC] -> convert_rate 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Capture 1188c2ecf20Sopenharmony_ci * convert_rate -> [SRC] -> runtime_rate 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (is_play == is_in) 1228c2ecf20Sopenharmony_ci return runtime->rate; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * return convert rate if SRC is used, 1268c2ecf20Sopenharmony_ci * otherwise, return runtime->rate as usual 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci if (src_mod) 1298c2ecf20Sopenharmony_ci rate = rsnd_src_convert_rate(io, src_mod); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (!rate) 1328c2ecf20Sopenharmony_ci rate = runtime->rate; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return rate; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const u32 bsdsr_table_pattern1[] = { 1388c2ecf20Sopenharmony_ci 0x01800000, /* 6 - 1/6 */ 1398c2ecf20Sopenharmony_ci 0x01000000, /* 6 - 1/4 */ 1408c2ecf20Sopenharmony_ci 0x00c00000, /* 6 - 1/3 */ 1418c2ecf20Sopenharmony_ci 0x00800000, /* 6 - 1/2 */ 1428c2ecf20Sopenharmony_ci 0x00600000, /* 6 - 2/3 */ 1438c2ecf20Sopenharmony_ci 0x00400000, /* 6 - 1 */ 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const u32 bsdsr_table_pattern2[] = { 1478c2ecf20Sopenharmony_ci 0x02400000, /* 6 - 1/6 */ 1488c2ecf20Sopenharmony_ci 0x01800000, /* 6 - 1/4 */ 1498c2ecf20Sopenharmony_ci 0x01200000, /* 6 - 1/3 */ 1508c2ecf20Sopenharmony_ci 0x00c00000, /* 6 - 1/2 */ 1518c2ecf20Sopenharmony_ci 0x00900000, /* 6 - 2/3 */ 1528c2ecf20Sopenharmony_ci 0x00600000, /* 6 - 1 */ 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const u32 bsisr_table[] = { 1568c2ecf20Sopenharmony_ci 0x00100060, /* 6 - 1/6 */ 1578c2ecf20Sopenharmony_ci 0x00100040, /* 6 - 1/4 */ 1588c2ecf20Sopenharmony_ci 0x00100030, /* 6 - 1/3 */ 1598c2ecf20Sopenharmony_ci 0x00100020, /* 6 - 1/2 */ 1608c2ecf20Sopenharmony_ci 0x00100020, /* 6 - 2/3 */ 1618c2ecf20Sopenharmony_ci 0x00100020, /* 6 - 1 */ 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic const u32 chan288888[] = { 1658c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1668c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1678c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1688c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1698c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1708c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const u32 chan244888[] = { 1748c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1758c2ecf20Sopenharmony_ci 0x0000001e, /* 1 to 4 */ 1768c2ecf20Sopenharmony_ci 0x0000001e, /* 1 to 4 */ 1778c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1788c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1798c2ecf20Sopenharmony_ci 0x000001fe, /* 1 to 8 */ 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic const u32 chan222222[] = { 1838c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1848c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1858c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1868c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1878c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1888c2ecf20Sopenharmony_ci 0x00000006, /* 1 to 2 */ 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, 1928c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 1958c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 1968c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 1978c2ecf20Sopenharmony_ci int is_play = rsnd_io_is_play(io); 1988c2ecf20Sopenharmony_ci int use_src = 0; 1998c2ecf20Sopenharmony_ci u32 fin, fout; 2008c2ecf20Sopenharmony_ci u32 ifscr, fsrate, adinr; 2018c2ecf20Sopenharmony_ci u32 cr, route; 2028c2ecf20Sopenharmony_ci u32 i_busif, o_busif, tmp; 2038c2ecf20Sopenharmony_ci const u32 *bsdsr_table; 2048c2ecf20Sopenharmony_ci const u32 *chptn; 2058c2ecf20Sopenharmony_ci uint ratio; 2068c2ecf20Sopenharmony_ci int chan; 2078c2ecf20Sopenharmony_ci int idx; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!runtime) 2108c2ecf20Sopenharmony_ci return; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci fin = rsnd_src_get_in_rate(priv, io); 2138c2ecf20Sopenharmony_ci fout = rsnd_src_get_out_rate(priv, io); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci chan = rsnd_runtime_channel_original(io); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ 2188c2ecf20Sopenharmony_ci if (fin == fout) 2198c2ecf20Sopenharmony_ci ratio = 0; 2208c2ecf20Sopenharmony_ci else if (fin > fout) 2218c2ecf20Sopenharmony_ci ratio = 100 * fin / fout; 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci ratio = 100 * fout / fin; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (ratio > 600) { 2268c2ecf20Sopenharmony_ci dev_err(dev, "FSO/FSI ratio error\n"); 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * SRC_ADINR 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci adinr = rsnd_get_adinr_bit(mod, io) | chan; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * SRC_IFSCR / SRC_IFSVR 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci ifscr = 0; 2418c2ecf20Sopenharmony_ci fsrate = 0; 2428c2ecf20Sopenharmony_ci if (use_src) { 2438c2ecf20Sopenharmony_ci u64 n; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ifscr = 1; 2468c2ecf20Sopenharmony_ci n = (u64)0x0400000 * fin; 2478c2ecf20Sopenharmony_ci do_div(n, fout); 2488c2ecf20Sopenharmony_ci fsrate = n; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * SRC_SRCCR / SRC_ROUTE_MODE0 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci cr = 0x00011110; 2558c2ecf20Sopenharmony_ci route = 0x0; 2568c2ecf20Sopenharmony_ci if (use_src) { 2578c2ecf20Sopenharmony_ci route = 0x1; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (rsnd_src_sync_is_enabled(mod)) { 2608c2ecf20Sopenharmony_ci cr |= 0x1; 2618c2ecf20Sopenharmony_ci route |= rsnd_io_is_play(io) ? 2628c2ecf20Sopenharmony_ci (0x1 << 24) : (0x1 << 25); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * SRC_BSDSR / SRC_BSISR 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * see 2708c2ecf20Sopenharmony_ci * Combination of Register Setting Related to 2718c2ecf20Sopenharmony_ci * FSO/FSI Ratio and Channel, Latency 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci switch (rsnd_mod_id(mod)) { 2748c2ecf20Sopenharmony_ci case 0: 2758c2ecf20Sopenharmony_ci chptn = chan288888; 2768c2ecf20Sopenharmony_ci bsdsr_table = bsdsr_table_pattern1; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case 1: 2798c2ecf20Sopenharmony_ci case 3: 2808c2ecf20Sopenharmony_ci case 4: 2818c2ecf20Sopenharmony_ci chptn = chan244888; 2828c2ecf20Sopenharmony_ci bsdsr_table = bsdsr_table_pattern1; 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci case 2: 2858c2ecf20Sopenharmony_ci case 9: 2868c2ecf20Sopenharmony_ci chptn = chan222222; 2878c2ecf20Sopenharmony_ci bsdsr_table = bsdsr_table_pattern1; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case 5: 2908c2ecf20Sopenharmony_ci case 6: 2918c2ecf20Sopenharmony_ci case 7: 2928c2ecf20Sopenharmony_ci case 8: 2938c2ecf20Sopenharmony_ci chptn = chan222222; 2948c2ecf20Sopenharmony_ci bsdsr_table = bsdsr_table_pattern2; 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci default: 2978c2ecf20Sopenharmony_ci goto convert_rate_err; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * E3 need to overwrite 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci if (rsnd_is_e3(priv)) 3048c2ecf20Sopenharmony_ci switch (rsnd_mod_id(mod)) { 3058c2ecf20Sopenharmony_ci case 0: 3068c2ecf20Sopenharmony_ci case 4: 3078c2ecf20Sopenharmony_ci chptn = chan222222; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) 3118c2ecf20Sopenharmony_ci if (chptn[idx] & (1 << chan)) 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (chan > 8 || 3158c2ecf20Sopenharmony_ci idx >= ARRAY_SIZE(chan222222)) 3168c2ecf20Sopenharmony_ci goto convert_rate_err; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* BUSIF_MODE */ 3198c2ecf20Sopenharmony_ci tmp = rsnd_get_busif_shift(io, mod); 3208c2ecf20Sopenharmony_ci i_busif = ( is_play ? tmp : 0) | 1; 3218c2ecf20Sopenharmony_ci o_busif = (!is_play ? tmp : 0) | 1; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ 3268c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_ADINR, adinr); 3278c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_IFSCR, ifscr); 3288c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_IFSVR, fsrate); 3298c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SRCCR, cr); 3308c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); 3318c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); 3328c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); 3358c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciconvert_rate_err: 3448c2ecf20Sopenharmony_ci dev_err(dev, "unknown BSDSR/BSDIR settings\n"); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int rsnd_src_irq(struct rsnd_mod *mod, 3488c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 3498c2ecf20Sopenharmony_ci struct rsnd_priv *priv, 3508c2ecf20Sopenharmony_ci int enable) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct rsnd_src *src = rsnd_mod_to_src(mod); 3538c2ecf20Sopenharmony_ci u32 sys_int_val, int_val, sys_int_mask; 3548c2ecf20Sopenharmony_ci int irq = src->irq; 3558c2ecf20Sopenharmony_ci int id = rsnd_mod_id(mod); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci sys_int_val = 3588c2ecf20Sopenharmony_ci sys_int_mask = OUF_SRC(id); 3598c2ecf20Sopenharmony_ci int_val = 0x3300; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * IRQ is not supported on non-DT 3638c2ecf20Sopenharmony_ci * see 3648c2ecf20Sopenharmony_ci * rsnd_src_probe_() 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci if ((irq <= 0) || !enable) { 3678c2ecf20Sopenharmony_ci sys_int_val = 0; 3688c2ecf20Sopenharmony_ci int_val = 0; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* 3728c2ecf20Sopenharmony_ci * WORKAROUND 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci * ignore over flow error when rsnd_src_sync_is_enabled() 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci if (rsnd_src_sync_is_enabled(mod)) 3778c2ecf20Sopenharmony_ci sys_int_val = sys_int_val & 0xffff; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); 3808c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); 3818c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void rsnd_src_status_clear(struct rsnd_mod *mod) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci u32 val = OUF_SRC(rsnd_mod_id(mod)); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SCU_SYS_STATUS0, val); 3918c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SCU_SYS_STATUS1, val); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic bool rsnd_src_error_occurred(struct rsnd_mod *mod) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 3978c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 3988c2ecf20Sopenharmony_ci u32 val0, val1; 3998c2ecf20Sopenharmony_ci u32 status0, status1; 4008c2ecf20Sopenharmony_ci bool ret = false; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* 4058c2ecf20Sopenharmony_ci * WORKAROUND 4068c2ecf20Sopenharmony_ci * 4078c2ecf20Sopenharmony_ci * ignore over flow error when rsnd_src_sync_is_enabled() 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci if (rsnd_src_sync_is_enabled(mod)) 4108c2ecf20Sopenharmony_ci val0 = val0 & 0xffff; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); 4138c2ecf20Sopenharmony_ci status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); 4148c2ecf20Sopenharmony_ci if ((status0 & val0) || (status1 & val1)) { 4158c2ecf20Sopenharmony_ci rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", 4168c2ecf20Sopenharmony_ci rsnd_mod_name(mod), status0, status1); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ret = true; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return ret; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int rsnd_src_start(struct rsnd_mod *mod, 4258c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 4268c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci u32 val; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* 4318c2ecf20Sopenharmony_ci * WORKAROUND 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * Enable SRC output if you want to use sync convert together with DVC 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ? 4368c2ecf20Sopenharmony_ci 0x01 : 0x11; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_CTRL, val); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int rsnd_src_stop(struct rsnd_mod *mod, 4448c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 4458c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SRC_CTRL, 0); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int rsnd_src_init(struct rsnd_mod *mod, 4538c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 4548c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct rsnd_src *src = rsnd_mod_to_src(mod); 4578c2ecf20Sopenharmony_ci int ret; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* reset sync convert_rate */ 4608c2ecf20Sopenharmony_ci src->sync.val = 0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ret = rsnd_mod_power_on(mod); 4638c2ecf20Sopenharmony_ci if (ret < 0) 4648c2ecf20Sopenharmony_ci return ret; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci rsnd_src_activation(mod); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci rsnd_src_set_convert_rate(io, mod); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci rsnd_src_status_clear(mod); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int rsnd_src_quit(struct rsnd_mod *mod, 4768c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 4778c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct rsnd_src *src = rsnd_mod_to_src(mod); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci rsnd_src_halt(mod); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci rsnd_mod_power_off(mod); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* reset sync convert_rate */ 4868c2ecf20Sopenharmony_ci src->sync.val = 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic void __rsnd_src_interrupt(struct rsnd_mod *mod, 4928c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 4958c2ecf20Sopenharmony_ci bool stop = false; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* ignore all cases if not working */ 5008c2ecf20Sopenharmony_ci if (!rsnd_io_is_working(io)) 5018c2ecf20Sopenharmony_ci goto rsnd_src_interrupt_out; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (rsnd_src_error_occurred(mod)) 5048c2ecf20Sopenharmony_ci stop = true; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci rsnd_src_status_clear(mod); 5078c2ecf20Sopenharmony_cirsnd_src_interrupt_out: 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (stop) 5128c2ecf20Sopenharmony_ci snd_pcm_stop_xrun(io->substream); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic irqreturn_t rsnd_src_interrupt(int irq, void *data) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct rsnd_mod *mod = data; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci rsnd_mod_interrupt(mod, __rsnd_src_interrupt); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int rsnd_src_probe_(struct rsnd_mod *mod, 5258c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 5268c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct rsnd_src *src = rsnd_mod_to_src(mod); 5298c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 5308c2ecf20Sopenharmony_ci int irq = src->irq; 5318c2ecf20Sopenharmony_ci int ret; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (irq > 0) { 5348c2ecf20Sopenharmony_ci /* 5358c2ecf20Sopenharmony_ci * IRQ is not supported on non-DT 5368c2ecf20Sopenharmony_ci * see 5378c2ecf20Sopenharmony_ci * rsnd_src_irq() 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, 5408c2ecf20Sopenharmony_ci rsnd_src_interrupt, 5418c2ecf20Sopenharmony_ci IRQF_SHARED, 5428c2ecf20Sopenharmony_ci dev_name(dev), mod); 5438c2ecf20Sopenharmony_ci if (ret) 5448c2ecf20Sopenharmony_ci return ret; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = rsnd_dma_attach(io, mod, &src->dma); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return ret; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int rsnd_src_pcm_new(struct rsnd_mod *mod, 5538c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 5548c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct rsnd_src *src = rsnd_mod_to_src(mod); 5578c2ecf20Sopenharmony_ci int ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* 5608c2ecf20Sopenharmony_ci * enable SRC sync convert if possible 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * It can't use SRC Synchronous convert 5658c2ecf20Sopenharmony_ci * when Capture if it uses CMD 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io)) 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * enable sync convert 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci ret = rsnd_kctrl_new_s(mod, io, rtd, 5748c2ecf20Sopenharmony_ci rsnd_io_is_play(io) ? 5758c2ecf20Sopenharmony_ci "SRC Out Rate Switch" : 5768c2ecf20Sopenharmony_ci "SRC In Rate Switch", 5778c2ecf20Sopenharmony_ci rsnd_kctrl_accept_anytime, 5788c2ecf20Sopenharmony_ci rsnd_src_set_convert_rate, 5798c2ecf20Sopenharmony_ci &src->sen, 1); 5808c2ecf20Sopenharmony_ci if (ret < 0) 5818c2ecf20Sopenharmony_ci return ret; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ret = rsnd_kctrl_new_s(mod, io, rtd, 5848c2ecf20Sopenharmony_ci rsnd_io_is_play(io) ? 5858c2ecf20Sopenharmony_ci "SRC Out Rate" : 5868c2ecf20Sopenharmony_ci "SRC In Rate", 5878c2ecf20Sopenharmony_ci rsnd_kctrl_accept_runtime, 5888c2ecf20Sopenharmony_ci rsnd_src_set_convert_rate, 5898c2ecf20Sopenharmony_ci &src->sync, 192000); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return ret; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_src_ops = { 5958c2ecf20Sopenharmony_ci .name = SRC_NAME, 5968c2ecf20Sopenharmony_ci .dma_req = rsnd_src_dma_req, 5978c2ecf20Sopenharmony_ci .probe = rsnd_src_probe_, 5988c2ecf20Sopenharmony_ci .init = rsnd_src_init, 5998c2ecf20Sopenharmony_ci .quit = rsnd_src_quit, 6008c2ecf20Sopenharmony_ci .start = rsnd_src_start, 6018c2ecf20Sopenharmony_ci .stop = rsnd_src_stop, 6028c2ecf20Sopenharmony_ci .irq = rsnd_src_irq, 6038c2ecf20Sopenharmony_ci .pcm_new = rsnd_src_pcm_new, 6048c2ecf20Sopenharmony_ci .get_status = rsnd_mod_get_status, 6058c2ecf20Sopenharmony_ci}; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistruct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) 6108c2ecf20Sopenharmony_ci id = 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return rsnd_mod_get(rsnd_src_get(priv, id)); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ciint rsnd_src_probe(struct rsnd_priv *priv) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct device_node *node; 6188c2ecf20Sopenharmony_ci struct device_node *np; 6198c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 6208c2ecf20Sopenharmony_ci struct rsnd_src *src; 6218c2ecf20Sopenharmony_ci struct clk *clk; 6228c2ecf20Sopenharmony_ci char name[RSND_SRC_NAME_SIZE]; 6238c2ecf20Sopenharmony_ci int i, nr, ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* This driver doesn't support Gen1 at this point */ 6268c2ecf20Sopenharmony_ci if (rsnd_is_gen1(priv)) 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci node = rsnd_src_of_node(priv); 6308c2ecf20Sopenharmony_ci if (!node) 6318c2ecf20Sopenharmony_ci return 0; /* not used is not error */ 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci nr = of_get_child_count(node); 6348c2ecf20Sopenharmony_ci if (!nr) { 6358c2ecf20Sopenharmony_ci ret = -EINVAL; 6368c2ecf20Sopenharmony_ci goto rsnd_src_probe_done; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci src = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL); 6408c2ecf20Sopenharmony_ci if (!src) { 6418c2ecf20Sopenharmony_ci ret = -ENOMEM; 6428c2ecf20Sopenharmony_ci goto rsnd_src_probe_done; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci priv->src_nr = nr; 6468c2ecf20Sopenharmony_ci priv->src = src; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci i = 0; 6498c2ecf20Sopenharmony_ci for_each_child_of_node(node, np) { 6508c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) 6518c2ecf20Sopenharmony_ci goto skip; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci src = rsnd_src_get(priv, i); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", 6568c2ecf20Sopenharmony_ci SRC_NAME, i); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci src->irq = irq_of_parse_and_map(np, 0); 6598c2ecf20Sopenharmony_ci if (!src->irq) { 6608c2ecf20Sopenharmony_ci ret = -EINVAL; 6618c2ecf20Sopenharmony_ci of_node_put(np); 6628c2ecf20Sopenharmony_ci goto rsnd_src_probe_done; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, name); 6668c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 6678c2ecf20Sopenharmony_ci ret = PTR_ERR(clk); 6688c2ecf20Sopenharmony_ci of_node_put(np); 6698c2ecf20Sopenharmony_ci goto rsnd_src_probe_done; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci ret = rsnd_mod_init(priv, rsnd_mod_get(src), 6738c2ecf20Sopenharmony_ci &rsnd_src_ops, clk, RSND_MOD_SRC, i); 6748c2ecf20Sopenharmony_ci if (ret) { 6758c2ecf20Sopenharmony_ci of_node_put(np); 6768c2ecf20Sopenharmony_ci goto rsnd_src_probe_done; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ciskip: 6808c2ecf20Sopenharmony_ci i++; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci ret = 0; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cirsnd_src_probe_done: 6868c2ecf20Sopenharmony_ci of_node_put(node); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return ret; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_civoid rsnd_src_remove(struct rsnd_priv *priv) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct rsnd_src *src; 6948c2ecf20Sopenharmony_ci int i; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci for_each_rsnd_src(src, priv, i) { 6978c2ecf20Sopenharmony_ci rsnd_mod_quit(rsnd_mod_get(src)); 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci} 700