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