xref: /openbmc/linux/sound/soc/sh/rcar/src.c (revision 90431eb49bff6d79814cbf0c96e13597ad53095c)
1ba9c949fSKuninori Morimoto /*
2ba9c949fSKuninori Morimoto  * Renesas R-Car SRC support
3ba9c949fSKuninori Morimoto  *
4ba9c949fSKuninori Morimoto  * Copyright (C) 2013 Renesas Solutions Corp.
5ba9c949fSKuninori Morimoto  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6ba9c949fSKuninori Morimoto  *
7ba9c949fSKuninori Morimoto  * This program is free software; you can redistribute it and/or modify
8ba9c949fSKuninori Morimoto  * it under the terms of the GNU General Public License version 2 as
9ba9c949fSKuninori Morimoto  * published by the Free Software Foundation.
10ba9c949fSKuninori Morimoto  */
11ba9c949fSKuninori Morimoto #include "rsnd.h"
12ba9c949fSKuninori Morimoto 
138aefda50SKuninori Morimoto #define SRC_NAME "src"
148aefda50SKuninori Morimoto 
15cfcefe01SKuninori Morimoto /* SRCx_STATUS */
16cfcefe01SKuninori Morimoto #define OUF_SRCO	((1 << 12) | (1 << 13))
17cfcefe01SKuninori Morimoto #define OUF_SRCI	((1 <<  9) | (1 <<  8))
18cfcefe01SKuninori Morimoto 
19cfcefe01SKuninori Morimoto /* SCU_SYSTEM_STATUS0/1 */
20cfcefe01SKuninori Morimoto #define OUF_SRC(id)	((1 << (id + 16)) | (1 << id))
21cfcefe01SKuninori Morimoto 
22ba9c949fSKuninori Morimoto struct rsnd_src {
23ba9c949fSKuninori Morimoto 	struct rsnd_mod mod;
24940e9479SKuninori Morimoto 	struct rsnd_mod *dma;
2543cb6954SKuninori Morimoto 	struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
2643cb6954SKuninori Morimoto 	struct rsnd_kctrl_cfg_s sync; /* sync convert */
273b7843ffSKuninori Morimoto 	u32 convert_rate; /* sampling rate convert */
28adf6a681SKuninori Morimoto 	int irq;
29ba9c949fSKuninori Morimoto };
30ba9c949fSKuninori Morimoto 
31ba9c949fSKuninori Morimoto #define RSND_SRC_NAME_SIZE 16
32ba9c949fSKuninori Morimoto 
33adf6a681SKuninori Morimoto #define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
34232c00b6SKuninori Morimoto #define rsnd_src_to_dma(src) ((src)->dma)
35da599fd3SKuninori Morimoto #define rsnd_src_nr(priv) ((priv)->src_nr)
36ab2049f9SKuninori Morimoto #define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val)
3782e76ed3SKuninori Morimoto 
38ba9c949fSKuninori Morimoto #define rsnd_mod_to_src(_mod)				\
39ba9c949fSKuninori Morimoto 	container_of((_mod), struct rsnd_src, mod)
40ba9c949fSKuninori Morimoto 
41ba9c949fSKuninori Morimoto #define for_each_rsnd_src(pos, priv, i)				\
42ba9c949fSKuninori Morimoto 	for ((i) = 0;						\
43ba9c949fSKuninori Morimoto 	     ((i) < rsnd_src_nr(priv)) &&			\
44ba9c949fSKuninori Morimoto 	     ((pos) = (struct rsnd_src *)(priv)->src + i);	\
45ba9c949fSKuninori Morimoto 	     i++)
46ba9c949fSKuninori Morimoto 
47ba9c949fSKuninori Morimoto 
48ba9c949fSKuninori Morimoto /*
49ba9c949fSKuninori Morimoto  *		image of SRC (Sampling Rate Converter)
50ba9c949fSKuninori Morimoto  *
51ba9c949fSKuninori Morimoto  * 96kHz   <-> +-----+	48kHz	+-----+	 48kHz	+-------+
52ba9c949fSKuninori Morimoto  * 48kHz   <-> | SRC | <------>	| SSI |	<----->	| codec |
53ba9c949fSKuninori Morimoto  * 44.1kHz <-> +-----+		+-----+		+-------+
54ba9c949fSKuninori Morimoto  * ...
55ba9c949fSKuninori Morimoto  *
56ba9c949fSKuninori Morimoto  */
57ba9c949fSKuninori Morimoto 
58ba9c949fSKuninori Morimoto /*
59ba9c949fSKuninori Morimoto  * src.c is caring...
60ba9c949fSKuninori Morimoto  *
61ba9c949fSKuninori Morimoto  * Gen1
62ba9c949fSKuninori Morimoto  *
63ba9c949fSKuninori Morimoto  * [mem] -> [SRU] -> [SSI]
64ba9c949fSKuninori Morimoto  *        |--------|
65ba9c949fSKuninori Morimoto  *
66ba9c949fSKuninori Morimoto  * Gen2
67ba9c949fSKuninori Morimoto  *
68ba9c949fSKuninori Morimoto  * [mem] -> [SRC] -> [SSIU] -> [SSI]
69ba9c949fSKuninori Morimoto  *        |-----------------|
70ba9c949fSKuninori Morimoto  */
71ba9c949fSKuninori Morimoto 
7298efeeaeSKuninori Morimoto static void rsnd_src_activation(struct rsnd_mod *mod)
73379febfdSKuninori Morimoto {
74379febfdSKuninori Morimoto 	rsnd_mod_write(mod, SRC_SWRSR, 0);
75379febfdSKuninori Morimoto 	rsnd_mod_write(mod, SRC_SWRSR, 1);
76379febfdSKuninori Morimoto }
77379febfdSKuninori Morimoto 
78475a361aSKuninori Morimoto static void rsnd_src_halt(struct rsnd_mod *mod)
79475a361aSKuninori Morimoto {
80475a361aSKuninori Morimoto 	rsnd_mod_write(mod, SRC_SRCIR, 1);
81475a361aSKuninori Morimoto 	rsnd_mod_write(mod, SRC_SWRSR, 0);
82475a361aSKuninori Morimoto }
83475a361aSKuninori Morimoto 
849b99e9a7SKuninori Morimoto static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
859b99e9a7SKuninori Morimoto 					 struct rsnd_mod *mod)
8672adc61fSKuninori Morimoto {
8772adc61fSKuninori Morimoto 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
8872adc61fSKuninori Morimoto 	int is_play = rsnd_io_is_play(io);
8972adc61fSKuninori Morimoto 
9072adc61fSKuninori Morimoto 	return rsnd_dma_request_channel(rsnd_src_of_node(priv),
9172adc61fSKuninori Morimoto 					mod,
9272adc61fSKuninori Morimoto 					is_play ? "rx" : "tx");
9372adc61fSKuninori Morimoto }
9472adc61fSKuninori Morimoto 
9588c61cffSKuninori Morimoto static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
961a9be9eeSKuninori Morimoto 				 struct rsnd_mod *mod)
9743cb6954SKuninori Morimoto {
9843cb6954SKuninori Morimoto 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
991a9be9eeSKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
10043cb6954SKuninori Morimoto 	u32 convert_rate;
10143cb6954SKuninori Morimoto 
10243cb6954SKuninori Morimoto 	if (!runtime)
10343cb6954SKuninori Morimoto 		return 0;
10443cb6954SKuninori Morimoto 
105ab2049f9SKuninori Morimoto 	if (!rsnd_src_sync_is_enabled(mod))
10643cb6954SKuninori Morimoto 		return src->convert_rate;
10743cb6954SKuninori Morimoto 
10843cb6954SKuninori Morimoto 	convert_rate = src->sync.val;
10943cb6954SKuninori Morimoto 
11043cb6954SKuninori Morimoto 	if (!convert_rate)
11143cb6954SKuninori Morimoto 		convert_rate = src->convert_rate;
11243cb6954SKuninori Morimoto 
11343cb6954SKuninori Morimoto 	if (!convert_rate)
11443cb6954SKuninori Morimoto 		convert_rate = runtime->rate;
11543cb6954SKuninori Morimoto 
11643cb6954SKuninori Morimoto 	return convert_rate;
11743cb6954SKuninori Morimoto }
11843cb6954SKuninori Morimoto 
119cbf1494fSKuninori Morimoto unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
120ba9c949fSKuninori Morimoto 			       struct rsnd_dai_stream *io,
121cbf1494fSKuninori Morimoto 			       int is_in)
122ba9c949fSKuninori Morimoto {
123b1eac430SKuninori Morimoto 	struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
124cbf1494fSKuninori Morimoto 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
125b1eac430SKuninori Morimoto 	unsigned int rate = 0;
126cbf1494fSKuninori Morimoto 	int is_play = rsnd_io_is_play(io);
127cbf1494fSKuninori Morimoto 
128cbf1494fSKuninori Morimoto 	/*
129cbf1494fSKuninori Morimoto 	 *
130cbf1494fSKuninori Morimoto 	 * Playback
131cbf1494fSKuninori Morimoto 	 * runtime_rate -> [SRC] -> convert_rate
132cbf1494fSKuninori Morimoto 	 *
133cbf1494fSKuninori Morimoto 	 * Capture
134cbf1494fSKuninori Morimoto 	 * convert_rate -> [SRC] -> runtime_rate
135cbf1494fSKuninori Morimoto 	 */
136cbf1494fSKuninori Morimoto 
137cbf1494fSKuninori Morimoto 	if (is_play == is_in)
138cbf1494fSKuninori Morimoto 		return runtime->rate;
139ba9c949fSKuninori Morimoto 
140ba9c949fSKuninori Morimoto 	/*
141ba9c949fSKuninori Morimoto 	 * return convert rate if SRC is used,
142ba9c949fSKuninori Morimoto 	 * otherwise, return runtime->rate as usual
143ba9c949fSKuninori Morimoto 	 */
1441a9be9eeSKuninori Morimoto 	if (src_mod)
1451a9be9eeSKuninori Morimoto 		rate = rsnd_src_convert_rate(io, src_mod);
146b1eac430SKuninori Morimoto 
147ba9c949fSKuninori Morimoto 	if (!rate)
148ba9c949fSKuninori Morimoto 		rate = runtime->rate;
149ba9c949fSKuninori Morimoto 
150ba9c949fSKuninori Morimoto 	return rate;
151ba9c949fSKuninori Morimoto }
152ba9c949fSKuninori Morimoto 
1533b7843ffSKuninori Morimoto static int rsnd_src_hw_params(struct rsnd_mod *mod,
1542c0fac19SKuninori Morimoto 			      struct rsnd_dai_stream *io,
1553b7843ffSKuninori Morimoto 			      struct snd_pcm_substream *substream,
1563b7843ffSKuninori Morimoto 			      struct snd_pcm_hw_params *fe_params)
1573b7843ffSKuninori Morimoto {
1583b7843ffSKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
1593b7843ffSKuninori Morimoto 	struct snd_soc_pcm_runtime *fe = substream->private_data;
1603b7843ffSKuninori Morimoto 
1613b7843ffSKuninori Morimoto 	/*
1623b7843ffSKuninori Morimoto 	 * SRC assumes that it is used under DPCM if user want to use
1633b7843ffSKuninori Morimoto 	 * sampling rate convert. Then, SRC should be FE.
1643b7843ffSKuninori Morimoto 	 * And then, this function will be called *after* BE settings.
1653b7843ffSKuninori Morimoto 	 * this means, each BE already has fixuped hw_params.
1663b7843ffSKuninori Morimoto 	 * see
1673b7843ffSKuninori Morimoto 	 *	dpcm_fe_dai_hw_params()
1683b7843ffSKuninori Morimoto 	 *	dpcm_be_dai_hw_params()
1693b7843ffSKuninori Morimoto 	 */
170fc99d23fSKuninori Morimoto 	src->convert_rate = 0;
1713b7843ffSKuninori Morimoto 	if (fe->dai_link->dynamic) {
1723b7843ffSKuninori Morimoto 		int stream = substream->stream;
1733b7843ffSKuninori Morimoto 		struct snd_soc_dpcm *dpcm;
1743b7843ffSKuninori Morimoto 		struct snd_pcm_hw_params *be_params;
1753b7843ffSKuninori Morimoto 
1763b7843ffSKuninori Morimoto 		list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1773b7843ffSKuninori Morimoto 			be_params = &dpcm->hw_params;
1783b7843ffSKuninori Morimoto 
1793b7843ffSKuninori Morimoto 			if (params_rate(fe_params) != params_rate(be_params))
1803b7843ffSKuninori Morimoto 				src->convert_rate = params_rate(be_params);
1813b7843ffSKuninori Morimoto 		}
1823b7843ffSKuninori Morimoto 	}
1833b7843ffSKuninori Morimoto 
1843b7843ffSKuninori Morimoto 	return 0;
1853b7843ffSKuninori Morimoto }
1863b7843ffSKuninori Morimoto 
18775916f65SKuninori Morimoto static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
18875916f65SKuninori Morimoto 				      struct rsnd_mod *mod)
189ba9c949fSKuninori Morimoto {
19075916f65SKuninori Morimoto 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
191cfcefe01SKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
19275916f65SKuninori Morimoto 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
193*90431eb4SKuninori Morimoto 	int is_play = rsnd_io_is_play(io);
19467923f77SKuninori Morimoto 	int use_src = 0;
1950102eed5SKuninori Morimoto 	u32 fin, fout;
19675916f65SKuninori Morimoto 	u32 ifscr, fsrate, adinr;
19775916f65SKuninori Morimoto 	u32 cr, route;
19875916f65SKuninori Morimoto 	u32 bsdsr, bsisr;
199*90431eb4SKuninori Morimoto 	u32 i_busif, o_busif, tmp;
20075916f65SKuninori Morimoto 	uint ratio;
201ba9c949fSKuninori Morimoto 
20275916f65SKuninori Morimoto 	if (!runtime)
20375916f65SKuninori Morimoto 		return;
204ba9c949fSKuninori Morimoto 
2050102eed5SKuninori Morimoto 	fin  = rsnd_src_get_in_rate(priv, io);
2060102eed5SKuninori Morimoto 	fout = rsnd_src_get_out_rate(priv, io);
2070102eed5SKuninori Morimoto 
20875916f65SKuninori Morimoto 	/* 6 - 1/6 are very enough ratio for SRC_BSDSR */
2090102eed5SKuninori Morimoto 	if (fin == fout)
21075916f65SKuninori Morimoto 		ratio = 0;
2110102eed5SKuninori Morimoto 	else if (fin > fout)
2120102eed5SKuninori Morimoto 		ratio = 100 * fin / fout;
21375916f65SKuninori Morimoto 	else
2140102eed5SKuninori Morimoto 		ratio = 100 * fout / fin;
215cfcefe01SKuninori Morimoto 
21675916f65SKuninori Morimoto 	if (ratio > 600) {
21775916f65SKuninori Morimoto 		dev_err(dev, "FSO/FSI ratio error\n");
21875916f65SKuninori Morimoto 		return;
219ba9c949fSKuninori Morimoto 	}
220ba9c949fSKuninori Morimoto 
22167923f77SKuninori Morimoto 	use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
22267923f77SKuninori Morimoto 
223ba9c949fSKuninori Morimoto 	/*
22475916f65SKuninori Morimoto 	 *	SRC_ADINR
225ba9c949fSKuninori Morimoto 	 */
226c45f7263SKuninori Morimoto 	adinr = rsnd_get_adinr_bit(mod, io) |
227eed76bb8SKuninori Morimoto 		rsnd_runtime_channel_original(io);
22875916f65SKuninori Morimoto 
22975916f65SKuninori Morimoto 	/*
23075916f65SKuninori Morimoto 	 *	SRC_IFSCR / SRC_IFSVR
23175916f65SKuninori Morimoto 	 */
23275916f65SKuninori Morimoto 	ifscr = 0;
23375916f65SKuninori Morimoto 	fsrate = 0;
23467923f77SKuninori Morimoto 	if (use_src) {
23593ca33c9SHiroyuki Yokoyama 		u64 n;
23693ca33c9SHiroyuki Yokoyama 
23775916f65SKuninori Morimoto 		ifscr = 1;
23893ca33c9SHiroyuki Yokoyama 		n = (u64)0x0400000 * fin;
23993ca33c9SHiroyuki Yokoyama 		do_div(n, fout);
24093ca33c9SHiroyuki Yokoyama 		fsrate = n;
24175916f65SKuninori Morimoto 	}
24275916f65SKuninori Morimoto 
24375916f65SKuninori Morimoto 	/*
24475916f65SKuninori Morimoto 	 *	SRC_SRCCR / SRC_ROUTE_MODE0
24575916f65SKuninori Morimoto 	 */
24675916f65SKuninori Morimoto 	cr	= 0x00011110;
24775916f65SKuninori Morimoto 	route	= 0x0;
24867923f77SKuninori Morimoto 	if (use_src) {
24975916f65SKuninori Morimoto 		route	= 0x1;
25075916f65SKuninori Morimoto 
251ab2049f9SKuninori Morimoto 		if (rsnd_src_sync_is_enabled(mod)) {
25275916f65SKuninori Morimoto 			cr |= 0x1;
25375916f65SKuninori Morimoto 			route |= rsnd_io_is_play(io) ?
25475916f65SKuninori Morimoto 				(0x1 << 24) : (0x1 << 25);
25575916f65SKuninori Morimoto 		}
25675916f65SKuninori Morimoto 	}
25775916f65SKuninori Morimoto 
25875916f65SKuninori Morimoto 	/*
25975916f65SKuninori Morimoto 	 * SRC_BSDSR / SRC_BSISR
26075916f65SKuninori Morimoto 	 */
26175916f65SKuninori Morimoto 	switch (rsnd_mod_id(mod)) {
26275916f65SKuninori Morimoto 	case 5:
26375916f65SKuninori Morimoto 	case 6:
26475916f65SKuninori Morimoto 	case 7:
26575916f65SKuninori Morimoto 	case 8:
26675916f65SKuninori Morimoto 		bsdsr = 0x02400000; /* 6 - 1/6 */
26775916f65SKuninori Morimoto 		bsisr = 0x00100060; /* 6 - 1/6 */
26875916f65SKuninori Morimoto 		break;
26975916f65SKuninori Morimoto 	default:
27075916f65SKuninori Morimoto 		bsdsr = 0x01800000; /* 6 - 1/6 */
27175916f65SKuninori Morimoto 		bsisr = 0x00100060 ;/* 6 - 1/6 */
27275916f65SKuninori Morimoto 		break;
27375916f65SKuninori Morimoto 	}
27475916f65SKuninori Morimoto 
275*90431eb4SKuninori Morimoto 	/* BUSIF_MODE */
276*90431eb4SKuninori Morimoto 	tmp = rsnd_get_busif_shift(io, mod);
277*90431eb4SKuninori Morimoto 	i_busif = ( is_play ? tmp : 0) | 1;
278*90431eb4SKuninori Morimoto 	o_busif = (!is_play ? tmp : 0) | 1;
279*90431eb4SKuninori Morimoto 
2800fbab951SKuninori Morimoto 	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
2810fbab951SKuninori Morimoto 
28275916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_SRCIR, 1);	/* initialize */
28375916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_ADINR, adinr);
28475916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_IFSCR, ifscr);
28575916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_IFSVR, fsrate);
28675916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_SRCCR, cr);
28775916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_BSDSR, bsdsr);
28875916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_BSISR, bsisr);
28975916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_SRCIR, 0);	/* cancel initialize */
29075916f65SKuninori Morimoto 
291*90431eb4SKuninori Morimoto 	rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif);
292*90431eb4SKuninori Morimoto 	rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif);
293*90431eb4SKuninori Morimoto 
29475916f65SKuninori Morimoto 	rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
29575916f65SKuninori Morimoto 
2960102eed5SKuninori Morimoto 	rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
29775916f65SKuninori Morimoto }
29875916f65SKuninori Morimoto 
299b5b442abSKuninori Morimoto static int rsnd_src_irq(struct rsnd_mod *mod,
300b5b442abSKuninori Morimoto 			struct rsnd_dai_stream *io,
301b5b442abSKuninori Morimoto 			struct rsnd_priv *priv,
302b5b442abSKuninori Morimoto 			int enable)
303cfcefe01SKuninori Morimoto {
304cfcefe01SKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
305cfcefe01SKuninori Morimoto 	u32 sys_int_val, int_val, sys_int_mask;
306adf6a681SKuninori Morimoto 	int irq = src->irq;
307cfcefe01SKuninori Morimoto 	int id = rsnd_mod_id(mod);
308cfcefe01SKuninori Morimoto 
309cfcefe01SKuninori Morimoto 	sys_int_val =
310cfcefe01SKuninori Morimoto 	sys_int_mask = OUF_SRC(id);
311cfcefe01SKuninori Morimoto 	int_val = 0x3300;
312cfcefe01SKuninori Morimoto 
313cfcefe01SKuninori Morimoto 	/*
314cfcefe01SKuninori Morimoto 	 * IRQ is not supported on non-DT
315cfcefe01SKuninori Morimoto 	 * see
31675916f65SKuninori Morimoto 	 *	rsnd_src_probe_()
317cfcefe01SKuninori Morimoto 	 */
318cfcefe01SKuninori Morimoto 	if ((irq <= 0) || !enable) {
319cfcefe01SKuninori Morimoto 		sys_int_val = 0;
320cfcefe01SKuninori Morimoto 		int_val = 0;
321cfcefe01SKuninori Morimoto 	}
322cfcefe01SKuninori Morimoto 
3231a1bf58aSKuninori Morimoto 	/*
3241a1bf58aSKuninori Morimoto 	 * WORKAROUND
3251a1bf58aSKuninori Morimoto 	 *
326ab2049f9SKuninori Morimoto 	 * ignore over flow error when rsnd_src_sync_is_enabled()
3271a1bf58aSKuninori Morimoto 	 */
328ab2049f9SKuninori Morimoto 	if (rsnd_src_sync_is_enabled(mod))
3291a1bf58aSKuninori Morimoto 		sys_int_val = sys_int_val & 0xffff;
3301a1bf58aSKuninori Morimoto 
331cfcefe01SKuninori Morimoto 	rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
332cfcefe01SKuninori Morimoto 	rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
333cfcefe01SKuninori Morimoto 	rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
334b5b442abSKuninori Morimoto 
335b5b442abSKuninori Morimoto 	return 0;
336cfcefe01SKuninori Morimoto }
337cfcefe01SKuninori Morimoto 
3388cc225f7SKuninori Morimoto static void rsnd_src_status_clear(struct rsnd_mod *mod)
339cfcefe01SKuninori Morimoto {
340cfcefe01SKuninori Morimoto 	u32 val = OUF_SRC(rsnd_mod_id(mod));
341cfcefe01SKuninori Morimoto 
34242b197e7SKuninori Morimoto 	rsnd_mod_write(mod, SCU_SYS_STATUS0, val);
34342b197e7SKuninori Morimoto 	rsnd_mod_write(mod, SCU_SYS_STATUS1, val);
344cfcefe01SKuninori Morimoto }
345cfcefe01SKuninori Morimoto 
3466a25c8daSKuninori Morimoto static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
347cfcefe01SKuninori Morimoto {
3481a1bf58aSKuninori Morimoto 	u32 val0, val1;
349cfcefe01SKuninori Morimoto 	bool ret = false;
350cfcefe01SKuninori Morimoto 
3511a1bf58aSKuninori Morimoto 	val0 = val1 = OUF_SRC(rsnd_mod_id(mod));
3521a1bf58aSKuninori Morimoto 
3531a1bf58aSKuninori Morimoto 	/*
3541a1bf58aSKuninori Morimoto 	 * WORKAROUND
3551a1bf58aSKuninori Morimoto 	 *
356ab2049f9SKuninori Morimoto 	 * ignore over flow error when rsnd_src_sync_is_enabled()
3571a1bf58aSKuninori Morimoto 	 */
358ab2049f9SKuninori Morimoto 	if (rsnd_src_sync_is_enabled(mod))
3591a1bf58aSKuninori Morimoto 		val0 = val0 & 0xffff;
3601a1bf58aSKuninori Morimoto 
3611a1bf58aSKuninori Morimoto 	if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
3626a25c8daSKuninori Morimoto 	    (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1))
363cfcefe01SKuninori Morimoto 		ret = true;
364cfcefe01SKuninori Morimoto 
365cfcefe01SKuninori Morimoto 	return ret;
366cfcefe01SKuninori Morimoto }
367cfcefe01SKuninori Morimoto 
36875916f65SKuninori Morimoto static int rsnd_src_start(struct rsnd_mod *mod,
369497debaaSKuninori Morimoto 			  struct rsnd_dai_stream *io,
370497debaaSKuninori Morimoto 			  struct rsnd_priv *priv)
371cfcefe01SKuninori Morimoto {
3721a1bf58aSKuninori Morimoto 	u32 val;
3731a1bf58aSKuninori Morimoto 
3741a1bf58aSKuninori Morimoto 	/*
3751a1bf58aSKuninori Morimoto 	 * WORKAROUND
3761a1bf58aSKuninori Morimoto 	 *
3771a1bf58aSKuninori Morimoto 	 * Enable SRC output if you want to use sync convert together with DVC
3781a1bf58aSKuninori Morimoto 	 */
379ab2049f9SKuninori Morimoto 	val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ?
3801a1bf58aSKuninori Morimoto 		0x01 : 0x11;
381cfcefe01SKuninori Morimoto 
382cfcefe01SKuninori Morimoto 	rsnd_mod_write(mod, SRC_CTRL, val);
383cfcefe01SKuninori Morimoto 
38475916f65SKuninori Morimoto 	return 0;
38575916f65SKuninori Morimoto }
386cfcefe01SKuninori Morimoto 
38775916f65SKuninori Morimoto static int rsnd_src_stop(struct rsnd_mod *mod,
38875916f65SKuninori Morimoto 			 struct rsnd_dai_stream *io,
38975916f65SKuninori Morimoto 			 struct rsnd_priv *priv)
39075916f65SKuninori Morimoto {
39131739a68SKuninori Morimoto 	rsnd_mod_write(mod, SRC_CTRL, 0);
392cfcefe01SKuninori Morimoto 
393cfcefe01SKuninori Morimoto 	return 0;
394cfcefe01SKuninori Morimoto }
395cfcefe01SKuninori Morimoto 
39675916f65SKuninori Morimoto static int rsnd_src_init(struct rsnd_mod *mod,
397497debaaSKuninori Morimoto 			 struct rsnd_dai_stream *io,
398497debaaSKuninori Morimoto 			 struct rsnd_priv *priv)
399cfcefe01SKuninori Morimoto {
40075916f65SKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
401cfcefe01SKuninori Morimoto 
402ef30da1cSKuninori Morimoto 	/* reset sync convert_rate */
403ef30da1cSKuninori Morimoto 	src->sync.val = 0;
404ef30da1cSKuninori Morimoto 
40575916f65SKuninori Morimoto 	rsnd_mod_power_on(mod);
406cfcefe01SKuninori Morimoto 
40798efeeaeSKuninori Morimoto 	rsnd_src_activation(mod);
408cfcefe01SKuninori Morimoto 
40975916f65SKuninori Morimoto 	rsnd_src_set_convert_rate(io, mod);
41075916f65SKuninori Morimoto 
4118cc225f7SKuninori Morimoto 	rsnd_src_status_clear(mod);
41275916f65SKuninori Morimoto 
41375916f65SKuninori Morimoto 	return 0;
414cfcefe01SKuninori Morimoto }
415cfcefe01SKuninori Morimoto 
41675916f65SKuninori Morimoto static int rsnd_src_quit(struct rsnd_mod *mod,
417b761bf27SKuninori Morimoto 			 struct rsnd_dai_stream *io,
418b761bf27SKuninori Morimoto 			 struct rsnd_priv *priv)
419b761bf27SKuninori Morimoto {
42075916f65SKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
42175916f65SKuninori Morimoto 
422475a361aSKuninori Morimoto 	rsnd_src_halt(mod);
423475a361aSKuninori Morimoto 
42475916f65SKuninori Morimoto 	rsnd_mod_power_off(mod);
42575916f65SKuninori Morimoto 
42675916f65SKuninori Morimoto 	/* reset sync convert_rate */
42775916f65SKuninori Morimoto 	src->sync.val = 0;
42875916f65SKuninori Morimoto 
42975916f65SKuninori Morimoto 	return 0;
430b761bf27SKuninori Morimoto }
431b761bf27SKuninori Morimoto 
43275916f65SKuninori Morimoto static void __rsnd_src_interrupt(struct rsnd_mod *mod,
43388c61cffSKuninori Morimoto 				 struct rsnd_dai_stream *io)
434cfcefe01SKuninori Morimoto {
43502299d98SKuninori Morimoto 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
4366a25c8daSKuninori Morimoto 	bool stop = false;
437cfcefe01SKuninori Morimoto 
43802299d98SKuninori Morimoto 	spin_lock(&priv->lock);
43902299d98SKuninori Morimoto 
44002299d98SKuninori Morimoto 	/* ignore all cases if not working */
441d5bbe7deSKuninori Morimoto 	if (!rsnd_io_is_working(io))
44275916f65SKuninori Morimoto 		goto rsnd_src_interrupt_out;
443cfcefe01SKuninori Morimoto 
4446a25c8daSKuninori Morimoto 	if (rsnd_src_error_occurred(mod))
4456a25c8daSKuninori Morimoto 		stop = true;
44688c61cffSKuninori Morimoto 
4478cc225f7SKuninori Morimoto 	rsnd_src_status_clear(mod);
44875916f65SKuninori Morimoto rsnd_src_interrupt_out:
4498cc225f7SKuninori Morimoto 
45002299d98SKuninori Morimoto 	spin_unlock(&priv->lock);
4516a25c8daSKuninori Morimoto 
4526a25c8daSKuninori Morimoto 	if (stop)
4536a25c8daSKuninori Morimoto 		snd_pcm_stop_xrun(io->substream);
45488c61cffSKuninori Morimoto }
45588c61cffSKuninori Morimoto 
45675916f65SKuninori Morimoto static irqreturn_t rsnd_src_interrupt(int irq, void *data)
45788c61cffSKuninori Morimoto {
45888c61cffSKuninori Morimoto 	struct rsnd_mod *mod = data;
45988c61cffSKuninori Morimoto 
46075916f65SKuninori Morimoto 	rsnd_mod_interrupt(mod, __rsnd_src_interrupt);
461cfcefe01SKuninori Morimoto 
462cfcefe01SKuninori Morimoto 	return IRQ_HANDLED;
463cfcefe01SKuninori Morimoto }
464cfcefe01SKuninori Morimoto 
46575916f65SKuninori Morimoto static int rsnd_src_probe_(struct rsnd_mod *mod,
4662c0fac19SKuninori Morimoto 			   struct rsnd_dai_stream *io,
467690602fcSKuninori Morimoto 			   struct rsnd_priv *priv)
468ba9c949fSKuninori Morimoto {
469ba9c949fSKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
470ba9c949fSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
471adf6a681SKuninori Morimoto 	int irq = src->irq;
472ba9c949fSKuninori Morimoto 	int ret;
473ba9c949fSKuninori Morimoto 
474cfcefe01SKuninori Morimoto 	if (irq > 0) {
475cfcefe01SKuninori Morimoto 		/*
476cfcefe01SKuninori Morimoto 		 * IRQ is not supported on non-DT
477cfcefe01SKuninori Morimoto 		 * see
478b5b442abSKuninori Morimoto 		 *	rsnd_src_irq()
479cfcefe01SKuninori Morimoto 		 */
480cfcefe01SKuninori Morimoto 		ret = devm_request_irq(dev, irq,
48175916f65SKuninori Morimoto 				       rsnd_src_interrupt,
482cfcefe01SKuninori Morimoto 				       IRQF_SHARED,
483cfcefe01SKuninori Morimoto 				       dev_name(dev), mod);
484cfcefe01SKuninori Morimoto 		if (ret)
485b543b52aSKuninori Morimoto 			return ret;
486cfcefe01SKuninori Morimoto 	}
487cfcefe01SKuninori Morimoto 
488b99305d2SKuninori Morimoto 	ret = rsnd_dma_attach(io, mod, &src->dma);
489cfcefe01SKuninori Morimoto 
490cfcefe01SKuninori Morimoto 	return ret;
491ba9c949fSKuninori Morimoto }
492ba9c949fSKuninori Morimoto 
49375916f65SKuninori Morimoto static int rsnd_src_pcm_new(struct rsnd_mod *mod,
4942c0fac19SKuninori Morimoto 			    struct rsnd_dai_stream *io,
49543cb6954SKuninori Morimoto 			    struct snd_soc_pcm_runtime *rtd)
49643cb6954SKuninori Morimoto {
49743cb6954SKuninori Morimoto 	struct rsnd_src *src = rsnd_mod_to_src(mod);
49843cb6954SKuninori Morimoto 	int ret;
49943cb6954SKuninori Morimoto 
50043cb6954SKuninori Morimoto 	/*
50143cb6954SKuninori Morimoto 	 * enable SRC sync convert if possible
50243cb6954SKuninori Morimoto 	 */
50343cb6954SKuninori Morimoto 
50443cb6954SKuninori Morimoto 	/*
50561a219feSKuninori Morimoto 	 * It can't use SRC Synchronous convert
50661a219feSKuninori Morimoto 	 * when Capture if it uses CMD
5077115cb91SKuninori Morimoto 	 */
50861a219feSKuninori Morimoto 	if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io))
5097115cb91SKuninori Morimoto 		return 0;
5107115cb91SKuninori Morimoto 
5117115cb91SKuninori Morimoto 	/*
51243cb6954SKuninori Morimoto 	 * enable sync convert
51343cb6954SKuninori Morimoto 	 */
514b65a7cccSKuninori Morimoto 	ret = rsnd_kctrl_new_s(mod, io, rtd,
51543cb6954SKuninori Morimoto 			       rsnd_io_is_play(io) ?
51643cb6954SKuninori Morimoto 			       "SRC Out Rate Switch" :
51743cb6954SKuninori Morimoto 			       "SRC In Rate Switch",
51875916f65SKuninori Morimoto 			       rsnd_src_set_convert_rate,
51943cb6954SKuninori Morimoto 			       &src->sen, 1);
52043cb6954SKuninori Morimoto 	if (ret < 0)
52143cb6954SKuninori Morimoto 		return ret;
52243cb6954SKuninori Morimoto 
523b65a7cccSKuninori Morimoto 	ret = rsnd_kctrl_new_s(mod, io, rtd,
52443cb6954SKuninori Morimoto 			       rsnd_io_is_play(io) ?
52543cb6954SKuninori Morimoto 			       "SRC Out Rate" :
52643cb6954SKuninori Morimoto 			       "SRC In Rate",
52775916f65SKuninori Morimoto 			       rsnd_src_set_convert_rate,
52843cb6954SKuninori Morimoto 			       &src->sync, 192000);
52943cb6954SKuninori Morimoto 
53043cb6954SKuninori Morimoto 	return ret;
53143cb6954SKuninori Morimoto }
53243cb6954SKuninori Morimoto 
53375916f65SKuninori Morimoto static struct rsnd_mod_ops rsnd_src_ops = {
5348aefda50SKuninori Morimoto 	.name	= SRC_NAME,
53572adc61fSKuninori Morimoto 	.dma_req = rsnd_src_dma_req,
53675916f65SKuninori Morimoto 	.probe	= rsnd_src_probe_,
53775916f65SKuninori Morimoto 	.init	= rsnd_src_init,
53875916f65SKuninori Morimoto 	.quit	= rsnd_src_quit,
53975916f65SKuninori Morimoto 	.start	= rsnd_src_start,
54075916f65SKuninori Morimoto 	.stop	= rsnd_src_stop,
541b5b442abSKuninori Morimoto 	.irq	= rsnd_src_irq,
5423b7843ffSKuninori Morimoto 	.hw_params = rsnd_src_hw_params,
54375916f65SKuninori Morimoto 	.pcm_new = rsnd_src_pcm_new,
544ba9c949fSKuninori Morimoto };
545ba9c949fSKuninori Morimoto 
546ba9c949fSKuninori Morimoto struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
547ba9c949fSKuninori Morimoto {
548ba9c949fSKuninori Morimoto 	if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
549ba9c949fSKuninori Morimoto 		id = 0;
550ba9c949fSKuninori Morimoto 
551adf6a681SKuninori Morimoto 	return rsnd_mod_get(rsnd_src_get(priv, id));
55290e8e50fSKuninori Morimoto }
55390e8e50fSKuninori Morimoto 
5542ea6b074SKuninori Morimoto int rsnd_src_probe(struct rsnd_priv *priv)
555ba9c949fSKuninori Morimoto {
556adf6a681SKuninori Morimoto 	struct device_node *node;
557adf6a681SKuninori Morimoto 	struct device_node *np;
558ba9c949fSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
559ba9c949fSKuninori Morimoto 	struct rsnd_src *src;
560ba9c949fSKuninori Morimoto 	struct clk *clk;
561ba9c949fSKuninori Morimoto 	char name[RSND_SRC_NAME_SIZE];
5622f78dd7fSKuninori Morimoto 	int i, nr, ret;
563ba9c949fSKuninori Morimoto 
564e8e7b7bdSKuninori Morimoto 	/* This driver doesn't support Gen1 at this point */
565e8e7b7bdSKuninori Morimoto 	if (rsnd_is_gen1(priv))
566e8e7b7bdSKuninori Morimoto 		return 0;
567033e7ed8SKuninori Morimoto 
568adf6a681SKuninori Morimoto 	node = rsnd_src_of_node(priv);
569adf6a681SKuninori Morimoto 	if (!node)
570adf6a681SKuninori Morimoto 		return 0; /* not used is not error */
57190e8e50fSKuninori Morimoto 
572adf6a681SKuninori Morimoto 	nr = of_get_child_count(node);
573adf6a681SKuninori Morimoto 	if (!nr) {
574adf6a681SKuninori Morimoto 		ret = -EINVAL;
575adf6a681SKuninori Morimoto 		goto rsnd_src_probe_done;
576adf6a681SKuninori Morimoto 	}
577ba9c949fSKuninori Morimoto 
578ba9c949fSKuninori Morimoto 	src	= devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
579adf6a681SKuninori Morimoto 	if (!src) {
580adf6a681SKuninori Morimoto 		ret = -ENOMEM;
581adf6a681SKuninori Morimoto 		goto rsnd_src_probe_done;
582adf6a681SKuninori Morimoto 	}
583ba9c949fSKuninori Morimoto 
584ba9c949fSKuninori Morimoto 	priv->src_nr	= nr;
585ba9c949fSKuninori Morimoto 	priv->src	= src;
586ba9c949fSKuninori Morimoto 
587adf6a681SKuninori Morimoto 	i = 0;
588adf6a681SKuninori Morimoto 	for_each_child_of_node(node, np) {
589de196515SSergei Shtylyov 		if (!of_device_is_available(np))
590de196515SSergei Shtylyov 			goto skip;
591de196515SSergei Shtylyov 
592adf6a681SKuninori Morimoto 		src = rsnd_src_get(priv, i);
593adf6a681SKuninori Morimoto 
5948aefda50SKuninori Morimoto 		snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
5958aefda50SKuninori Morimoto 			 SRC_NAME, i);
596ba9c949fSKuninori Morimoto 
597adf6a681SKuninori Morimoto 		src->irq = irq_of_parse_and_map(np, 0);
598adf6a681SKuninori Morimoto 		if (!src->irq) {
599adf6a681SKuninori Morimoto 			ret = -EINVAL;
600adf6a681SKuninori Morimoto 			goto rsnd_src_probe_done;
601adf6a681SKuninori Morimoto 		}
602ba9c949fSKuninori Morimoto 
603adf6a681SKuninori Morimoto 		clk = devm_clk_get(dev, name);
604adf6a681SKuninori Morimoto 		if (IS_ERR(clk)) {
605adf6a681SKuninori Morimoto 			ret = PTR_ERR(clk);
606adf6a681SKuninori Morimoto 			goto rsnd_src_probe_done;
607adf6a681SKuninori Morimoto 		}
608ba9c949fSKuninori Morimoto 
609e8e7b7bdSKuninori Morimoto 		ret = rsnd_mod_init(priv, rsnd_mod_get(src),
6105ba17b42SKuninori Morimoto 				    &rsnd_src_ops, clk, rsnd_mod_get_status,
6115ba17b42SKuninori Morimoto 				    RSND_MOD_SRC, i);
6122f78dd7fSKuninori Morimoto 		if (ret)
613adf6a681SKuninori Morimoto 			goto rsnd_src_probe_done;
614adf6a681SKuninori Morimoto 
615de196515SSergei Shtylyov skip:
616adf6a681SKuninori Morimoto 		i++;
617ba9c949fSKuninori Morimoto 	}
618ba9c949fSKuninori Morimoto 
619adf6a681SKuninori Morimoto 	ret = 0;
620adf6a681SKuninori Morimoto 
621adf6a681SKuninori Morimoto rsnd_src_probe_done:
622adf6a681SKuninori Morimoto 	of_node_put(node);
623adf6a681SKuninori Morimoto 
624adf6a681SKuninori Morimoto 	return ret;
625ba9c949fSKuninori Morimoto }
6262f78dd7fSKuninori Morimoto 
6272ea6b074SKuninori Morimoto void rsnd_src_remove(struct rsnd_priv *priv)
6282f78dd7fSKuninori Morimoto {
6292f78dd7fSKuninori Morimoto 	struct rsnd_src *src;
6302f78dd7fSKuninori Morimoto 	int i;
6312f78dd7fSKuninori Morimoto 
6322f78dd7fSKuninori Morimoto 	for_each_rsnd_src(src, priv, i) {
633b76e218aSKuninori Morimoto 		rsnd_mod_quit(rsnd_mod_get(src));
6342f78dd7fSKuninori Morimoto 	}
6352f78dd7fSKuninori Morimoto }
636