Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/renesas/rcar/ssiu.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Renesas R-Car SSIU support
4
//
5
// Copyright (c) 2015 Kuninori Morimoto <[email protected]>
6
7
#include "rsnd.h"
8
9
#define SSIU_NAME "ssiu"
10
11
struct rsnd_ssiu {
12
struct rsnd_mod mod;
13
u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
14
unsigned int usrcnt;
15
int id;
16
int id_sub;
17
};
18
19
/* SSI_MODE */
20
#define TDM_EXT (1 << 0)
21
#define TDM_SPLIT (1 << 8)
22
23
#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
24
#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
25
#define for_each_rsnd_ssiu(pos, priv, i) \
26
for (i = 0; \
27
(i < rsnd_ssiu_nr(priv)) && \
28
((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
29
i++)
30
31
/*
32
* SSI Gen2 Gen3 Gen4
33
* 0 BUSIF0-3 BUSIF0-7 BUSIF0-7
34
* 1 BUSIF0-3 BUSIF0-7
35
* 2 BUSIF0-3 BUSIF0-7
36
* 3 BUSIF0 BUSIF0-7
37
* 4 BUSIF0 BUSIF0-7
38
* 5 BUSIF0 BUSIF0
39
* 6 BUSIF0 BUSIF0
40
* 7 BUSIF0 BUSIF0
41
* 8 BUSIF0 BUSIF0
42
* 9 BUSIF0-3 BUSIF0-7
43
* total 22 52 8
44
*/
45
static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
46
static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
47
static const int gen4_id[] = { 0 };
48
49
/* enable busif buffer over/under run interrupt. */
50
#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
51
#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
52
static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
53
{
54
int id = rsnd_mod_id(mod);
55
int shift, offset;
56
int i;
57
58
switch (id) {
59
case 0:
60
case 1:
61
case 2:
62
case 3:
63
case 4:
64
shift = id;
65
offset = 0;
66
break;
67
case 9:
68
shift = 1;
69
offset = 1;
70
break;
71
default:
72
return;
73
}
74
75
for (i = 0; i < 4; i++) {
76
enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
77
u32 val = 0xf << (shift * 4);
78
u32 sys_int_enable = rsnd_mod_read(mod, reg);
79
80
if (enable)
81
sys_int_enable |= val;
82
else
83
sys_int_enable &= ~val;
84
rsnd_mod_write(mod, reg, sys_int_enable);
85
}
86
}
87
88
bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
89
{
90
bool error = false;
91
int id = rsnd_mod_id(mod);
92
int shift, offset;
93
int i;
94
95
switch (id) {
96
case 0:
97
case 1:
98
case 2:
99
case 3:
100
case 4:
101
shift = id;
102
offset = 0;
103
break;
104
case 9:
105
shift = 1;
106
offset = 1;
107
break;
108
default:
109
goto out;
110
}
111
112
for (i = 0; i < 4; i++) {
113
u32 reg = SSI_SYS_STATUS(i * 2) + offset;
114
u32 status = rsnd_mod_read(mod, reg);
115
u32 val = 0xf << (shift * 4);
116
117
status &= val;
118
if (status) {
119
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
120
struct device *dev = rsnd_priv_to_dev(priv);
121
122
rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
123
rsnd_mod_name(mod), status);
124
error = true;
125
}
126
rsnd_mod_write(mod, reg, val);
127
}
128
out:
129
return error;
130
}
131
132
static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
133
struct rsnd_dai_stream *io,
134
enum rsnd_mod_type type)
135
{
136
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
137
int busif = rsnd_mod_id_sub(mod);
138
139
return &ssiu->busif_status[busif];
140
}
141
142
static int rsnd_ssiu_init(struct rsnd_mod *mod,
143
struct rsnd_dai_stream *io,
144
struct rsnd_priv *priv)
145
{
146
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
147
u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
148
int use_busif = rsnd_ssi_use_busif(io);
149
int id = rsnd_mod_id(mod);
150
int is_clk_master = rsnd_rdai_is_clk_master(rdai);
151
u32 val1, val2;
152
153
/* clear status */
154
rsnd_ssiu_busif_err_status_clear(mod);
155
156
/* Gen4 doesn't have SSI_MODE */
157
if (rsnd_is_gen4(priv))
158
goto ssi_mode_setting_end;
159
160
/*
161
* SSI_MODE0
162
*/
163
rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
164
165
/*
166
* SSI_MODE1 / SSI_MODE2
167
*
168
* FIXME
169
* sharing/multi with SSI0 are mainly supported
170
*/
171
val1 = rsnd_mod_read(mod, SSI_MODE1);
172
val2 = rsnd_mod_read(mod, SSI_MODE2);
173
if (rsnd_ssi_is_pin_sharing(io)) {
174
175
ssis |= (1 << id);
176
177
} else if (ssis) {
178
/*
179
* Multi SSI
180
*
181
* set synchronized bit here
182
*/
183
184
/* SSI4 is synchronized with SSI3 */
185
if (ssis & (1 << 4))
186
val1 |= (1 << 20);
187
/* SSI012 are synchronized */
188
if (ssis == 0x0006)
189
val1 |= (1 << 4);
190
/* SSI0129 are synchronized */
191
if (ssis == 0x0206)
192
val2 |= (1 << 4);
193
}
194
195
/* SSI1 is sharing pin with SSI0 */
196
if (ssis & (1 << 1))
197
val1 |= is_clk_master ? 0x2 : 0x1;
198
199
/* SSI2 is sharing pin with SSI0 */
200
if (ssis & (1 << 2))
201
val1 |= is_clk_master ? 0x2 << 2 :
202
0x1 << 2;
203
/* SSI4 is sharing pin with SSI3 */
204
if (ssis & (1 << 4))
205
val1 |= is_clk_master ? 0x2 << 16 :
206
0x1 << 16;
207
/* SSI9 is sharing pin with SSI0 */
208
if (ssis & (1 << 9))
209
val2 |= is_clk_master ? 0x2 : 0x1;
210
211
rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
212
rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
213
214
ssi_mode_setting_end:
215
/*
216
* Enable busif buffer over/under run interrupt.
217
* It will be handled from ssi.c
218
* see
219
* __rsnd_ssi_interrupt()
220
*/
221
rsnd_ssiu_busif_err_irq_enable(mod);
222
223
return 0;
224
}
225
226
static int rsnd_ssiu_quit(struct rsnd_mod *mod,
227
struct rsnd_dai_stream *io,
228
struct rsnd_priv *priv)
229
{
230
/* disable busif buffer over/under run interrupt. */
231
rsnd_ssiu_busif_err_irq_disable(mod);
232
233
return 0;
234
}
235
236
static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
237
.name = SSIU_NAME,
238
.init = rsnd_ssiu_init,
239
.quit = rsnd_ssiu_quit,
240
.get_status = rsnd_ssiu_get_status,
241
};
242
243
static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
244
struct rsnd_dai_stream *io,
245
struct rsnd_priv *priv)
246
{
247
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
248
u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
249
u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
250
int ret;
251
u32 mode = 0;
252
253
ret = rsnd_ssiu_init(mod, io, priv);
254
if (ret < 0)
255
return ret;
256
257
ssiu->usrcnt++;
258
259
/*
260
* TDM Extend/Split Mode
261
* see
262
* rsnd_ssi_config_init()
263
*/
264
if (rsnd_runtime_is_tdm(io))
265
mode = TDM_EXT;
266
else if (rsnd_runtime_is_tdm_split(io))
267
mode = TDM_SPLIT;
268
269
rsnd_mod_write(mod, SSI_MODE, mode);
270
271
if (rsnd_ssi_use_busif(io)) {
272
int id = rsnd_mod_id(mod);
273
int busif = rsnd_mod_id_sub(mod);
274
enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
275
276
if ((id == 9) && (busif >= 4)) {
277
adinr_reg = SSI9_BUSIF_ADINR(busif);
278
mode_reg = SSI9_BUSIF_MODE(busif);
279
dalign_reg = SSI9_BUSIF_DALIGN(busif);
280
} else {
281
adinr_reg = SSI_BUSIF_ADINR(busif);
282
mode_reg = SSI_BUSIF_MODE(busif);
283
dalign_reg = SSI_BUSIF_DALIGN(busif);
284
}
285
286
rsnd_mod_write(mod, adinr_reg,
287
rsnd_get_adinr_bit(mod, io) |
288
(rsnd_io_is_play(io) ?
289
rsnd_runtime_channel_after_ctu(io) :
290
rsnd_runtime_channel_original(io)));
291
rsnd_mod_write(mod, mode_reg,
292
rsnd_get_busif_shift(io, mod) | 1);
293
rsnd_mod_write(mod, dalign_reg,
294
rsnd_get_dalign(mod, io));
295
}
296
297
if (has_hdmi0 || has_hdmi1) {
298
enum rsnd_mod_type rsnd_ssi_array[] = {
299
RSND_MOD_SSIM1,
300
RSND_MOD_SSIM2,
301
RSND_MOD_SSIM3,
302
};
303
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
304
struct rsnd_mod *pos;
305
u32 val;
306
int i;
307
308
i = rsnd_mod_id(ssi_mod);
309
310
/* output all same SSI as default */
311
val = i << 16 |
312
i << 20 |
313
i << 24 |
314
i << 28 |
315
i;
316
317
for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
318
int shift = (i * 4) + 20;
319
320
val = (val & ~(0xF << shift)) |
321
rsnd_mod_id(pos) << shift;
322
}
323
324
if (has_hdmi0)
325
rsnd_mod_write(mod, HDMI0_SEL, val);
326
if (has_hdmi1)
327
rsnd_mod_write(mod, HDMI1_SEL, val);
328
}
329
330
return 0;
331
}
332
333
static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
334
struct rsnd_dai_stream *io,
335
struct rsnd_priv *priv)
336
{
337
int busif = rsnd_mod_id_sub(mod);
338
339
if (!rsnd_ssi_use_busif(io))
340
return 0;
341
342
rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
343
344
if (rsnd_ssi_multi_secondaries_runtime(io))
345
rsnd_mod_write(mod, SSI_CONTROL, 0x1);
346
347
return 0;
348
}
349
350
static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
351
struct rsnd_dai_stream *io,
352
struct rsnd_priv *priv)
353
{
354
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
355
int busif = rsnd_mod_id_sub(mod);
356
357
if (!rsnd_ssi_use_busif(io))
358
return 0;
359
360
rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
361
362
if (--ssiu->usrcnt)
363
return 0;
364
365
if (rsnd_ssi_multi_secondaries_runtime(io))
366
rsnd_mod_write(mod, SSI_CONTROL, 0);
367
368
return 0;
369
}
370
371
static int rsnd_ssiu_id(struct rsnd_mod *mod)
372
{
373
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
374
375
/* see rsnd_ssiu_probe() */
376
return ssiu->id;
377
}
378
379
static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
380
{
381
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
382
383
/* see rsnd_ssiu_probe() */
384
return ssiu->id_sub;
385
}
386
387
static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
388
struct rsnd_mod *mod)
389
{
390
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
391
int is_play = rsnd_io_is_play(io);
392
char *name;
393
394
/*
395
* It should use "rcar_sound,ssiu" on DT.
396
* But, we need to keep compatibility for old version.
397
*
398
* If it has "rcar_sound.ssiu", it will be used.
399
* If not, "rcar_sound.ssi" will be used.
400
* see
401
* rsnd_ssi_dma_req()
402
* rsnd_dma_of_path()
403
*/
404
405
name = is_play ? "rx" : "tx";
406
407
return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
408
SSIU_NAME, mod, name);
409
}
410
411
#ifdef CONFIG_DEBUG_FS
412
static void rsnd_ssiu_debug_info(struct seq_file *m,
413
struct rsnd_dai_stream *io,
414
struct rsnd_mod *mod)
415
{
416
rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU,
417
rsnd_mod_id(mod) * 0x80, 0x80);
418
}
419
#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
420
#else
421
#define DEBUG_INFO
422
#endif
423
424
static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
425
.name = SSIU_NAME,
426
.dma_req = rsnd_ssiu_dma_req,
427
.init = rsnd_ssiu_init_gen2,
428
.quit = rsnd_ssiu_quit,
429
.start = rsnd_ssiu_start_gen2,
430
.stop = rsnd_ssiu_stop_gen2,
431
.get_status = rsnd_ssiu_get_status,
432
DEBUG_INFO
433
};
434
435
static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
436
{
437
if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
438
id = 0;
439
440
return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
441
}
442
443
static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
444
struct rsnd_dai_stream *io)
445
{
446
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
447
struct rsnd_ssiu *ssiu;
448
int is_dma_mode;
449
int i;
450
451
if (!ssi_mod)
452
return;
453
454
is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod);
455
456
/* select BUSIF0 */
457
for_each_rsnd_ssiu(ssiu, priv, i) {
458
struct rsnd_mod *mod = rsnd_mod_get(ssiu);
459
460
if (is_dma_mode &&
461
(rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
462
(rsnd_mod_id_sub(mod) == 0)) {
463
rsnd_dai_connect(mod, io, mod->type);
464
return;
465
}
466
}
467
}
468
469
void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
470
struct device_node *playback,
471
struct device_node *capture)
472
{
473
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
474
struct device *dev = rsnd_priv_to_dev(priv);
475
struct device_node *node = rsnd_ssiu_of_node(priv);
476
struct rsnd_dai_stream *io_p = &rdai->playback;
477
struct rsnd_dai_stream *io_c = &rdai->capture;
478
479
/* use rcar_sound,ssiu if exist */
480
if (node) {
481
int i = 0;
482
483
for_each_child_of_node_scoped(node, np) {
484
struct rsnd_mod *mod;
485
486
i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
487
if (i < 0)
488
break;
489
490
mod = rsnd_ssiu_mod_get(priv, i);
491
492
if (np == playback)
493
rsnd_dai_connect(mod, io_p, mod->type);
494
if (np == capture)
495
rsnd_dai_connect(mod, io_c, mod->type);
496
i++;
497
}
498
499
of_node_put(node);
500
}
501
502
/* Keep DT compatibility */
503
if (!rsnd_io_to_mod_ssiu(io_p))
504
rsnd_parse_connect_ssiu_compatible(priv, io_p);
505
if (!rsnd_io_to_mod_ssiu(io_c))
506
rsnd_parse_connect_ssiu_compatible(priv, io_c);
507
}
508
509
int rsnd_ssiu_probe(struct rsnd_priv *priv)
510
{
511
struct device *dev = rsnd_priv_to_dev(priv);
512
struct device_node *node;
513
struct rsnd_ssiu *ssiu;
514
struct rsnd_mod_ops *ops;
515
const int *list = NULL;
516
int i, nr;
517
518
/*
519
* Keep DT compatibility.
520
* if it has "rcar_sound,ssiu", use it.
521
* if not, use "rcar_sound,ssi"
522
* see
523
* rsnd_ssiu_bufsif_to_id()
524
*/
525
node = rsnd_ssiu_of_node(priv);
526
if (node)
527
nr = rsnd_node_count(priv, node, SSIU_NAME);
528
else
529
nr = priv->ssi_nr;
530
531
if (!nr)
532
return -EINVAL;
533
534
ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
535
if (!ssiu)
536
return -ENOMEM;
537
538
priv->ssiu = ssiu;
539
priv->ssiu_nr = nr;
540
541
if (rsnd_is_gen1(priv))
542
ops = &rsnd_ssiu_ops_gen1;
543
else
544
ops = &rsnd_ssiu_ops_gen2;
545
546
/* Keep compatibility */
547
nr = 0;
548
if ((node) &&
549
(ops == &rsnd_ssiu_ops_gen2)) {
550
ops->id = rsnd_ssiu_id;
551
ops->id_sub = rsnd_ssiu_id_sub;
552
553
if (rsnd_is_gen2(priv)) {
554
list = gen2_id;
555
nr = ARRAY_SIZE(gen2_id);
556
} else if (rsnd_is_gen3(priv)) {
557
list = gen3_id;
558
nr = ARRAY_SIZE(gen3_id);
559
} else if (rsnd_is_gen4(priv)) {
560
list = gen4_id;
561
nr = ARRAY_SIZE(gen4_id);
562
} else {
563
dev_err(dev, "unknown SSIU\n");
564
return -ENODEV;
565
}
566
}
567
568
for_each_rsnd_ssiu(ssiu, priv, i) {
569
int ret;
570
571
if (node) {
572
int j;
573
574
/*
575
* see
576
* rsnd_ssiu_get_id()
577
* rsnd_ssiu_get_id_sub()
578
*/
579
for (j = 0; j < nr; j++) {
580
if (list[j] > i)
581
break;
582
ssiu->id = j;
583
ssiu->id_sub = i - list[ssiu->id];
584
}
585
} else {
586
ssiu->id = i;
587
}
588
589
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
590
ops, NULL, RSND_MOD_SSIU, i);
591
if (ret)
592
return ret;
593
}
594
595
return 0;
596
}
597
598
void rsnd_ssiu_remove(struct rsnd_priv *priv)
599
{
600
struct rsnd_ssiu *ssiu;
601
int i;
602
603
for_each_rsnd_ssiu(ssiu, priv, i) {
604
rsnd_mod_quit(rsnd_mod_get(ssiu));
605
}
606
}
607
608