Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/boards/sof_maxim_common.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
//
3
// Copyright(c) 2020 Intel Corporation
4
#include <linux/module.h>
5
#include <linux/string.h>
6
#include <sound/pcm.h>
7
#include <sound/pcm_params.h>
8
#include <sound/soc.h>
9
#include <sound/soc-acpi.h>
10
#include <sound/soc-dai.h>
11
#include <sound/soc-dapm.h>
12
#include <sound/sof.h>
13
#include <uapi/sound/asound.h>
14
#include "../common/soc-intel-quirks.h"
15
#include "sof_maxim_common.h"
16
17
/*
18
* Common structures and functions
19
*/
20
static const struct snd_kcontrol_new maxim_2spk_kcontrols[] = {
21
SOC_DAPM_PIN_SWITCH("Left Spk"),
22
SOC_DAPM_PIN_SWITCH("Right Spk"),
23
24
};
25
26
static const struct snd_soc_dapm_widget maxim_2spk_widgets[] = {
27
SND_SOC_DAPM_SPK("Left Spk", NULL),
28
SND_SOC_DAPM_SPK("Right Spk", NULL),
29
};
30
31
/* helper function to get the number of specific codec */
32
static unsigned int get_num_codecs(const char *hid)
33
{
34
struct acpi_device *adev;
35
unsigned int dev_num = 0;
36
37
for_each_acpi_dev_match(adev, hid, NULL, -1)
38
dev_num++;
39
40
return dev_num;
41
}
42
43
/*
44
* Maxim MAX98373
45
*/
46
#define MAX_98373_PIN_NAME 16
47
48
static const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
49
/* speaker */
50
{ "Left Spk", NULL, "Left BE_OUT" },
51
{ "Right Spk", NULL, "Right BE_OUT" },
52
};
53
54
static struct snd_soc_codec_conf max_98373_codec_conf[] = {
55
{
56
.dlc = COMP_CODEC_CONF(MAX_98373_DEV0_NAME),
57
.name_prefix = "Right",
58
},
59
{
60
.dlc = COMP_CODEC_CONF(MAX_98373_DEV1_NAME),
61
.name_prefix = "Left",
62
},
63
};
64
65
static struct snd_soc_dai_link_component max_98373_components[] = {
66
{ /* For Right */
67
.name = MAX_98373_DEV0_NAME,
68
.dai_name = MAX_98373_CODEC_DAI,
69
},
70
{ /* For Left */
71
.name = MAX_98373_DEV1_NAME,
72
.dai_name = MAX_98373_CODEC_DAI,
73
},
74
};
75
76
/*
77
* According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask
78
* should choose two channels from TDM slots, the LSB of rx mask is left channel
79
* and the other one is right channel.
80
*/
81
static const struct {
82
unsigned int rx;
83
} max_98373_tdm_mask[] = {
84
{.rx = 0x3},
85
{.rx = 0x3},
86
};
87
88
/*
89
* The tx mask indicates which channel(s) contains output IV-sense data and
90
* others should set to Hi-Z. Here we get the channel number from codec's ACPI
91
* device property "maxim,vmon-slot-no" and "maxim,imon-slot-no" to generate the
92
* mask. Refer to the max98373_slot_config() function in max98373.c codec driver.
93
*/
94
static unsigned int max_98373_get_tx_mask(struct device *dev)
95
{
96
int vmon_slot;
97
int imon_slot;
98
99
if (device_property_read_u32(dev, "maxim,vmon-slot-no", &vmon_slot))
100
vmon_slot = 0;
101
102
if (device_property_read_u32(dev, "maxim,imon-slot-no", &imon_slot))
103
imon_slot = 1;
104
105
dev_dbg(dev, "vmon_slot %d imon_slot %d\n", vmon_slot, imon_slot);
106
107
return (0x1 << vmon_slot) | (0x1 << imon_slot);
108
}
109
110
static int max_98373_hw_params(struct snd_pcm_substream *substream,
111
struct snd_pcm_hw_params *params)
112
{
113
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
114
struct snd_soc_dai_link *dai_link = rtd->dai_link;
115
struct snd_soc_dai *codec_dai;
116
int i;
117
int tdm_slots;
118
unsigned int tx_mask;
119
unsigned int tx_mask_used = 0x0;
120
int ret = 0;
121
122
for_each_rtd_codec_dais(rtd, i, codec_dai) {
123
if (i >= ARRAY_SIZE(max_98373_tdm_mask)) {
124
dev_err(codec_dai->dev, "only 2 amps are supported\n");
125
return -EINVAL;
126
}
127
128
switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
129
case SND_SOC_DAIFMT_DSP_A:
130
case SND_SOC_DAIFMT_DSP_B:
131
/* get the tplg configured tdm slot number */
132
tdm_slots = sof_dai_get_tdm_slots(rtd);
133
if (tdm_slots <= 0) {
134
dev_err(rtd->dev, "invalid tdm slots %d\n",
135
tdm_slots);
136
return -EINVAL;
137
}
138
139
/* get the tx mask from ACPI device properties */
140
tx_mask = max_98373_get_tx_mask(codec_dai->dev);
141
if (!tx_mask)
142
return -EINVAL;
143
144
if (tx_mask & tx_mask_used) {
145
dev_err(codec_dai->dev, "invalid tx mask 0x%x, used 0x%x\n",
146
tx_mask, tx_mask_used);
147
return -EINVAL;
148
}
149
150
tx_mask_used |= tx_mask;
151
152
/*
153
* check if tdm slot number is too small for channel
154
* allocation
155
*/
156
if (fls(tx_mask) > tdm_slots) {
157
dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n",
158
fls(tx_mask), tdm_slots);
159
return -EINVAL;
160
}
161
162
if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) {
163
dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n",
164
fls(max_98373_tdm_mask[i].rx), tdm_slots);
165
return -EINVAL;
166
}
167
168
dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n",
169
tx_mask, max_98373_tdm_mask[i].rx,
170
tdm_slots, params_width(params));
171
172
ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask,
173
max_98373_tdm_mask[i].rx,
174
tdm_slots,
175
params_width(params));
176
if (ret < 0) {
177
dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
178
ret);
179
return ret;
180
}
181
break;
182
default:
183
dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
184
break;
185
}
186
}
187
return 0;
188
}
189
190
static int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
191
{
192
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
193
struct snd_soc_dai *codec_dai;
194
struct snd_soc_dai *cpu_dai;
195
int j;
196
int ret = 0;
197
198
/* set spk pin by playback only */
199
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
200
return 0;
201
202
cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
203
for_each_rtd_codec_dais(rtd, j, codec_dai) {
204
struct snd_soc_dapm_context *dapm =
205
snd_soc_component_get_dapm(cpu_dai->component);
206
char pin_name[MAX_98373_PIN_NAME];
207
208
snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
209
codec_dai->component->name_prefix);
210
211
switch (cmd) {
212
case SNDRV_PCM_TRIGGER_START:
213
case SNDRV_PCM_TRIGGER_RESUME:
214
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
215
ret = snd_soc_dapm_enable_pin(dapm, pin_name);
216
if (!ret)
217
snd_soc_dapm_sync(dapm);
218
break;
219
case SNDRV_PCM_TRIGGER_STOP:
220
case SNDRV_PCM_TRIGGER_SUSPEND:
221
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
222
ret = snd_soc_dapm_disable_pin(dapm, pin_name);
223
if (!ret)
224
snd_soc_dapm_sync(dapm);
225
break;
226
default:
227
break;
228
}
229
}
230
231
return ret;
232
}
233
234
static const struct snd_soc_ops max_98373_ops = {
235
.hw_params = max_98373_hw_params,
236
.trigger = max_98373_trigger,
237
};
238
239
static int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
240
{
241
struct snd_soc_card *card = rtd->card;
242
unsigned int num_codecs = get_num_codecs(MAX_98373_ACPI_HID);
243
int ret;
244
245
switch (num_codecs) {
246
case 2:
247
ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets,
248
ARRAY_SIZE(maxim_2spk_widgets));
249
if (ret) {
250
dev_err(rtd->dev, "fail to add max98373 widgets, ret %d\n",
251
ret);
252
return ret;
253
}
254
255
ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols,
256
ARRAY_SIZE(maxim_2spk_kcontrols));
257
if (ret) {
258
dev_err(rtd->dev, "fail to add max98373 kcontrols, ret %d\n",
259
ret);
260
return ret;
261
}
262
263
ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes,
264
ARRAY_SIZE(max_98373_dapm_routes));
265
if (ret) {
266
dev_err(rtd->dev, "fail to add max98373 routes, ret %d\n",
267
ret);
268
return ret;
269
}
270
break;
271
default:
272
dev_err(rtd->dev, "max98373: invalid num_codecs %d\n", num_codecs);
273
return -EINVAL;
274
}
275
276
return ret;
277
}
278
279
void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link)
280
{
281
link->codecs = max_98373_components;
282
link->num_codecs = ARRAY_SIZE(max_98373_components);
283
link->init = max_98373_spk_codec_init;
284
link->ops = &max_98373_ops;
285
}
286
EXPORT_SYMBOL_NS(max_98373_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
287
288
void max_98373_set_codec_conf(struct snd_soc_card *card)
289
{
290
card->codec_conf = max_98373_codec_conf;
291
card->num_configs = ARRAY_SIZE(max_98373_codec_conf);
292
}
293
EXPORT_SYMBOL_NS(max_98373_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
294
295
/*
296
* Maxim MAX98390
297
*/
298
static const struct snd_soc_dapm_route max_98390_dapm_routes[] = {
299
/* speaker */
300
{ "Left Spk", NULL, "Left BE_OUT" },
301
{ "Right Spk", NULL, "Right BE_OUT" },
302
};
303
304
static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = {
305
SOC_DAPM_PIN_SWITCH("TL Spk"),
306
SOC_DAPM_PIN_SWITCH("TR Spk"),
307
};
308
309
static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = {
310
SND_SOC_DAPM_SPK("TL Spk", NULL),
311
SND_SOC_DAPM_SPK("TR Spk", NULL),
312
};
313
314
static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = {
315
/* Tweeter speaker */
316
{ "TL Spk", NULL, "Tweeter Left BE_OUT" },
317
{ "TR Spk", NULL, "Tweeter Right BE_OUT" },
318
};
319
320
static struct snd_soc_codec_conf max_98390_cml_codec_conf[] = {
321
{
322
.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
323
.name_prefix = "Left",
324
},
325
{
326
.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
327
.name_prefix = "Right",
328
},
329
};
330
331
static struct snd_soc_codec_conf max_98390_codec_conf[] = {
332
{
333
.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
334
.name_prefix = "Right",
335
},
336
{
337
.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
338
.name_prefix = "Left",
339
},
340
{
341
.dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME),
342
.name_prefix = "Tweeter Right",
343
},
344
{
345
.dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME),
346
.name_prefix = "Tweeter Left",
347
},
348
};
349
350
static struct snd_soc_dai_link_component max_98390_components[] = {
351
{
352
.name = MAX_98390_DEV0_NAME,
353
.dai_name = MAX_98390_CODEC_DAI,
354
},
355
{
356
.name = MAX_98390_DEV1_NAME,
357
.dai_name = MAX_98390_CODEC_DAI,
358
},
359
{
360
.name = MAX_98390_DEV2_NAME,
361
.dai_name = MAX_98390_CODEC_DAI,
362
},
363
{
364
.name = MAX_98390_DEV3_NAME,
365
.dai_name = MAX_98390_CODEC_DAI,
366
},
367
};
368
369
static const struct {
370
unsigned int tx;
371
unsigned int rx;
372
} max_98390_tdm_mask[] = {
373
{.tx = 0x01, .rx = 0x3},
374
{.tx = 0x02, .rx = 0x3},
375
{.tx = 0x04, .rx = 0x3},
376
{.tx = 0x08, .rx = 0x3},
377
};
378
379
static int max_98390_hw_params(struct snd_pcm_substream *substream,
380
struct snd_pcm_hw_params *params)
381
{
382
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
383
struct snd_soc_dai_link *dai_link = rtd->dai_link;
384
struct snd_soc_dai *codec_dai;
385
int i, ret;
386
387
for_each_rtd_codec_dais(rtd, i, codec_dai) {
388
if (i >= ARRAY_SIZE(max_98390_tdm_mask)) {
389
dev_err(codec_dai->dev, "invalid codec index %d\n", i);
390
return -ENODEV;
391
}
392
393
switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
394
case SND_SOC_DAIFMT_DSP_A:
395
case SND_SOC_DAIFMT_DSP_B:
396
/* 4-slot TDM */
397
ret = snd_soc_dai_set_tdm_slot(codec_dai,
398
max_98390_tdm_mask[i].tx,
399
max_98390_tdm_mask[i].rx,
400
4,
401
params_width(params));
402
if (ret < 0) {
403
dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
404
ret);
405
return ret;
406
}
407
break;
408
default:
409
dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
410
break;
411
}
412
}
413
return 0;
414
}
415
416
static int max_98390_init(struct snd_soc_pcm_runtime *rtd)
417
{
418
struct snd_soc_card *card = rtd->card;
419
unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
420
int ret;
421
422
switch (num_codecs) {
423
case 4:
424
/* add widgets/controls/dapm for tweeter speakers */
425
ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets,
426
ARRAY_SIZE(max_98390_tt_dapm_widgets));
427
if (ret) {
428
dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n",
429
ret);
430
/* Don't need to add routes if widget addition failed */
431
return ret;
432
}
433
434
ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols,
435
ARRAY_SIZE(max_98390_tt_kcontrols));
436
if (ret) {
437
dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n",
438
ret);
439
return ret;
440
}
441
442
ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes,
443
ARRAY_SIZE(max_98390_tt_dapm_routes));
444
if (ret) {
445
dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n",
446
ret);
447
return ret;
448
}
449
450
fallthrough;
451
case 2:
452
/* add regular speakers dapm route */
453
ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets,
454
ARRAY_SIZE(maxim_2spk_widgets));
455
if (ret) {
456
dev_err(rtd->dev, "fail to add max98390 woofer widgets, ret %d\n",
457
ret);
458
return ret;
459
}
460
461
ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols,
462
ARRAY_SIZE(maxim_2spk_kcontrols));
463
if (ret) {
464
dev_err(rtd->dev, "fail to add max98390 woofer kcontrols, ret %d\n",
465
ret);
466
return ret;
467
}
468
469
ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
470
ARRAY_SIZE(max_98390_dapm_routes));
471
if (ret) {
472
dev_err(rtd->dev, "unable to add dapm routes, ret %d\n",
473
ret);
474
return ret;
475
}
476
break;
477
default:
478
dev_err(rtd->dev, "invalid codec number %d\n", num_codecs);
479
return -EINVAL;
480
}
481
482
return ret;
483
}
484
485
static const struct snd_soc_ops max_98390_ops = {
486
.hw_params = max_98390_hw_params,
487
};
488
489
void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link)
490
{
491
unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
492
493
link->codecs = max_98390_components;
494
495
switch (num_codecs) {
496
case 2:
497
case 4:
498
link->num_codecs = num_codecs;
499
break;
500
default:
501
dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
502
MAX_98390_ACPI_HID);
503
break;
504
}
505
506
link->init = max_98390_init;
507
link->ops = &max_98390_ops;
508
}
509
EXPORT_SYMBOL_NS(max_98390_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
510
511
void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card)
512
{
513
unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
514
515
card->codec_conf = max_98390_codec_conf;
516
517
switch (num_codecs) {
518
case 2:
519
if (soc_intel_is_cml())
520
card->codec_conf = max_98390_cml_codec_conf;
521
522
fallthrough;
523
case 4:
524
card->num_configs = num_codecs;
525
break;
526
default:
527
dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
528
MAX_98390_ACPI_HID);
529
break;
530
}
531
}
532
EXPORT_SYMBOL_NS(max_98390_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
533
534
/*
535
* Maxim MAX98357A/MAX98360A
536
*/
537
static const struct snd_kcontrol_new max_98357a_kcontrols[] = {
538
SOC_DAPM_PIN_SWITCH("Spk"),
539
};
540
541
static const struct snd_soc_dapm_widget max_98357a_dapm_widgets[] = {
542
SND_SOC_DAPM_SPK("Spk", NULL),
543
};
544
545
static const struct snd_soc_dapm_route max_98357a_dapm_routes[] = {
546
/* speaker */
547
{"Spk", NULL, "Speaker"},
548
};
549
550
static struct snd_soc_dai_link_component max_98357a_components[] = {
551
{
552
.name = MAX_98357A_DEV0_NAME,
553
.dai_name = MAX_98357A_CODEC_DAI,
554
}
555
};
556
557
static struct snd_soc_dai_link_component max_98360a_components[] = {
558
{
559
.name = MAX_98360A_DEV0_NAME,
560
.dai_name = MAX_98357A_CODEC_DAI,
561
}
562
};
563
564
static int max_98357a_init(struct snd_soc_pcm_runtime *rtd)
565
{
566
struct snd_soc_card *card = rtd->card;
567
int ret;
568
569
ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets,
570
ARRAY_SIZE(max_98357a_dapm_widgets));
571
if (ret) {
572
dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
573
/* Don't need to add routes if widget addition failed */
574
return ret;
575
}
576
577
ret = snd_soc_add_card_controls(card, max_98357a_kcontrols,
578
ARRAY_SIZE(max_98357a_kcontrols));
579
if (ret) {
580
dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
581
return ret;
582
}
583
584
ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes,
585
ARRAY_SIZE(max_98357a_dapm_routes));
586
587
if (ret)
588
dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
589
590
return ret;
591
}
592
593
void max_98357a_dai_link(struct snd_soc_dai_link *link)
594
{
595
link->codecs = max_98357a_components;
596
link->num_codecs = ARRAY_SIZE(max_98357a_components);
597
link->init = max_98357a_init;
598
}
599
EXPORT_SYMBOL_NS(max_98357a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
600
601
void max_98360a_dai_link(struct snd_soc_dai_link *link)
602
{
603
link->codecs = max_98360a_components;
604
link->num_codecs = ARRAY_SIZE(max_98360a_components);
605
link->init = max_98357a_init;
606
}
607
EXPORT_SYMBOL_NS(max_98360a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
608
609
MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers");
610
MODULE_LICENSE("GPL");
611
612