hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/sound/soc/codecs/tas5720.c
....@@ -1,18 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
34 *
4
- * Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com
5
+ * Copyright (C)2015-2016 Texas Instruments Incorporated - https://www.ti.com
56 *
67 * Author: Andreas Dannenberg <dannenberg@ti.com>
7
- *
8
- * This program is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License
10
- * version 2 as published by the Free Software Foundation.
11
- *
12
- * This program is distributed in the hope that it will be useful, but
13
- * WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * General Public License for more details.
168 */
179
1810 #include <linux/module.h>
....@@ -152,6 +144,7 @@
152144 int slots, int slot_width)
153145 {
154146 struct snd_soc_component *component = dai->component;
147
+ struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
155148 unsigned int first_slot;
156149 int ret;
157150
....@@ -185,6 +178,20 @@
185178 if (ret < 0)
186179 goto error_snd_soc_component_update_bits;
187180
181
+ /* Configure TDM slot width. This is only applicable to TAS5722. */
182
+ switch (tas5720->devtype) {
183
+ case TAS5722:
184
+ ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
185
+ TAS5722_TDM_SLOT_16B,
186
+ slot_width == 16 ?
187
+ TAS5722_TDM_SLOT_16B : 0);
188
+ if (ret < 0)
189
+ goto error_snd_soc_component_update_bits;
190
+ break;
191
+ default:
192
+ break;
193
+ }
194
+
188195 return 0;
189196
190197 error_snd_soc_component_update_bits:
....@@ -192,7 +199,7 @@
192199 return ret;
193200 }
194201
195
-static int tas5720_mute(struct snd_soc_dai *dai, int mute)
202
+static int tas5720_mute(struct snd_soc_dai *dai, int mute, int direction)
196203 {
197204 struct snd_soc_component *component = dai->component;
198205 int ret;
....@@ -485,15 +492,56 @@
485492 );
486493
487494 /*
488
- * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
489
- * setting the gain below -100 dB (register value <0x7) is effectively a MUTE
490
- * as per device datasheet.
495
+ * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
496
+ * depending on the device. Note that setting the gain below -100 dB
497
+ * (register value <0x7) is effectively a MUTE as per device datasheet.
498
+ *
499
+ * Note that for the TAS5722 the digital volume controls are actually split
500
+ * over two registers, so we need custom getters/setters for access.
491501 */
492
-static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
502
+static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0);
503
+static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
504
+
505
+static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
506
+ struct snd_ctl_elem_value *ucontrol)
507
+{
508
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
509
+ unsigned int val;
510
+
511
+ val = snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG);
512
+ ucontrol->value.integer.value[0] = val << 1;
513
+
514
+ val = snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG);
515
+ ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB;
516
+
517
+ return 0;
518
+}
519
+
520
+static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
521
+ struct snd_ctl_elem_value *ucontrol)
522
+{
523
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
524
+ unsigned int sel = ucontrol->value.integer.value[0];
525
+
526
+ snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
527
+ snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
528
+ TAS5722_VOL_CONTROL_LSB, sel);
529
+
530
+ return 0;
531
+}
493532
494533 static const struct snd_kcontrol_new tas5720_snd_controls[] = {
495534 SOC_SINGLE_TLV("Speaker Driver Playback Volume",
496
- TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv),
535
+ TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv),
536
+ SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
537
+ TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
538
+};
539
+
540
+static const struct snd_kcontrol_new tas5722_snd_controls[] = {
541
+ SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
542
+ 0, 0, 511, 0,
543
+ tas5722_volume_get, tas5722_volume_set,
544
+ tas5722_dac_tlv),
497545 SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
498546 TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
499547 };
....@@ -527,6 +575,23 @@
527575 .non_legacy_dai_naming = 1,
528576 };
529577
578
+static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
579
+ .probe = tas5720_codec_probe,
580
+ .remove = tas5720_codec_remove,
581
+ .suspend = tas5720_suspend,
582
+ .resume = tas5720_resume,
583
+ .controls = tas5722_snd_controls,
584
+ .num_controls = ARRAY_SIZE(tas5722_snd_controls),
585
+ .dapm_widgets = tas5720_dapm_widgets,
586
+ .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
587
+ .dapm_routes = tas5720_audio_map,
588
+ .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
589
+ .idle_bias_on = 1,
590
+ .use_pmdown_time = 1,
591
+ .endianness = 1,
592
+ .non_legacy_dai_naming = 1,
593
+};
594
+
530595 /* PCM rates supported by the TAS5720 driver */
531596 #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
532597 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
....@@ -539,7 +604,8 @@
539604 .hw_params = tas5720_hw_params,
540605 .set_fmt = tas5720_set_dai_fmt,
541606 .set_tdm_slot = tas5720_set_dai_tdm_slot,
542
- .digital_mute = tas5720_mute,
607
+ .mute_stream = tas5720_mute,
608
+ .no_capture_mute = 1,
543609 };
544610
545611 /*
....@@ -613,9 +679,23 @@
613679
614680 dev_set_drvdata(dev, data);
615681
616
- ret = devm_snd_soc_register_component(&client->dev,
617
- &soc_component_dev_tas5720,
618
- tas5720_dai, ARRAY_SIZE(tas5720_dai));
682
+ switch (id->driver_data) {
683
+ case TAS5720:
684
+ ret = devm_snd_soc_register_component(&client->dev,
685
+ &soc_component_dev_tas5720,
686
+ tas5720_dai,
687
+ ARRAY_SIZE(tas5720_dai));
688
+ break;
689
+ case TAS5722:
690
+ ret = devm_snd_soc_register_component(&client->dev,
691
+ &soc_component_dev_tas5722,
692
+ tas5720_dai,
693
+ ARRAY_SIZE(tas5720_dai));
694
+ break;
695
+ default:
696
+ dev_err(dev, "unexpected private driver data\n");
697
+ return -EINVAL;
698
+ }
619699 if (ret < 0) {
620700 dev_err(dev, "failed to register component: %d\n", ret);
621701 return ret;