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