xref: /OK3568_Linux_fs/kernel/sound/soc/sh/rcar/cmd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Renesas R-Car CMD support
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (C) 2015 Renesas Solutions Corp.
6*4882a593Smuzhiyun // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "rsnd.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun struct rsnd_cmd {
11*4882a593Smuzhiyun 	struct rsnd_mod mod;
12*4882a593Smuzhiyun };
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define CMD_NAME "cmd"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
17*4882a593Smuzhiyun #define for_each_rsnd_cmd(pos, priv, i)					\
18*4882a593Smuzhiyun 	for ((i) = 0;							\
19*4882a593Smuzhiyun 	     ((i) < rsnd_cmd_nr(priv)) &&				\
20*4882a593Smuzhiyun 		     ((pos) = (struct rsnd_cmd *)(priv)->cmd + i);	\
21*4882a593Smuzhiyun 	     i++)
22*4882a593Smuzhiyun 
rsnd_cmd_init(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)23*4882a593Smuzhiyun static int rsnd_cmd_init(struct rsnd_mod *mod,
24*4882a593Smuzhiyun 			 struct rsnd_dai_stream *io,
25*4882a593Smuzhiyun 			 struct rsnd_priv *priv)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
28*4882a593Smuzhiyun 	struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
29*4882a593Smuzhiyun 	struct device *dev = rsnd_priv_to_dev(priv);
30*4882a593Smuzhiyun 	u32 data;
31*4882a593Smuzhiyun 	static const u32 path[] = {
32*4882a593Smuzhiyun 		[1] = 1 << 0,
33*4882a593Smuzhiyun 		[5] = 1 << 8,
34*4882a593Smuzhiyun 		[6] = 1 << 12,
35*4882a593Smuzhiyun 		[9] = 1 << 15,
36*4882a593Smuzhiyun 	};
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	if (!mix && !dvc)
39*4882a593Smuzhiyun 		return 0;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
42*4882a593Smuzhiyun 		return -ENXIO;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	if (mix) {
45*4882a593Smuzhiyun 		struct rsnd_dai *rdai;
46*4882a593Smuzhiyun 		struct rsnd_mod *src;
47*4882a593Smuzhiyun 		struct rsnd_dai_stream *tio;
48*4882a593Smuzhiyun 		int i;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 		/*
51*4882a593Smuzhiyun 		 * it is assuming that integrater is well understanding about
52*4882a593Smuzhiyun 		 * data path. Here doesn't check impossible connection,
53*4882a593Smuzhiyun 		 * like src2 + src5
54*4882a593Smuzhiyun 		 */
55*4882a593Smuzhiyun 		data = 0;
56*4882a593Smuzhiyun 		for_each_rsnd_dai(rdai, priv, i) {
57*4882a593Smuzhiyun 			tio = &rdai->playback;
58*4882a593Smuzhiyun 			src = rsnd_io_to_mod_src(tio);
59*4882a593Smuzhiyun 			if (mix == rsnd_io_to_mod_mix(tio))
60*4882a593Smuzhiyun 				data |= path[rsnd_mod_id(src)];
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 			tio = &rdai->capture;
63*4882a593Smuzhiyun 			src = rsnd_io_to_mod_src(tio);
64*4882a593Smuzhiyun 			if (mix == rsnd_io_to_mod_mix(tio))
65*4882a593Smuzhiyun 				data |= path[rsnd_mod_id(src)];
66*4882a593Smuzhiyun 		}
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	} else {
69*4882a593Smuzhiyun 		struct rsnd_mod *src = rsnd_io_to_mod_src(io);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		static const u8 cmd_case[] = {
72*4882a593Smuzhiyun 			[0] = 0x3,
73*4882a593Smuzhiyun 			[1] = 0x3,
74*4882a593Smuzhiyun 			[2] = 0x4,
75*4882a593Smuzhiyun 			[3] = 0x1,
76*4882a593Smuzhiyun 			[4] = 0x2,
77*4882a593Smuzhiyun 			[5] = 0x4,
78*4882a593Smuzhiyun 			[6] = 0x1,
79*4882a593Smuzhiyun 			[9] = 0x2,
80*4882a593Smuzhiyun 		};
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 		if (unlikely(!src))
83*4882a593Smuzhiyun 			return -EIO;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 		data = path[rsnd_mod_id(src)] |
86*4882a593Smuzhiyun 			cmd_case[rsnd_mod_id(src)] << 16;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
92*4882a593Smuzhiyun 	rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
93*4882a593Smuzhiyun 	rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	rsnd_adg_set_cmd_timsel_gen2(mod, io);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return 0;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
rsnd_cmd_start(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)100*4882a593Smuzhiyun static int rsnd_cmd_start(struct rsnd_mod *mod,
101*4882a593Smuzhiyun 			  struct rsnd_dai_stream *io,
102*4882a593Smuzhiyun 			  struct rsnd_priv *priv)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	rsnd_mod_write(mod, CMD_CTRL, 0x10);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	return 0;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
rsnd_cmd_stop(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)109*4882a593Smuzhiyun static int rsnd_cmd_stop(struct rsnd_mod *mod,
110*4882a593Smuzhiyun 			 struct rsnd_dai_stream *io,
111*4882a593Smuzhiyun 			 struct rsnd_priv *priv)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	rsnd_mod_write(mod, CMD_CTRL, 0);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun static struct rsnd_mod_ops rsnd_cmd_ops = {
119*4882a593Smuzhiyun 	.name		= CMD_NAME,
120*4882a593Smuzhiyun 	.init		= rsnd_cmd_init,
121*4882a593Smuzhiyun 	.start		= rsnd_cmd_start,
122*4882a593Smuzhiyun 	.stop		= rsnd_cmd_stop,
123*4882a593Smuzhiyun 	.get_status	= rsnd_mod_get_status,
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun 
rsnd_cmd_mod_get(struct rsnd_priv * priv,int id)126*4882a593Smuzhiyun static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
129*4882a593Smuzhiyun 		id = 0;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
132*4882a593Smuzhiyun }
rsnd_cmd_attach(struct rsnd_dai_stream * io,int id)133*4882a593Smuzhiyun int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
136*4882a593Smuzhiyun 	struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	return rsnd_dai_connect(mod, io, mod->type);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
rsnd_cmd_probe(struct rsnd_priv * priv)141*4882a593Smuzhiyun int rsnd_cmd_probe(struct rsnd_priv *priv)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	struct device *dev = rsnd_priv_to_dev(priv);
144*4882a593Smuzhiyun 	struct rsnd_cmd *cmd;
145*4882a593Smuzhiyun 	int i, nr, ret;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* This driver doesn't support Gen1 at this point */
148*4882a593Smuzhiyun 	if (rsnd_is_gen1(priv))
149*4882a593Smuzhiyun 		return 0;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* same number as DVC */
152*4882a593Smuzhiyun 	nr = priv->dvc_nr;
153*4882a593Smuzhiyun 	if (!nr)
154*4882a593Smuzhiyun 		return 0;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL);
157*4882a593Smuzhiyun 	if (!cmd)
158*4882a593Smuzhiyun 		return -ENOMEM;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	priv->cmd_nr	= nr;
161*4882a593Smuzhiyun 	priv->cmd	= cmd;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	for_each_rsnd_cmd(cmd, priv, i) {
164*4882a593Smuzhiyun 		ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
165*4882a593Smuzhiyun 				    &rsnd_cmd_ops, NULL,
166*4882a593Smuzhiyun 				    RSND_MOD_CMD, i);
167*4882a593Smuzhiyun 		if (ret)
168*4882a593Smuzhiyun 			return ret;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
rsnd_cmd_remove(struct rsnd_priv * priv)174*4882a593Smuzhiyun void rsnd_cmd_remove(struct rsnd_priv *priv)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	struct rsnd_cmd *cmd;
177*4882a593Smuzhiyun 	int i;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	for_each_rsnd_cmd(cmd, priv, i) {
180*4882a593Smuzhiyun 		rsnd_mod_quit(rsnd_mod_get(cmd));
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun }
183