summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/lpass-va-macro.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2025-12-02 07:12:56 +0100
committerTakashi Iwai <tiwai@suse.de>2025-12-02 07:12:56 +0100
commit9747b22a417d2a7c478678143863b9777de104e4 (patch)
tree2690242ac1e95570c3e56a3106752af4cc2b5472 /sound/soc/codecs/lpass-va-macro.c
parentef5e0a02d842b2c6dfcfd9b80feb185769b892ef (diff)
parentc5fae31f60a91dbe884ef2789fb3440bb4cddf05 (diff)
Merge tag 'asoc-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v6.19 This is a very large set of updates, as well as some more extensive cleanup work from Morimto-san we've also added a generic SCDA class driver for SoundWire devices enabling us to support many chips with no custom code. There's also a batch of new drivers added for both SoCs and CODECs. - Added a SoundWire SCDA generic class driver, pulling in a little regmap work to support it. - A *lot* of cleaup and API improvement work from Morimoto-san. - Lots of work on the existing Cirrus, Intel, Maxim and Qualcomm drivers. - Support for Allwinner A523, Mediatek MT8189, Qualcomm QCM2290, QRB2210 and SM6115, SpacemiT K1, and TI TAS2568, TAS5802, TAS5806, TAS5815, TAS5828 and TAS5830. This also pulls in some gpiolib changes supporting shared GPIOs in the core there so we can convert some of the ASoC drivers open coding handling of that to the core functionality.
Diffstat (limited to 'sound/soc/codecs/lpass-va-macro.c')
-rw-r--r--sound/soc/codecs/lpass-va-macro.c104
1 files changed, 69 insertions, 35 deletions
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 92c177b82a02..528d5b167ecf 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
@@ -64,8 +65,15 @@
#define CDC_VA_TOP_CSR_I2S_CLK (0x00A8)
#define CDC_VA_TOP_CSR_I2S_RESET (0x00AC)
#define CDC_VA_TOP_CSR_CORE_ID_0 (0x00C0)
+ #define CORE_ID_0_REV_MAJ GENMASK(7, 0)
#define CDC_VA_TOP_CSR_CORE_ID_1 (0x00C4)
+#define CORE_ID_1_HAS_WSAMACRO BIT(0)
+#define CORE_ID_1_HAS_RXMACRO BIT(1)
+#define CORE_ID_1_HAS_TXMACRO BIT(2)
+#define CORE_ID_1_HAS_VAMACRO BIT(3)
#define CDC_VA_TOP_CSR_CORE_ID_2 (0x00C8)
+ #define CORE_ID_2_REV_MIN GENMASK(7, 4)
+ #define CORE_ID_2_REV_STEP GENMASK(3, 0)
#define CDC_VA_TOP_CSR_CORE_ID_3 (0x00CC)
#define CDC_VA_TOP_CSR_SWR_MIC_CTL0 (0x00D0)
#define CDC_VA_TOP_CSR_SWR_MIC_CTL1 (0x00D4)
@@ -516,8 +524,7 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -556,8 +563,7 @@ static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct soc_mixer_control *mc =
@@ -577,8 +583,7 @@ static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct snd_soc_dapm_update *update = NULL;
@@ -819,7 +824,7 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w,
static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct va_macro *va = snd_soc_component_get_drvdata(comp);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -832,7 +837,7 @@ static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
int value = ucontrol->value.enumerated.item[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -1462,39 +1467,63 @@ undefined_rate:
return dmic_sample_rate;
}
-static void va_macro_set_lpass_codec_version(struct va_macro *va)
+static int va_macro_set_lpass_codec_version(struct va_macro *va)
{
- int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0;
int version = LPASS_CODEC_VERSION_UNKNOWN;
+ u32 maj, min, step;
+ u32 val;
- regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &core_id_0);
- regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &core_id_1);
- regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_2, &core_id_2);
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &val);
+ maj = FIELD_GET(CORE_ID_0_REV_MAJ, val);
- if ((core_id_0 == 0x01) && (core_id_1 == 0x0F))
- version = LPASS_CODEC_VERSION_2_0;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && core_id_2 == 0x01)
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &val);
+ if (!FIELD_GET(CORE_ID_1_HAS_VAMACRO, val)) {
+ dev_err(va->dev, "This is not a VA macro instance\n");
+ return -ENODEV;
+ }
+
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_2, &val);
+ min = FIELD_GET(CORE_ID_2_REV_MIN, val);
+ step = FIELD_GET(CORE_ID_2_REV_STEP, val);
+
+ if (maj == 1) {
version = LPASS_CODEC_VERSION_2_0;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0E))
- version = LPASS_CODEC_VERSION_2_1;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x50 || core_id_2 == 0x51))
- version = LPASS_CODEC_VERSION_2_5;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x60 || core_id_2 == 0x61))
- version = LPASS_CODEC_VERSION_2_6;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x70 || core_id_2 == 0x71))
- version = LPASS_CODEC_VERSION_2_7;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x80 || core_id_2 == 0x81))
- version = LPASS_CODEC_VERSION_2_8;
- if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x90 || core_id_2 == 0x91))
- version = LPASS_CODEC_VERSION_2_9;
-
- if (version == LPASS_CODEC_VERSION_UNKNOWN)
- dev_warn(va->dev, "Unknown Codec version, ID: %02x / %02x / %02x\n",
- core_id_0, core_id_1, core_id_2);
+ } else if (maj == 2) {
+ switch (min) {
+ case 0:
+ version = LPASS_CODEC_VERSION_2_0;
+ break;
+ case 5:
+ version = LPASS_CODEC_VERSION_2_5;
+ break;
+ case 6:
+ version = LPASS_CODEC_VERSION_2_6;
+ break;
+ case 7:
+ version = LPASS_CODEC_VERSION_2_7;
+ break;
+ case 8:
+ version = LPASS_CODEC_VERSION_2_8;
+ break;
+ case 9:
+ version = LPASS_CODEC_VERSION_2_9;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (version == LPASS_CODEC_VERSION_UNKNOWN) {
+ dev_err(va->dev, "VA Macro v%u.%u.%u is not supported\n",
+ maj, min, step);
+ return -EOPNOTSUPP;
+ }
lpass_macro_set_codec_version(version);
dev_dbg(va->dev, "LPASS Codec Version %s\n", lpass_macro_get_codec_version_string(version));
+
+ return 0;
}
static int va_macro_probe(struct platform_device *pdev)
@@ -1594,10 +1623,14 @@ static int va_macro_probe(struct platform_device *pdev)
* old version of codecs do not have a reliable way to determine the
* version from registers, get them from soc specific data
*/
- if (data->version)
+ if (data->version) {
lpass_macro_set_codec_version(data->version);
- else /* read version from register */
- va_macro_set_lpass_codec_version(va);
+ } else {
+ /* read version from register */
+ ret = va_macro_set_lpass_codec_version(va);
+ if (ret)
+ goto err_clkout;
+ }
if (va->has_swr_master) {
/* Set default CLK div to 1 */
@@ -1723,6 +1756,7 @@ static const struct dev_pm_ops va_macro_pm_ops = {
static const struct of_device_id va_macro_dt_match[] = {
{ .compatible = "qcom,sc7280-lpass-va-macro", .data = &sm8250_va_data },
+ { .compatible = "qcom,sm6115-lpass-va-macro", .data = &sm8450_va_data },
{ .compatible = "qcom,sm8250-lpass-va-macro", .data = &sm8250_va_data },
{ .compatible = "qcom,sm8450-lpass-va-macro", .data = &sm8450_va_data },
{ .compatible = "qcom,sm8550-lpass-va-macro", .data = &sm8550_va_data },