Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/renesas/rcar/ctu.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// ctu.c
4
//
5
// Copyright (c) 2015 Kuninori Morimoto <[email protected]>
6
7
#include "rsnd.h"
8
9
#define CTU_NAME_SIZE 16
10
#define CTU_NAME "ctu"
11
12
/*
13
* User needs to setup CTU by amixer, and its settings are
14
* based on below registers
15
*
16
* CTUn_CPMDR : amixser set "CTU Pass"
17
* CTUn_SV0xR : amixser set "CTU SV0"
18
* CTUn_SV1xR : amixser set "CTU SV1"
19
* CTUn_SV2xR : amixser set "CTU SV2"
20
* CTUn_SV3xR : amixser set "CTU SV3"
21
*
22
* [CTU Pass]
23
* 0000: default
24
* 0001: Connect input data of channel 0
25
* 0010: Connect input data of channel 1
26
* 0011: Connect input data of channel 2
27
* 0100: Connect input data of channel 3
28
* 0101: Connect input data of channel 4
29
* 0110: Connect input data of channel 5
30
* 0111: Connect input data of channel 6
31
* 1000: Connect input data of channel 7
32
* 1001: Connect calculated data by scale values of matrix row 0
33
* 1010: Connect calculated data by scale values of matrix row 1
34
* 1011: Connect calculated data by scale values of matrix row 2
35
* 1100: Connect calculated data by scale values of matrix row 3
36
*
37
* [CTU SVx]
38
* [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07]
39
* [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17]
40
* [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27]
41
* [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37]
42
* [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
43
* [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
44
* [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
45
* [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
46
*
47
* [SVxx]
48
* Plus Minus
49
* value time dB value time dB
50
* -----------------------------------------------------------------------
51
* H'7F_FFFF 2 6 H'80_0000 2 6
52
* ...
53
* H'40_0000 1 0 H'C0_0000 1 0
54
* ...
55
* H'00_0001 2.38 x 10^-7 -132
56
* H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132
57
*
58
*
59
* Ex) Input ch -> Output ch
60
* 1ch -> 0ch
61
* 0ch -> 1ch
62
*
63
* amixer set "CTU Reset" on
64
* amixer set "CTU Pass" 9,10
65
* amixer set "CTU SV0" 0,4194304
66
* amixer set "CTU SV1" 4194304,0
67
* or
68
* amixer set "CTU Reset" on
69
* amixer set "CTU Pass" 2,1
70
*/
71
72
struct rsnd_ctu {
73
struct rsnd_mod mod;
74
struct rsnd_kctrl_cfg_m pass;
75
struct rsnd_kctrl_cfg_m sv[4];
76
struct rsnd_kctrl_cfg_s reset;
77
int channels;
78
u32 flags;
79
};
80
81
#define KCTRL_INITIALIZED (1 << 0)
82
83
#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
84
#define for_each_rsnd_ctu(pos, priv, i) \
85
for ((i) = 0; \
86
((i) < rsnd_ctu_nr(priv)) && \
87
((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \
88
i++)
89
90
#define rsnd_mod_to_ctu(_mod) \
91
container_of((_mod), struct rsnd_ctu, mod)
92
93
#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
94
95
static void rsnd_ctu_activation(struct rsnd_mod *mod)
96
{
97
rsnd_mod_write(mod, CTU_SWRSR, 0);
98
rsnd_mod_write(mod, CTU_SWRSR, 1);
99
}
100
101
static void rsnd_ctu_halt(struct rsnd_mod *mod)
102
{
103
rsnd_mod_write(mod, CTU_CTUIR, 1);
104
rsnd_mod_write(mod, CTU_SWRSR, 0);
105
}
106
107
static int rsnd_ctu_probe_(struct rsnd_mod *mod,
108
struct rsnd_dai_stream *io,
109
struct rsnd_priv *priv)
110
{
111
return rsnd_cmd_attach(io, rsnd_mod_id(mod));
112
}
113
114
static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
115
struct rsnd_mod *mod)
116
{
117
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
118
u32 cpmdr = 0;
119
u32 scmdr = 0;
120
int i, j;
121
122
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
123
u32 val = rsnd_kctrl_valm(ctu->pass, i);
124
125
cpmdr |= val << (28 - (i * 4));
126
127
if ((val > 0x8) && (scmdr < (val - 0x8)))
128
scmdr = val - 0x8;
129
}
130
131
rsnd_mod_write(mod, CTU_CTUIR, 1);
132
133
rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
134
135
rsnd_mod_write(mod, CTU_CPMDR, cpmdr);
136
137
rsnd_mod_write(mod, CTU_SCMDR, scmdr);
138
139
for (i = 0; i < 4; i++) {
140
141
if (i >= scmdr)
142
break;
143
144
for (j = 0; j < RSND_MAX_CHANNELS; j++)
145
rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
146
}
147
148
rsnd_mod_write(mod, CTU_CTUIR, 0);
149
}
150
151
static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
152
struct rsnd_mod *mod)
153
{
154
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
155
int i;
156
157
if (!rsnd_kctrl_vals(ctu->reset))
158
return;
159
160
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
161
rsnd_kctrl_valm(ctu->pass, i) = 0;
162
rsnd_kctrl_valm(ctu->sv[0], i) = 0;
163
rsnd_kctrl_valm(ctu->sv[1], i) = 0;
164
rsnd_kctrl_valm(ctu->sv[2], i) = 0;
165
rsnd_kctrl_valm(ctu->sv[3], i) = 0;
166
}
167
rsnd_kctrl_vals(ctu->reset) = 0;
168
}
169
170
static int rsnd_ctu_init(struct rsnd_mod *mod,
171
struct rsnd_dai_stream *io,
172
struct rsnd_priv *priv)
173
{
174
int ret;
175
176
ret = rsnd_mod_power_on(mod);
177
if (ret < 0)
178
return ret;
179
180
rsnd_ctu_activation(mod);
181
182
rsnd_ctu_value_init(io, mod);
183
184
return 0;
185
}
186
187
static int rsnd_ctu_quit(struct rsnd_mod *mod,
188
struct rsnd_dai_stream *io,
189
struct rsnd_priv *priv)
190
{
191
rsnd_ctu_halt(mod);
192
193
rsnd_mod_power_off(mod);
194
195
return 0;
196
}
197
198
static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
199
struct rsnd_dai_stream *io,
200
struct snd_soc_pcm_runtime *rtd)
201
{
202
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
203
int ret;
204
205
if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
206
return 0;
207
208
/* CTU Pass */
209
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
210
rsnd_kctrl_accept_anytime,
211
NULL,
212
&ctu->pass, RSND_MAX_CHANNELS,
213
0xC);
214
if (ret < 0)
215
return ret;
216
217
/* ROW0 */
218
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
219
rsnd_kctrl_accept_anytime,
220
NULL,
221
&ctu->sv[0], RSND_MAX_CHANNELS,
222
0x00FFFFFF);
223
if (ret < 0)
224
return ret;
225
226
/* ROW1 */
227
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
228
rsnd_kctrl_accept_anytime,
229
NULL,
230
&ctu->sv[1], RSND_MAX_CHANNELS,
231
0x00FFFFFF);
232
if (ret < 0)
233
return ret;
234
235
/* ROW2 */
236
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
237
rsnd_kctrl_accept_anytime,
238
NULL,
239
&ctu->sv[2], RSND_MAX_CHANNELS,
240
0x00FFFFFF);
241
if (ret < 0)
242
return ret;
243
244
/* ROW3 */
245
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
246
rsnd_kctrl_accept_anytime,
247
NULL,
248
&ctu->sv[3], RSND_MAX_CHANNELS,
249
0x00FFFFFF);
250
if (ret < 0)
251
return ret;
252
253
/* Reset */
254
ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset",
255
rsnd_kctrl_accept_anytime,
256
rsnd_ctu_value_reset,
257
&ctu->reset, 1);
258
259
rsnd_flags_set(ctu, KCTRL_INITIALIZED);
260
261
return ret;
262
}
263
264
static int rsnd_ctu_id(struct rsnd_mod *mod)
265
{
266
/*
267
* ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
268
* ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
269
*/
270
return mod->id / 4;
271
}
272
273
static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
274
{
275
/*
276
* ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
277
* ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
278
*/
279
return mod->id % 4;
280
}
281
282
#ifdef CONFIG_DEBUG_FS
283
static void rsnd_ctu_debug_info(struct seq_file *m,
284
struct rsnd_dai_stream *io,
285
struct rsnd_mod *mod)
286
{
287
rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
288
0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100);
289
}
290
#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info
291
#else
292
#define DEBUG_INFO
293
#endif
294
295
static struct rsnd_mod_ops rsnd_ctu_ops = {
296
.name = CTU_NAME,
297
.probe = rsnd_ctu_probe_,
298
.init = rsnd_ctu_init,
299
.quit = rsnd_ctu_quit,
300
.pcm_new = rsnd_ctu_pcm_new,
301
.get_status = rsnd_mod_get_status,
302
.id = rsnd_ctu_id,
303
.id_sub = rsnd_ctu_id_sub,
304
.id_cmd = rsnd_mod_id_raw,
305
DEBUG_INFO
306
};
307
308
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
309
{
310
if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
311
id = 0;
312
313
return rsnd_mod_get(rsnd_ctu_get(priv, id));
314
}
315
316
int rsnd_ctu_probe(struct rsnd_priv *priv)
317
{
318
struct device_node *node;
319
struct device *dev = rsnd_priv_to_dev(priv);
320
struct rsnd_ctu *ctu;
321
struct clk *clk;
322
char name[CTU_NAME_SIZE];
323
int i, nr, ret;
324
325
node = rsnd_ctu_of_node(priv);
326
if (!node)
327
return 0; /* not used is not error */
328
329
nr = of_get_child_count(node);
330
if (!nr) {
331
ret = -EINVAL;
332
goto rsnd_ctu_probe_done;
333
}
334
335
ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL);
336
if (!ctu) {
337
ret = -ENOMEM;
338
goto rsnd_ctu_probe_done;
339
}
340
341
priv->ctu_nr = nr;
342
priv->ctu = ctu;
343
344
i = 0;
345
ret = 0;
346
for_each_child_of_node_scoped(node, np) {
347
ctu = rsnd_ctu_get(priv, i);
348
349
/*
350
* CTU00, CTU01, CTU02, CTU03 => CTU0
351
* CTU10, CTU11, CTU12, CTU13 => CTU1
352
*/
353
snprintf(name, CTU_NAME_SIZE, "%s.%d",
354
CTU_NAME, i / 4);
355
356
clk = devm_clk_get(dev, name);
357
if (IS_ERR(clk)) {
358
ret = PTR_ERR(clk);
359
goto rsnd_ctu_probe_done;
360
}
361
362
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
363
clk, RSND_MOD_CTU, i);
364
if (ret)
365
goto rsnd_ctu_probe_done;
366
367
i++;
368
}
369
370
371
rsnd_ctu_probe_done:
372
of_node_put(node);
373
374
return ret;
375
}
376
377
void rsnd_ctu_remove(struct rsnd_priv *priv)
378
{
379
struct rsnd_ctu *ctu;
380
int i;
381
382
for_each_rsnd_ctu(ctu, priv, i) {
383
rsnd_mod_quit(rsnd_mod_get(ctu));
384
}
385
}
386
387