11e0edd4dSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0 21e0edd4dSKuninori Morimoto // 31e0edd4dSKuninori Morimoto // Renesas R-Car SRC support 41e0edd4dSKuninori Morimoto // 51e0edd4dSKuninori Morimoto // Copyright (C) 2013 Renesas Solutions Corp. 61e0edd4dSKuninori Morimoto // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 72b627869SKuninori Morimoto 82b627869SKuninori Morimoto /* 963346d3dSKuninori Morimoto * You can use Synchronous Sampling Rate Convert (if no DVC) 1063346d3dSKuninori Morimoto * 1163346d3dSKuninori Morimoto * amixer set "SRC Out Rate" on 1263346d3dSKuninori Morimoto * aplay xxx.wav & 1363346d3dSKuninori Morimoto * amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz 1463346d3dSKuninori Morimoto * amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz 1563346d3dSKuninori Morimoto */ 1663346d3dSKuninori Morimoto 1763346d3dSKuninori Morimoto /* 182b627869SKuninori Morimoto * you can enable below define if you don't need 192b627869SKuninori Morimoto * SSI interrupt status debug message when debugging 201788a152SKuninori Morimoto * see rsnd_print_irq_status() 212b627869SKuninori Morimoto * 222b627869SKuninori Morimoto * #define RSND_DEBUG_NO_IRQ_STATUS 1 232b627869SKuninori Morimoto */ 242b627869SKuninori Morimoto 25ba9c949fSKuninori Morimoto #include "rsnd.h" 26ba9c949fSKuninori Morimoto 278aefda50SKuninori Morimoto #define SRC_NAME "src" 288aefda50SKuninori Morimoto 29cfcefe01SKuninori Morimoto /* SCU_SYSTEM_STATUS0/1 */ 30cfcefe01SKuninori Morimoto #define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) 31cfcefe01SKuninori Morimoto 32ba9c949fSKuninori Morimoto struct rsnd_src { 33ba9c949fSKuninori Morimoto struct rsnd_mod mod; 34940e9479SKuninori Morimoto struct rsnd_mod *dma; 3543cb6954SKuninori Morimoto struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ 3643cb6954SKuninori Morimoto struct rsnd_kctrl_cfg_s sync; /* sync convert */ 37adf6a681SKuninori Morimoto int irq; 38ba9c949fSKuninori Morimoto }; 39ba9c949fSKuninori Morimoto 40ba9c949fSKuninori Morimoto #define RSND_SRC_NAME_SIZE 16 41ba9c949fSKuninori Morimoto 42adf6a681SKuninori Morimoto #define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) 43da599fd3SKuninori Morimoto #define rsnd_src_nr(priv) ((priv)->src_nr) 44ab2049f9SKuninori Morimoto #define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val) 4582e76ed3SKuninori Morimoto 46ba9c949fSKuninori Morimoto #define rsnd_mod_to_src(_mod) \ 47ba9c949fSKuninori Morimoto container_of((_mod), struct rsnd_src, mod) 48ba9c949fSKuninori Morimoto 49ba9c949fSKuninori Morimoto #define for_each_rsnd_src(pos, priv, i) \ 50ba9c949fSKuninori Morimoto for ((i) = 0; \ 51ba9c949fSKuninori Morimoto ((i) < rsnd_src_nr(priv)) && \ 52ba9c949fSKuninori Morimoto ((pos) = (struct rsnd_src *)(priv)->src + i); \ 53ba9c949fSKuninori Morimoto i++) 54ba9c949fSKuninori Morimoto 55ba9c949fSKuninori Morimoto 56ba9c949fSKuninori Morimoto /* 57ba9c949fSKuninori Morimoto * image of SRC (Sampling Rate Converter) 58ba9c949fSKuninori Morimoto * 59ba9c949fSKuninori Morimoto * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ 60ba9c949fSKuninori Morimoto * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | 61ba9c949fSKuninori Morimoto * 44.1kHz <-> +-----+ +-----+ +-------+ 62ba9c949fSKuninori Morimoto * ... 63ba9c949fSKuninori Morimoto * 64ba9c949fSKuninori Morimoto */ 65ba9c949fSKuninori Morimoto 6698efeeaeSKuninori Morimoto static void rsnd_src_activation(struct rsnd_mod *mod) 67379febfdSKuninori Morimoto { 68379febfdSKuninori Morimoto rsnd_mod_write(mod, SRC_SWRSR, 0); 69379febfdSKuninori Morimoto rsnd_mod_write(mod, SRC_SWRSR, 1); 70379febfdSKuninori Morimoto } 71379febfdSKuninori Morimoto 72475a361aSKuninori Morimoto static void rsnd_src_halt(struct rsnd_mod *mod) 73475a361aSKuninori Morimoto { 74475a361aSKuninori Morimoto rsnd_mod_write(mod, SRC_SRCIR, 1); 75475a361aSKuninori Morimoto rsnd_mod_write(mod, SRC_SWRSR, 0); 76475a361aSKuninori Morimoto } 77475a361aSKuninori Morimoto 789b99e9a7SKuninori Morimoto static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, 799b99e9a7SKuninori Morimoto struct rsnd_mod *mod) 8072adc61fSKuninori Morimoto { 8172adc61fSKuninori Morimoto struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 8272adc61fSKuninori Morimoto int is_play = rsnd_io_is_play(io); 8372adc61fSKuninori Morimoto 8472adc61fSKuninori Morimoto return rsnd_dma_request_channel(rsnd_src_of_node(priv), 85039f2cccSKuninori Morimoto SRC_NAME, mod, 8672adc61fSKuninori Morimoto is_play ? "rx" : "tx"); 8772adc61fSKuninori Morimoto } 8872adc61fSKuninori Morimoto 8988c61cffSKuninori Morimoto static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, 901a9be9eeSKuninori Morimoto struct rsnd_mod *mod) 9143cb6954SKuninori Morimoto { 9243cb6954SKuninori Morimoto struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 931a9be9eeSKuninori Morimoto struct rsnd_src *src = rsnd_mod_to_src(mod); 9443cb6954SKuninori Morimoto u32 convert_rate; 9543cb6954SKuninori Morimoto 9643cb6954SKuninori Morimoto if (!runtime) 9743cb6954SKuninori Morimoto return 0; 9843cb6954SKuninori Morimoto 99ab2049f9SKuninori Morimoto if (!rsnd_src_sync_is_enabled(mod)) 100c2aaaa57SKuninori Morimoto return rsnd_io_converted_rate(io); 10143cb6954SKuninori Morimoto 10243cb6954SKuninori Morimoto convert_rate = src->sync.val; 10343cb6954SKuninori Morimoto 10443cb6954SKuninori Morimoto if (!convert_rate) 105c2aaaa57SKuninori Morimoto convert_rate = rsnd_io_converted_rate(io); 10643cb6954SKuninori Morimoto 10743cb6954SKuninori Morimoto if (!convert_rate) 10843cb6954SKuninori Morimoto convert_rate = runtime->rate; 10943cb6954SKuninori Morimoto 11043cb6954SKuninori Morimoto return convert_rate; 11143cb6954SKuninori Morimoto } 11243cb6954SKuninori Morimoto 113cbf1494fSKuninori Morimoto unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, 114ba9c949fSKuninori Morimoto struct rsnd_dai_stream *io, 115cbf1494fSKuninori Morimoto int is_in) 116ba9c949fSKuninori Morimoto { 117b1eac430SKuninori Morimoto struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); 118cbf1494fSKuninori Morimoto struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 119b1eac430SKuninori Morimoto unsigned int rate = 0; 120cbf1494fSKuninori Morimoto int is_play = rsnd_io_is_play(io); 121cbf1494fSKuninori Morimoto 122cbf1494fSKuninori Morimoto /* 123cbf1494fSKuninori Morimoto * Playback 124cbf1494fSKuninori Morimoto * runtime_rate -> [SRC] -> convert_rate 125cbf1494fSKuninori Morimoto * 126cbf1494fSKuninori Morimoto * Capture 127cbf1494fSKuninori Morimoto * convert_rate -> [SRC] -> runtime_rate 128cbf1494fSKuninori Morimoto */ 129cbf1494fSKuninori Morimoto 130cbf1494fSKuninori Morimoto if (is_play == is_in) 131cbf1494fSKuninori Morimoto return runtime->rate; 132ba9c949fSKuninori Morimoto 133ba9c949fSKuninori Morimoto /* 134ba9c949fSKuninori Morimoto * return convert rate if SRC is used, 135ba9c949fSKuninori Morimoto * otherwise, return runtime->rate as usual 136ba9c949fSKuninori Morimoto */ 1371a9be9eeSKuninori Morimoto if (src_mod) 1381a9be9eeSKuninori Morimoto rate = rsnd_src_convert_rate(io, src_mod); 139b1eac430SKuninori Morimoto 140ba9c949fSKuninori Morimoto if (!rate) 141ba9c949fSKuninori Morimoto rate = runtime->rate; 142ba9c949fSKuninori Morimoto 143ba9c949fSKuninori Morimoto return rate; 144ba9c949fSKuninori Morimoto } 145ba9c949fSKuninori Morimoto 146399706dfSJiada Wang static const u32 bsdsr_table_pattern1[] = { 1477674bec4SKuninori Morimoto 0x01800000, /* 6 - 1/6 */ 1487674bec4SKuninori Morimoto 0x01000000, /* 6 - 1/4 */ 1497674bec4SKuninori Morimoto 0x00c00000, /* 6 - 1/3 */ 1507674bec4SKuninori Morimoto 0x00800000, /* 6 - 1/2 */ 1517674bec4SKuninori Morimoto 0x00600000, /* 6 - 2/3 */ 1527674bec4SKuninori Morimoto 0x00400000, /* 6 - 1 */ 1537674bec4SKuninori Morimoto }; 1547674bec4SKuninori Morimoto 155399706dfSJiada Wang static const u32 bsdsr_table_pattern2[] = { 1567674bec4SKuninori Morimoto 0x02400000, /* 6 - 1/6 */ 1577674bec4SKuninori Morimoto 0x01800000, /* 6 - 1/4 */ 1587674bec4SKuninori Morimoto 0x01200000, /* 6 - 1/3 */ 1597674bec4SKuninori Morimoto 0x00c00000, /* 6 - 1/2 */ 1607674bec4SKuninori Morimoto 0x00900000, /* 6 - 2/3 */ 1617674bec4SKuninori Morimoto 0x00600000, /* 6 - 1 */ 1627674bec4SKuninori Morimoto }; 1637674bec4SKuninori Morimoto 164399706dfSJiada Wang static const u32 bsisr_table[] = { 1657674bec4SKuninori Morimoto 0x00100060, /* 6 - 1/6 */ 1667674bec4SKuninori Morimoto 0x00100040, /* 6 - 1/4 */ 1677674bec4SKuninori Morimoto 0x00100030, /* 6 - 1/3 */ 1687674bec4SKuninori Morimoto 0x00100020, /* 6 - 1/2 */ 1697674bec4SKuninori Morimoto 0x00100020, /* 6 - 2/3 */ 1707674bec4SKuninori Morimoto 0x00100020, /* 6 - 1 */ 1717674bec4SKuninori Morimoto }; 1727674bec4SKuninori Morimoto 173399706dfSJiada Wang static const u32 chan288888[] = { 1747674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1757674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1767674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1777674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1787674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1797674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1807674bec4SKuninori Morimoto }; 1817674bec4SKuninori Morimoto 182399706dfSJiada Wang static const u32 chan244888[] = { 1837674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1847674bec4SKuninori Morimoto 0x0000001e, /* 1 to 4 */ 1857674bec4SKuninori Morimoto 0x0000001e, /* 1 to 4 */ 1867674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1877674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1887674bec4SKuninori Morimoto 0x000001fe, /* 1 to 8 */ 1897674bec4SKuninori Morimoto }; 1907674bec4SKuninori Morimoto 191399706dfSJiada Wang static const u32 chan222222[] = { 1927674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1937674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1947674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1957674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1967674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1977674bec4SKuninori Morimoto 0x00000006, /* 1 to 2 */ 1987674bec4SKuninori Morimoto }; 1997674bec4SKuninori Morimoto 20075916f65SKuninori Morimoto static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, 20175916f65SKuninori Morimoto struct rsnd_mod *mod) 202ba9c949fSKuninori Morimoto { 20375916f65SKuninori Morimoto struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 204cfcefe01SKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 20575916f65SKuninori Morimoto struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 20690431eb4SKuninori Morimoto int is_play = rsnd_io_is_play(io); 20767923f77SKuninori Morimoto int use_src = 0; 2080102eed5SKuninori Morimoto u32 fin, fout; 20975916f65SKuninori Morimoto u32 ifscr, fsrate, adinr; 21075916f65SKuninori Morimoto u32 cr, route; 21190431eb4SKuninori Morimoto u32 i_busif, o_busif, tmp; 2127674bec4SKuninori Morimoto const u32 *bsdsr_table; 2137674bec4SKuninori Morimoto const u32 *chptn; 21475916f65SKuninori Morimoto uint ratio; 2157674bec4SKuninori Morimoto int chan; 2167674bec4SKuninori Morimoto int idx; 217ba9c949fSKuninori Morimoto 21875916f65SKuninori Morimoto if (!runtime) 21975916f65SKuninori Morimoto return; 220ba9c949fSKuninori Morimoto 2210102eed5SKuninori Morimoto fin = rsnd_src_get_in_rate(priv, io); 2220102eed5SKuninori Morimoto fout = rsnd_src_get_out_rate(priv, io); 2230102eed5SKuninori Morimoto 2247674bec4SKuninori Morimoto chan = rsnd_runtime_channel_original(io); 2257674bec4SKuninori Morimoto 22675916f65SKuninori Morimoto /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ 2270102eed5SKuninori Morimoto if (fin == fout) 22875916f65SKuninori Morimoto ratio = 0; 2290102eed5SKuninori Morimoto else if (fin > fout) 2300102eed5SKuninori Morimoto ratio = 100 * fin / fout; 23175916f65SKuninori Morimoto else 2320102eed5SKuninori Morimoto ratio = 100 * fout / fin; 233cfcefe01SKuninori Morimoto 23475916f65SKuninori Morimoto if (ratio > 600) { 23575916f65SKuninori Morimoto dev_err(dev, "FSO/FSI ratio error\n"); 23675916f65SKuninori Morimoto return; 237ba9c949fSKuninori Morimoto } 238ba9c949fSKuninori Morimoto 23967923f77SKuninori Morimoto use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); 24067923f77SKuninori Morimoto 241ba9c949fSKuninori Morimoto /* 24275916f65SKuninori Morimoto * SRC_ADINR 243ba9c949fSKuninori Morimoto */ 2447674bec4SKuninori Morimoto adinr = rsnd_get_adinr_bit(mod, io) | chan; 24575916f65SKuninori Morimoto 24675916f65SKuninori Morimoto /* 24775916f65SKuninori Morimoto * SRC_IFSCR / SRC_IFSVR 24875916f65SKuninori Morimoto */ 24975916f65SKuninori Morimoto ifscr = 0; 25075916f65SKuninori Morimoto fsrate = 0; 25167923f77SKuninori Morimoto if (use_src) { 25293ca33c9SHiroyuki Yokoyama u64 n; 25393ca33c9SHiroyuki Yokoyama 25475916f65SKuninori Morimoto ifscr = 1; 25593ca33c9SHiroyuki Yokoyama n = (u64)0x0400000 * fin; 25693ca33c9SHiroyuki Yokoyama do_div(n, fout); 25793ca33c9SHiroyuki Yokoyama fsrate = n; 25875916f65SKuninori Morimoto } 25975916f65SKuninori Morimoto 26075916f65SKuninori Morimoto /* 26175916f65SKuninori Morimoto * SRC_SRCCR / SRC_ROUTE_MODE0 26275916f65SKuninori Morimoto */ 26375916f65SKuninori Morimoto cr = 0x00011110; 26475916f65SKuninori Morimoto route = 0x0; 26567923f77SKuninori Morimoto if (use_src) { 26675916f65SKuninori Morimoto route = 0x1; 26775916f65SKuninori Morimoto 268ab2049f9SKuninori Morimoto if (rsnd_src_sync_is_enabled(mod)) { 26975916f65SKuninori Morimoto cr |= 0x1; 27075916f65SKuninori Morimoto route |= rsnd_io_is_play(io) ? 27175916f65SKuninori Morimoto (0x1 << 24) : (0x1 << 25); 27275916f65SKuninori Morimoto } 27375916f65SKuninori Morimoto } 27475916f65SKuninori Morimoto 27575916f65SKuninori Morimoto /* 27675916f65SKuninori Morimoto * SRC_BSDSR / SRC_BSISR 2777674bec4SKuninori Morimoto * 2787674bec4SKuninori Morimoto * see 2797674bec4SKuninori Morimoto * Combination of Register Setting Related to 2807674bec4SKuninori Morimoto * FSO/FSI Ratio and Channel, Latency 28175916f65SKuninori Morimoto */ 28275916f65SKuninori Morimoto switch (rsnd_mod_id(mod)) { 2837674bec4SKuninori Morimoto case 0: 2847674bec4SKuninori Morimoto chptn = chan288888; 2857674bec4SKuninori Morimoto bsdsr_table = bsdsr_table_pattern1; 2867674bec4SKuninori Morimoto break; 2877674bec4SKuninori Morimoto case 1: 2887674bec4SKuninori Morimoto case 3: 2897674bec4SKuninori Morimoto case 4: 2907674bec4SKuninori Morimoto chptn = chan244888; 2917674bec4SKuninori Morimoto bsdsr_table = bsdsr_table_pattern1; 2927674bec4SKuninori Morimoto break; 2937674bec4SKuninori Morimoto case 2: 2947674bec4SKuninori Morimoto case 9: 2957674bec4SKuninori Morimoto chptn = chan222222; 2967674bec4SKuninori Morimoto bsdsr_table = bsdsr_table_pattern1; 2977674bec4SKuninori Morimoto break; 29875916f65SKuninori Morimoto case 5: 29975916f65SKuninori Morimoto case 6: 30075916f65SKuninori Morimoto case 7: 30175916f65SKuninori Morimoto case 8: 3027674bec4SKuninori Morimoto chptn = chan222222; 3037674bec4SKuninori Morimoto bsdsr_table = bsdsr_table_pattern2; 30475916f65SKuninori Morimoto break; 30575916f65SKuninori Morimoto default: 3067674bec4SKuninori Morimoto goto convert_rate_err; 30775916f65SKuninori Morimoto } 30875916f65SKuninori Morimoto 3097674bec4SKuninori Morimoto /* 3107674bec4SKuninori Morimoto * E3 need to overwrite 3117674bec4SKuninori Morimoto */ 312ba164a49SJiada Wang if (rsnd_is_e3(priv)) 3137674bec4SKuninori Morimoto switch (rsnd_mod_id(mod)) { 3147674bec4SKuninori Morimoto case 0: 3157674bec4SKuninori Morimoto case 4: 3167674bec4SKuninori Morimoto chptn = chan222222; 3177674bec4SKuninori Morimoto } 3187674bec4SKuninori Morimoto 3197674bec4SKuninori Morimoto for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) 3207674bec4SKuninori Morimoto if (chptn[idx] & (1 << chan)) 3217674bec4SKuninori Morimoto break; 3227674bec4SKuninori Morimoto 3237674bec4SKuninori Morimoto if (chan > 8 || 3247674bec4SKuninori Morimoto idx >= ARRAY_SIZE(chan222222)) 3257674bec4SKuninori Morimoto goto convert_rate_err; 3267674bec4SKuninori Morimoto 32790431eb4SKuninori Morimoto /* BUSIF_MODE */ 32890431eb4SKuninori Morimoto tmp = rsnd_get_busif_shift(io, mod); 32990431eb4SKuninori Morimoto i_busif = ( is_play ? tmp : 0) | 1; 33090431eb4SKuninori Morimoto o_busif = (!is_play ? tmp : 0) | 1; 33190431eb4SKuninori Morimoto 3320fbab951SKuninori Morimoto rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); 3330fbab951SKuninori Morimoto 33475916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ 33575916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_ADINR, adinr); 33675916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_IFSCR, ifscr); 33775916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_IFSVR, fsrate); 33875916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_SRCCR, cr); 3397674bec4SKuninori Morimoto rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); 3407674bec4SKuninori Morimoto rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); 34175916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ 34275916f65SKuninori Morimoto 34390431eb4SKuninori Morimoto rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); 34490431eb4SKuninori Morimoto rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif); 34590431eb4SKuninori Morimoto 34675916f65SKuninori Morimoto rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); 34775916f65SKuninori Morimoto 3480102eed5SKuninori Morimoto rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); 3497674bec4SKuninori Morimoto 3507674bec4SKuninori Morimoto return; 3517674bec4SKuninori Morimoto 3527674bec4SKuninori Morimoto convert_rate_err: 3537674bec4SKuninori Morimoto dev_err(dev, "unknown BSDSR/BSDIR settings\n"); 35475916f65SKuninori Morimoto } 35575916f65SKuninori Morimoto 356b5b442abSKuninori Morimoto static int rsnd_src_irq(struct rsnd_mod *mod, 357b5b442abSKuninori Morimoto struct rsnd_dai_stream *io, 358b5b442abSKuninori Morimoto struct rsnd_priv *priv, 359b5b442abSKuninori Morimoto int enable) 360cfcefe01SKuninori Morimoto { 361cfcefe01SKuninori Morimoto struct rsnd_src *src = rsnd_mod_to_src(mod); 362cfcefe01SKuninori Morimoto u32 sys_int_val, int_val, sys_int_mask; 363adf6a681SKuninori Morimoto int irq = src->irq; 364cfcefe01SKuninori Morimoto int id = rsnd_mod_id(mod); 365cfcefe01SKuninori Morimoto 366cfcefe01SKuninori Morimoto sys_int_val = 367cfcefe01SKuninori Morimoto sys_int_mask = OUF_SRC(id); 368cfcefe01SKuninori Morimoto int_val = 0x3300; 369cfcefe01SKuninori Morimoto 370cfcefe01SKuninori Morimoto /* 371cfcefe01SKuninori Morimoto * IRQ is not supported on non-DT 372cfcefe01SKuninori Morimoto * see 37375916f65SKuninori Morimoto * rsnd_src_probe_() 374cfcefe01SKuninori Morimoto */ 375cfcefe01SKuninori Morimoto if ((irq <= 0) || !enable) { 376cfcefe01SKuninori Morimoto sys_int_val = 0; 377cfcefe01SKuninori Morimoto int_val = 0; 378cfcefe01SKuninori Morimoto } 379cfcefe01SKuninori Morimoto 3801a1bf58aSKuninori Morimoto /* 3811a1bf58aSKuninori Morimoto * WORKAROUND 3821a1bf58aSKuninori Morimoto * 383ab2049f9SKuninori Morimoto * ignore over flow error when rsnd_src_sync_is_enabled() 3841a1bf58aSKuninori Morimoto */ 385ab2049f9SKuninori Morimoto if (rsnd_src_sync_is_enabled(mod)) 3861a1bf58aSKuninori Morimoto sys_int_val = sys_int_val & 0xffff; 3871a1bf58aSKuninori Morimoto 388cfcefe01SKuninori Morimoto rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); 389cfcefe01SKuninori Morimoto rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); 390cfcefe01SKuninori Morimoto rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); 391b5b442abSKuninori Morimoto 392b5b442abSKuninori Morimoto return 0; 393cfcefe01SKuninori Morimoto } 394cfcefe01SKuninori Morimoto 3958cc225f7SKuninori Morimoto static void rsnd_src_status_clear(struct rsnd_mod *mod) 396cfcefe01SKuninori Morimoto { 397cfcefe01SKuninori Morimoto u32 val = OUF_SRC(rsnd_mod_id(mod)); 398cfcefe01SKuninori Morimoto 39942b197e7SKuninori Morimoto rsnd_mod_write(mod, SCU_SYS_STATUS0, val); 40042b197e7SKuninori Morimoto rsnd_mod_write(mod, SCU_SYS_STATUS1, val); 401cfcefe01SKuninori Morimoto } 402cfcefe01SKuninori Morimoto 4036a25c8daSKuninori Morimoto static bool rsnd_src_error_occurred(struct rsnd_mod *mod) 404cfcefe01SKuninori Morimoto { 4052b627869SKuninori Morimoto struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 4062b627869SKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 4071a1bf58aSKuninori Morimoto u32 val0, val1; 4082b627869SKuninori Morimoto u32 status0, status1; 409cfcefe01SKuninori Morimoto bool ret = false; 410cfcefe01SKuninori Morimoto 4111a1bf58aSKuninori Morimoto val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); 4121a1bf58aSKuninori Morimoto 4131a1bf58aSKuninori Morimoto /* 4141a1bf58aSKuninori Morimoto * WORKAROUND 4151a1bf58aSKuninori Morimoto * 416ab2049f9SKuninori Morimoto * ignore over flow error when rsnd_src_sync_is_enabled() 4171a1bf58aSKuninori Morimoto */ 418ab2049f9SKuninori Morimoto if (rsnd_src_sync_is_enabled(mod)) 4191a1bf58aSKuninori Morimoto val0 = val0 & 0xffff; 4201a1bf58aSKuninori Morimoto 4212b627869SKuninori Morimoto status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); 4222b627869SKuninori Morimoto status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); 4232b627869SKuninori Morimoto if ((status0 & val0) || (status1 & val1)) { 4241788a152SKuninori Morimoto rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", 425c0ea089dSKuninori Morimoto rsnd_mod_name(mod), status0, status1); 4262b627869SKuninori Morimoto 427cfcefe01SKuninori Morimoto ret = true; 4282b627869SKuninori Morimoto } 429cfcefe01SKuninori Morimoto 430cfcefe01SKuninori Morimoto return ret; 431cfcefe01SKuninori Morimoto } 432cfcefe01SKuninori Morimoto 43375916f65SKuninori Morimoto static int rsnd_src_start(struct rsnd_mod *mod, 434497debaaSKuninori Morimoto struct rsnd_dai_stream *io, 435497debaaSKuninori Morimoto struct rsnd_priv *priv) 436cfcefe01SKuninori Morimoto { 4371a1bf58aSKuninori Morimoto u32 val; 4381a1bf58aSKuninori Morimoto 4391a1bf58aSKuninori Morimoto /* 4401a1bf58aSKuninori Morimoto * WORKAROUND 4411a1bf58aSKuninori Morimoto * 4421a1bf58aSKuninori Morimoto * Enable SRC output if you want to use sync convert together with DVC 4431a1bf58aSKuninori Morimoto */ 444ab2049f9SKuninori Morimoto val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ? 4451a1bf58aSKuninori Morimoto 0x01 : 0x11; 446cfcefe01SKuninori Morimoto 447cfcefe01SKuninori Morimoto rsnd_mod_write(mod, SRC_CTRL, val); 448cfcefe01SKuninori Morimoto 44975916f65SKuninori Morimoto return 0; 45075916f65SKuninori Morimoto } 451cfcefe01SKuninori Morimoto 45275916f65SKuninori Morimoto static int rsnd_src_stop(struct rsnd_mod *mod, 45375916f65SKuninori Morimoto struct rsnd_dai_stream *io, 45475916f65SKuninori Morimoto struct rsnd_priv *priv) 45575916f65SKuninori Morimoto { 45631739a68SKuninori Morimoto rsnd_mod_write(mod, SRC_CTRL, 0); 457cfcefe01SKuninori Morimoto 458cfcefe01SKuninori Morimoto return 0; 459cfcefe01SKuninori Morimoto } 460cfcefe01SKuninori Morimoto 46175916f65SKuninori Morimoto static int rsnd_src_init(struct rsnd_mod *mod, 462497debaaSKuninori Morimoto struct rsnd_dai_stream *io, 463497debaaSKuninori Morimoto struct rsnd_priv *priv) 464cfcefe01SKuninori Morimoto { 46575916f65SKuninori Morimoto struct rsnd_src *src = rsnd_mod_to_src(mod); 466cfcefe01SKuninori Morimoto 467ef30da1cSKuninori Morimoto /* reset sync convert_rate */ 468ef30da1cSKuninori Morimoto src->sync.val = 0; 469ef30da1cSKuninori Morimoto 47075916f65SKuninori Morimoto rsnd_mod_power_on(mod); 471cfcefe01SKuninori Morimoto 47298efeeaeSKuninori Morimoto rsnd_src_activation(mod); 473cfcefe01SKuninori Morimoto 47475916f65SKuninori Morimoto rsnd_src_set_convert_rate(io, mod); 47575916f65SKuninori Morimoto 4768cc225f7SKuninori Morimoto rsnd_src_status_clear(mod); 47775916f65SKuninori Morimoto 47875916f65SKuninori Morimoto return 0; 479cfcefe01SKuninori Morimoto } 480cfcefe01SKuninori Morimoto 48175916f65SKuninori Morimoto static int rsnd_src_quit(struct rsnd_mod *mod, 482b761bf27SKuninori Morimoto struct rsnd_dai_stream *io, 483b761bf27SKuninori Morimoto struct rsnd_priv *priv) 484b761bf27SKuninori Morimoto { 48575916f65SKuninori Morimoto struct rsnd_src *src = rsnd_mod_to_src(mod); 48675916f65SKuninori Morimoto 487475a361aSKuninori Morimoto rsnd_src_halt(mod); 488475a361aSKuninori Morimoto 48975916f65SKuninori Morimoto rsnd_mod_power_off(mod); 49075916f65SKuninori Morimoto 49175916f65SKuninori Morimoto /* reset sync convert_rate */ 49275916f65SKuninori Morimoto src->sync.val = 0; 49375916f65SKuninori Morimoto 49475916f65SKuninori Morimoto return 0; 495b761bf27SKuninori Morimoto } 496b761bf27SKuninori Morimoto 49775916f65SKuninori Morimoto static void __rsnd_src_interrupt(struct rsnd_mod *mod, 49888c61cffSKuninori Morimoto struct rsnd_dai_stream *io) 499cfcefe01SKuninori Morimoto { 50002299d98SKuninori Morimoto struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 5016a25c8daSKuninori Morimoto bool stop = false; 502cfcefe01SKuninori Morimoto 50302299d98SKuninori Morimoto spin_lock(&priv->lock); 50402299d98SKuninori Morimoto 50502299d98SKuninori Morimoto /* ignore all cases if not working */ 506d5bbe7deSKuninori Morimoto if (!rsnd_io_is_working(io)) 50775916f65SKuninori Morimoto goto rsnd_src_interrupt_out; 508cfcefe01SKuninori Morimoto 5096a25c8daSKuninori Morimoto if (rsnd_src_error_occurred(mod)) 5106a25c8daSKuninori Morimoto stop = true; 51188c61cffSKuninori Morimoto 5128cc225f7SKuninori Morimoto rsnd_src_status_clear(mod); 51375916f65SKuninori Morimoto rsnd_src_interrupt_out: 5148cc225f7SKuninori Morimoto 51502299d98SKuninori Morimoto spin_unlock(&priv->lock); 5166a25c8daSKuninori Morimoto 5176a25c8daSKuninori Morimoto if (stop) 5186a25c8daSKuninori Morimoto snd_pcm_stop_xrun(io->substream); 51988c61cffSKuninori Morimoto } 52088c61cffSKuninori Morimoto 52175916f65SKuninori Morimoto static irqreturn_t rsnd_src_interrupt(int irq, void *data) 52288c61cffSKuninori Morimoto { 52388c61cffSKuninori Morimoto struct rsnd_mod *mod = data; 52488c61cffSKuninori Morimoto 52575916f65SKuninori Morimoto rsnd_mod_interrupt(mod, __rsnd_src_interrupt); 526cfcefe01SKuninori Morimoto 527cfcefe01SKuninori Morimoto return IRQ_HANDLED; 528cfcefe01SKuninori Morimoto } 529cfcefe01SKuninori Morimoto 53075916f65SKuninori Morimoto static int rsnd_src_probe_(struct rsnd_mod *mod, 5312c0fac19SKuninori Morimoto struct rsnd_dai_stream *io, 532690602fcSKuninori Morimoto struct rsnd_priv *priv) 533ba9c949fSKuninori Morimoto { 534ba9c949fSKuninori Morimoto struct rsnd_src *src = rsnd_mod_to_src(mod); 535ba9c949fSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 536adf6a681SKuninori Morimoto int irq = src->irq; 537ba9c949fSKuninori Morimoto int ret; 538ba9c949fSKuninori Morimoto 539cfcefe01SKuninori Morimoto if (irq > 0) { 540cfcefe01SKuninori Morimoto /* 541cfcefe01SKuninori Morimoto * IRQ is not supported on non-DT 542cfcefe01SKuninori Morimoto * see 543b5b442abSKuninori Morimoto * rsnd_src_irq() 544cfcefe01SKuninori Morimoto */ 545cfcefe01SKuninori Morimoto ret = devm_request_irq(dev, irq, 54675916f65SKuninori Morimoto rsnd_src_interrupt, 547cfcefe01SKuninori Morimoto IRQF_SHARED, 548cfcefe01SKuninori Morimoto dev_name(dev), mod); 549cfcefe01SKuninori Morimoto if (ret) 550b543b52aSKuninori Morimoto return ret; 551cfcefe01SKuninori Morimoto } 552cfcefe01SKuninori Morimoto 553b99305d2SKuninori Morimoto ret = rsnd_dma_attach(io, mod, &src->dma); 554cfcefe01SKuninori Morimoto 555cfcefe01SKuninori Morimoto return ret; 556ba9c949fSKuninori Morimoto } 557ba9c949fSKuninori Morimoto 55875916f65SKuninori Morimoto static int rsnd_src_pcm_new(struct rsnd_mod *mod, 5592c0fac19SKuninori Morimoto struct rsnd_dai_stream *io, 56043cb6954SKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 56143cb6954SKuninori Morimoto { 56243cb6954SKuninori Morimoto struct rsnd_src *src = rsnd_mod_to_src(mod); 56343cb6954SKuninori Morimoto int ret; 56443cb6954SKuninori Morimoto 56543cb6954SKuninori Morimoto /* 56643cb6954SKuninori Morimoto * enable SRC sync convert if possible 56743cb6954SKuninori Morimoto */ 56843cb6954SKuninori Morimoto 56943cb6954SKuninori Morimoto /* 57061a219feSKuninori Morimoto * It can't use SRC Synchronous convert 57161a219feSKuninori Morimoto * when Capture if it uses CMD 5727115cb91SKuninori Morimoto */ 57361a219feSKuninori Morimoto if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io)) 5747115cb91SKuninori Morimoto return 0; 5757115cb91SKuninori Morimoto 5767115cb91SKuninori Morimoto /* 57743cb6954SKuninori Morimoto * enable sync convert 57843cb6954SKuninori Morimoto */ 579b65a7cccSKuninori Morimoto ret = rsnd_kctrl_new_s(mod, io, rtd, 58043cb6954SKuninori Morimoto rsnd_io_is_play(io) ? 58143cb6954SKuninori Morimoto "SRC Out Rate Switch" : 58243cb6954SKuninori Morimoto "SRC In Rate Switch", 583f0b04d8bSKuninori Morimoto rsnd_kctrl_accept_anytime, 58475916f65SKuninori Morimoto rsnd_src_set_convert_rate, 58543cb6954SKuninori Morimoto &src->sen, 1); 58643cb6954SKuninori Morimoto if (ret < 0) 58743cb6954SKuninori Morimoto return ret; 58843cb6954SKuninori Morimoto 589b65a7cccSKuninori Morimoto ret = rsnd_kctrl_new_s(mod, io, rtd, 59043cb6954SKuninori Morimoto rsnd_io_is_play(io) ? 59143cb6954SKuninori Morimoto "SRC Out Rate" : 59243cb6954SKuninori Morimoto "SRC In Rate", 593f0b04d8bSKuninori Morimoto rsnd_kctrl_accept_runtime, 59475916f65SKuninori Morimoto rsnd_src_set_convert_rate, 59543cb6954SKuninori Morimoto &src->sync, 192000); 59643cb6954SKuninori Morimoto 59743cb6954SKuninori Morimoto return ret; 59843cb6954SKuninori Morimoto } 59943cb6954SKuninori Morimoto 6001f9c82b5SKuninori Morimoto #ifdef CONFIG_DEBUG_FS 6011f9c82b5SKuninori Morimoto static void rsnd_src_debug_info(struct seq_file *m, 6021f9c82b5SKuninori Morimoto struct rsnd_dai_stream *io, 6031f9c82b5SKuninori Morimoto struct rsnd_mod *mod) 6041f9c82b5SKuninori Morimoto { 6051f9c82b5SKuninori Morimoto rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, 6061f9c82b5SKuninori Morimoto rsnd_mod_id(mod) * 0x20, 0x20); 6071f9c82b5SKuninori Morimoto seq_puts(m, "\n"); 6081f9c82b5SKuninori Morimoto rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, 6091f9c82b5SKuninori Morimoto 0x1c0, 0x20); 6101f9c82b5SKuninori Morimoto seq_puts(m, "\n"); 6111f9c82b5SKuninori Morimoto rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, 6121f9c82b5SKuninori Morimoto 0x200 + rsnd_mod_id(mod) * 0x40, 0x40); 6131f9c82b5SKuninori Morimoto } 6141f9c82b5SKuninori Morimoto #define DEBUG_INFO .debug_info = rsnd_src_debug_info 6151f9c82b5SKuninori Morimoto #else 6161f9c82b5SKuninori Morimoto #define DEBUG_INFO 6171f9c82b5SKuninori Morimoto #endif 6181f9c82b5SKuninori Morimoto 61975916f65SKuninori Morimoto static struct rsnd_mod_ops rsnd_src_ops = { 6208aefda50SKuninori Morimoto .name = SRC_NAME, 62172adc61fSKuninori Morimoto .dma_req = rsnd_src_dma_req, 62275916f65SKuninori Morimoto .probe = rsnd_src_probe_, 62375916f65SKuninori Morimoto .init = rsnd_src_init, 62475916f65SKuninori Morimoto .quit = rsnd_src_quit, 62575916f65SKuninori Morimoto .start = rsnd_src_start, 62675916f65SKuninori Morimoto .stop = rsnd_src_stop, 627b5b442abSKuninori Morimoto .irq = rsnd_src_irq, 62875916f65SKuninori Morimoto .pcm_new = rsnd_src_pcm_new, 6297e7fe06dSKuninori Morimoto .get_status = rsnd_mod_get_status, 6301f9c82b5SKuninori Morimoto DEBUG_INFO 631ba9c949fSKuninori Morimoto }; 632ba9c949fSKuninori Morimoto 633ba9c949fSKuninori Morimoto struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) 634ba9c949fSKuninori Morimoto { 635ba9c949fSKuninori Morimoto if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) 636ba9c949fSKuninori Morimoto id = 0; 637ba9c949fSKuninori Morimoto 638adf6a681SKuninori Morimoto return rsnd_mod_get(rsnd_src_get(priv, id)); 63990e8e50fSKuninori Morimoto } 64090e8e50fSKuninori Morimoto 6412ea6b074SKuninori Morimoto int rsnd_src_probe(struct rsnd_priv *priv) 642ba9c949fSKuninori Morimoto { 643adf6a681SKuninori Morimoto struct device_node *node; 644adf6a681SKuninori Morimoto struct device_node *np; 645ba9c949fSKuninori Morimoto struct device *dev = rsnd_priv_to_dev(priv); 646ba9c949fSKuninori Morimoto struct rsnd_src *src; 647ba9c949fSKuninori Morimoto struct clk *clk; 648ba9c949fSKuninori Morimoto char name[RSND_SRC_NAME_SIZE]; 6492f78dd7fSKuninori Morimoto int i, nr, ret; 650ba9c949fSKuninori Morimoto 651e8e7b7bdSKuninori Morimoto /* This driver doesn't support Gen1 at this point */ 652e8e7b7bdSKuninori Morimoto if (rsnd_is_gen1(priv)) 653e8e7b7bdSKuninori Morimoto return 0; 654033e7ed8SKuninori Morimoto 655adf6a681SKuninori Morimoto node = rsnd_src_of_node(priv); 656adf6a681SKuninori Morimoto if (!node) 657adf6a681SKuninori Morimoto return 0; /* not used is not error */ 65890e8e50fSKuninori Morimoto 659*c413983eSKuninori Morimoto nr = rsnd_node_count(priv, node, SRC_NAME); 660adf6a681SKuninori Morimoto if (!nr) { 661adf6a681SKuninori Morimoto ret = -EINVAL; 662adf6a681SKuninori Morimoto goto rsnd_src_probe_done; 663adf6a681SKuninori Morimoto } 664ba9c949fSKuninori Morimoto 665a86854d0SKees Cook src = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL); 666adf6a681SKuninori Morimoto if (!src) { 667adf6a681SKuninori Morimoto ret = -ENOMEM; 668adf6a681SKuninori Morimoto goto rsnd_src_probe_done; 669adf6a681SKuninori Morimoto } 670ba9c949fSKuninori Morimoto 671ba9c949fSKuninori Morimoto priv->src_nr = nr; 672ba9c949fSKuninori Morimoto priv->src = src; 673ba9c949fSKuninori Morimoto 674adf6a681SKuninori Morimoto i = 0; 675adf6a681SKuninori Morimoto for_each_child_of_node(node, np) { 676de196515SSergei Shtylyov if (!of_device_is_available(np)) 677de196515SSergei Shtylyov goto skip; 678de196515SSergei Shtylyov 679*c413983eSKuninori Morimoto i = rsnd_node_fixed_index(np, SRC_NAME, i); 680*c413983eSKuninori Morimoto 681adf6a681SKuninori Morimoto src = rsnd_src_get(priv, i); 682adf6a681SKuninori Morimoto 6838aefda50SKuninori Morimoto snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", 6848aefda50SKuninori Morimoto SRC_NAME, i); 685ba9c949fSKuninori Morimoto 686adf6a681SKuninori Morimoto src->irq = irq_of_parse_and_map(np, 0); 687adf6a681SKuninori Morimoto if (!src->irq) { 688adf6a681SKuninori Morimoto ret = -EINVAL; 68953ba2aa3SJulia Lawall of_node_put(np); 690adf6a681SKuninori Morimoto goto rsnd_src_probe_done; 691adf6a681SKuninori Morimoto } 692ba9c949fSKuninori Morimoto 693adf6a681SKuninori Morimoto clk = devm_clk_get(dev, name); 694adf6a681SKuninori Morimoto if (IS_ERR(clk)) { 695adf6a681SKuninori Morimoto ret = PTR_ERR(clk); 69653ba2aa3SJulia Lawall of_node_put(np); 697adf6a681SKuninori Morimoto goto rsnd_src_probe_done; 698adf6a681SKuninori Morimoto } 699ba9c949fSKuninori Morimoto 700e8e7b7bdSKuninori Morimoto ret = rsnd_mod_init(priv, rsnd_mod_get(src), 7017e7fe06dSKuninori Morimoto &rsnd_src_ops, clk, RSND_MOD_SRC, i); 70253ba2aa3SJulia Lawall if (ret) { 70353ba2aa3SJulia Lawall of_node_put(np); 704adf6a681SKuninori Morimoto goto rsnd_src_probe_done; 70553ba2aa3SJulia Lawall } 706adf6a681SKuninori Morimoto 707de196515SSergei Shtylyov skip: 708adf6a681SKuninori Morimoto i++; 709ba9c949fSKuninori Morimoto } 710ba9c949fSKuninori Morimoto 711adf6a681SKuninori Morimoto ret = 0; 712adf6a681SKuninori Morimoto 713adf6a681SKuninori Morimoto rsnd_src_probe_done: 714adf6a681SKuninori Morimoto of_node_put(node); 715adf6a681SKuninori Morimoto 716adf6a681SKuninori Morimoto return ret; 717ba9c949fSKuninori Morimoto } 7182f78dd7fSKuninori Morimoto 7192ea6b074SKuninori Morimoto void rsnd_src_remove(struct rsnd_priv *priv) 7202f78dd7fSKuninori Morimoto { 7212f78dd7fSKuninori Morimoto struct rsnd_src *src; 7222f78dd7fSKuninori Morimoto int i; 7232f78dd7fSKuninori Morimoto 7242f78dd7fSKuninori Morimoto for_each_rsnd_src(src, priv, i) { 725b76e218aSKuninori Morimoto rsnd_mod_quit(rsnd_mod_get(src)); 7262f78dd7fSKuninori Morimoto } 7272f78dd7fSKuninori Morimoto } 728