[9610][EVB] madera: support Aov driver update
authorhq_guohongtao5_tmp <guohongtao5@huaqin.com>
Mon, 17 Sep 2018 11:27:02 +0000 (19:27 +0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:29:41 +0000 (17:29 +0800)
Change-Id: I2f3e428be04c83a81b0162f2581ee9297f28d224
Signed-off-by: Karl Sun <Karl.sun@cirrus.com>
12 files changed:
arch/arm64/boot/dts/exynos/exynos9609-wing.dts
drivers/mfd/madera-core.c [changed mode: 0644->0755]
include/linux/mfd/madera/core.h [changed mode: 0644->0755]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/aov_trigger.c [new file with mode: 0755]
sound/soc/codecs/aov_trigger.h [new file with mode: 0755]
sound/soc/codecs/cs47l35.c
sound/soc/codecs/madera-slimbus.c
sound/soc/codecs/madera-slimbus.h
sound/soc/codecs/madera.c [changed mode: 0644->0755]
sound/soc/codecs/madera.h [changed mode: 0644->0755]

index 4d051207a09589c1fd67c25993c9b91a1f61083d..e48331bf5986bd5305e05f71334a7821e90d90ec 100755 (executable)
                                        "ABOX SIFS0 Capture", "VINPUTCALL";
 
                                samsung,codec = <&abox &abox_uaif_0 &abox_uaif_1 &abox_uaif_2
-                                       &abox_uaif_4 &abox_dsif &abox_spdy>; /*&cs35l41_left*/
+                                       &abox_uaif_4 &abox_dsif &abox_spdy &cs35l41_left>;
                                samsung,prefix = "ABOX", "ABOX", "ABOX", "ABOX",
                                        "ABOX", "ABOX", "ABOX", "Left";
                                samsung,aux = <&abox_effect &abox_bt>;
                                        };
                                };
 
-#if 0          /*ToDo: enable speaker amp on EVB board*/
                                codec-left-amp@0 {
                                        format = "i2s";
 
                                                sound-dai = <&cs35l41_left 0>;
                                        };
                                };
-#endif
                        };
 
 
 };
 
 &spi_6 {
-       status = "disable";
+       status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&spi6_bus &spi6_cs_func>;
        /*cs-gpios = <&gpp2 3 0>;*/
old mode 100644 (file)
new mode 100755 (executable)
index 5e4a30d..e64c0e3
@@ -672,6 +672,8 @@ int madera_dev_init(struct madera *madera)
        if (ret)
                goto err_pinctrl;
 
+       mutex_init(&madera->reg_setting_lock);
+       
        BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier);
 
        if (dev_get_platdata(madera->dev)) {
old mode 100644 (file)
new mode 100755 (executable)
index 8673d73..090440f
@@ -168,6 +168,8 @@ struct madera {
 
        struct snd_soc_dapm_context *dapm;
 
+       struct mutex reg_setting_lock;
+
        struct blocking_notifier_head notifier;
 };
 
index 45b30d7f2897e224a1c8d701630446f61e174b8c..f0b09b2578625905ec5e1407a3d3d0e0968dd3b6 100755 (executable)
@@ -269,6 +269,16 @@ config SND_SOC_WM_ADSP
        default m if SND_SOC_WM5102=m
        default m if SND_SOC_WM5110=m
        default m if SND_SOC_WM2200=m
+config SND_SOC_AOV_TRIGGER
+       tristate "AOV Trigger"
+       default n
+        help
+          Always-On-Audio trigger driver is needed to expose
+          audio DSP voice trigger events to user space. An app should
+          register to receive a trigger and rearm it each time after
+          reading a voice data from DSP.
+
+          If unsure select "N".
 
 config SND_SOC_AB8500_CODEC
        tristate
index 820bfe2d8d5bc40e3ba15a0f9d7332dbb1142776..05b52f03efbbdd2e72b6520fb6e50968e9114e83 100755 (executable)
@@ -89,7 +89,7 @@ snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
 snd-soc-lm49453-objs := lm49453.o
 snd-soc-madera-objs := madera.o
-
+snd-soc-madera-slimbus-objs := madera-slimbus.o
 snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98090-objs := max98090.o
@@ -184,6 +184,7 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
+snd-soc-aov-trigger-objs := aov_trigger.o
 snd-soc-wm0010-objs := wm0010.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
@@ -240,6 +241,7 @@ snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-zx-aud96p22-objs := zx_aud96p22.o
+obj-$(CONFIG_SND_SOC_AOV_TRIGGER) += snd-soc-aov-trigger.o
 # Amp
 snd-soc-dio2125-objs := dio2125.o
 snd-soc-max9877-objs := max9877.o
diff --git a/sound/soc/codecs/aov_trigger.c b/sound/soc/codecs/aov_trigger.c
new file mode 100755 (executable)
index 0000000..469a354
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2014, Motorola Mobility, LLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/kobject.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <sound/soc.h>
+// #include <linux/wakelock.h>
+#include <linux/mfd/madera/core.h>
+#include "madera.h"
+
+#define MAX_DSP_TO_CHECK 4
+#define MAX_NUM_PANIC_CODE 4
+
+struct dsp_event_info {
+       int panic;
+       int event;
+       u16 panic_code[MAX_NUM_PANIC_CODE];
+};
+static bool aov_trigger_active;
+static struct kobject aov_trigger_kobj;
+static struct snd_soc_codec *aov_codec;
+static struct notifier_block aov_trigger_nb;
+static struct wakeup_source aov_wake_src;
+
+static struct dsp_event_info dsp_info[MAX_DSP_TO_CHECK];
+static DEFINE_MUTEX(dsp_info_mutex);
+
+static struct attribute aov_sysfs_attr_trigger = {
+       .name = "trigger",
+       .mode = S_IRUSR | S_IRGRP
+};
+
+static struct attribute aov_sysfs_attr_register = {
+       .name = "register",
+       .mode = S_IWUSR | S_IWGRP
+};
+
+static struct attribute aov_sysfs_attr_event = {
+       .name = "event",
+       .mode = S_IRUSR | S_IRGRP
+};
+
+static const char *reg_cmd = "register";
+static const char *unreg_cmd = "unregister";
+
+static int aov_trigger_notify(struct notifier_block *nb,
+                                  unsigned long event, void *data)
+{
+       struct madera_voice_trigger_info *trig_info = data;
+       int dsp;
+
+       if (aov_codec == NULL)
+               return -EPERM;
+       /*
+        * Once a trigger is received, unregister from
+        * trigger notification. Client needs to re-arm
+        * the rigger.
+        */
+
+       dev_dbg(aov_codec->dev, "received madera notity event: 0x%lx", event);
+       if ((event == MADERA_NOTIFY_VOICE_TRIGGER) &&
+           (trig_info->core_num >= 0) &&
+           (trig_info->core_num < MAX_DSP_TO_CHECK)) {
+
+               dsp = trig_info->core_num;
+
+               switch (trig_info->code) {
+               case MADERA_TRIGGER_VOICE:
+                       if (!aov_trigger_active)
+                               return 0;
+                       aov_trigger_active = false;
+                       dev_info(aov_codec->dev,
+                               "DSP%d: notify aov trigger.", dsp);
+                       sysfs_notify(&aov_trigger_kobj, NULL,
+                                    aov_sysfs_attr_trigger.name);
+                       __pm_wakeup_event(&aov_wake_src, 500);
+                       break;
+               case MADERA_TRIGGER_TEXT:
+                       mutex_lock(&dsp_info_mutex);
+                       dsp_info[dsp].event = 1;
+                       mutex_unlock(&dsp_info_mutex);
+                       dev_info(aov_codec->dev,
+                               "DSP%d: aov notify text event.", dsp);
+                       sysfs_notify(&aov_trigger_kobj, NULL,
+                                    aov_sysfs_attr_event.name);
+                       break;
+               case MADERA_TRIGGER_PANIC:
+                       mutex_lock(&dsp_info_mutex);
+                       dsp_info[dsp].panic = 1;
+                       memcpy(dsp_info[dsp].panic_code, trig_info->err_msg,
+                              sizeof(u16) * MAX_NUM_PANIC_CODE);
+                       mutex_unlock(&dsp_info_mutex);
+                       dev_info(aov_codec->dev,
+                               "DSP%d: aov notify panic.", dsp);
+                       sysfs_notify(&aov_trigger_kobj, NULL,
+                                    aov_sysfs_attr_event.name);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void aov_register_trigger(void)
+{
+       if (aov_codec == NULL)
+               return;
+       aov_trigger_active = true;
+       dev_dbg(aov_codec->dev, "registered aov trigger.");
+}
+
+static void aov_unregister_trigger(void)
+{
+       if (aov_codec == NULL)
+               return;
+       aov_trigger_active = false;
+       dev_dbg(aov_codec->dev, "unregistered aov trigger.");
+}
+
+static void aov_sysfs_release(struct kobject *kobj)
+{
+       aov_codec = NULL;
+}
+
+static ssize_t aov_sysfs_show(struct kobject *kobj,
+                                 struct attribute *attr, char *buf)
+{
+       int i, j;
+       int count;
+       char *ptr = buf;
+
+       if (attr != &aov_sysfs_attr_event)
+               return 0;
+
+       mutex_lock(&dsp_info_mutex);
+       for (i = 0; i < MAX_DSP_TO_CHECK; i++) {
+               count = scnprintf(ptr, PAGE_SIZE - (ptr - buf),
+                                 "dsp %d: panic:%d event:%d code:",
+                                 i, dsp_info[i].panic, dsp_info[i].event);
+               ptr += count;
+               for (j = 0; j < MAX_NUM_PANIC_CODE; j++) {
+                       count = scnprintf(ptr, PAGE_SIZE - (ptr - buf),
+                                         "%04x", dsp_info[i].panic_code[j]);
+                       ptr += count;
+               }
+               count = scnprintf(ptr, PAGE_SIZE - (ptr - buf), "\n");
+               ptr += count;
+       }
+       memset(dsp_info, 0, sizeof(struct dsp_event_info) * MAX_DSP_TO_CHECK);
+       mutex_unlock(&dsp_info_mutex);
+
+       return ptr - buf;
+}
+
+static ssize_t aov_sysfs_store(struct kobject *kobj,
+                                  struct attribute *attr,
+                                  const char *buf, size_t count)
+{
+       ssize_t ret = -EIO;
+
+       if (attr != &aov_sysfs_attr_register)
+               return ret;
+
+       if (!strncmp(reg_cmd, buf, strlen(reg_cmd))) {
+               aov_register_trigger();
+               ret = count;
+       } else if (!strncmp(unreg_cmd, buf, strlen(unreg_cmd))) {
+               aov_unregister_trigger();
+               ret = count;
+       }
+       return ret;
+}
+
+static const struct sysfs_ops aov_sysfs_ops = {
+       .show = aov_sysfs_show,
+       .store = aov_sysfs_store,
+};
+
+static struct kobj_type ktype_aov_trigger = {
+       .sysfs_ops = &aov_sysfs_ops,
+       .default_attrs = NULL,
+       .release = aov_sysfs_release,
+};
+
+void aov_trigger_register_notifier(struct snd_soc_codec *codec)
+{
+       if (!aov_codec) {
+               aov_trigger_nb.notifier_call = aov_trigger_notify;
+               aov_codec = codec;
+               madera_register_notifier(aov_codec, &aov_trigger_nb);
+       }
+}
+EXPORT_SYMBOL_GPL(aov_trigger_register_notifier);
+
+static int aov_trigger_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       static int aov_trigger_init_called;
+
+       if (aov_trigger_init_called)
+               return ret;
+       aov_trigger_init_called = 1;
+
+       ret = kobject_init_and_add(&aov_trigger_kobj,
+                                  &ktype_aov_trigger,
+                                  kernel_kobj, "aov");
+       if (ret)
+               goto exit;
+
+       sysfs_attr_init(&aov_sysfs_attr_trigger);
+       ret = sysfs_create_file(&aov_trigger_kobj,
+                               &aov_sysfs_attr_trigger);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "%s: trigger node creation failed, ret=%d\n",
+                       __func__, ret);
+               goto exit_remove_kobj;
+       }
+
+       sysfs_attr_init(&aov_sysfs_attr_register);
+       ret = sysfs_create_file(&aov_trigger_kobj,
+                               &aov_sysfs_attr_register);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "%s: register node creation failed, ret=%d\n",
+                       __func__, ret);
+               goto exit_remove_trigger;
+       }
+
+       sysfs_attr_init(&aov_sysfs_attr_event);
+       ret = sysfs_create_file(&aov_trigger_kobj,
+                               &aov_sysfs_attr_event);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "%s: event node creation failed, ret=%d\n",
+                       __func__, ret);
+               goto exit_remove_register;
+       }
+
+       wakeup_source_init(&aov_wake_src, "aov_wakelock");
+
+       goto exit;
+
+exit_remove_register:
+       sysfs_remove_file(&aov_trigger_kobj,
+                       &aov_sysfs_attr_register);
+exit_remove_trigger:
+       sysfs_remove_file(&aov_trigger_kobj,
+                       &aov_sysfs_attr_trigger);
+exit_remove_kobj:
+       kobject_put(&aov_trigger_kobj);
+exit:
+       return ret;
+}
+
+static int aov_trigger_remove(struct platform_device *pdev)
+{
+       sysfs_remove_file(&aov_trigger_kobj, &aov_sysfs_attr_event);
+       sysfs_remove_file(&aov_trigger_kobj, &aov_sysfs_attr_register);
+       sysfs_remove_file(&aov_trigger_kobj, &aov_sysfs_attr_trigger);
+       wakeup_source_trash(&aov_wake_src);
+       kobject_del(&aov_trigger_kobj);
+       return 0;
+}
+
+static struct of_device_id aov_trigger_match_table[] = {
+       {       .compatible = "mmi,aov-trigger",
+       },
+       {}
+};
+
+static struct platform_driver aov_trigger_driver = {
+       .probe          = aov_trigger_probe,
+       .remove         = aov_trigger_remove,
+       .driver         = {
+               .name   = "aov-trigger",
+               .of_match_table = of_match_ptr(aov_trigger_match_table),
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init aov_trigger_init(void)
+{
+       return platform_driver_register(&aov_trigger_driver);
+}
+
+static void __exit aov_trigger_exit(void)
+{
+       platform_driver_unregister(&aov_trigger_driver);
+}
+
+module_init(aov_trigger_init);
+module_exit(aov_trigger_exit);
+
+MODULE_DESCRIPTION("Motorola AOV trigger driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/aov_trigger.h b/sound/soc/codecs/aov_trigger.h
new file mode 100755 (executable)
index 0000000..5ee0212
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014, Motorola Mobility, LLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __AOV_TRIGGER_H
+#define __AOV_TRIGGER_H
+
+struct snd_soc_codec;
+
+void aov_trigger_register_notifier(struct snd_soc_codec *codec);
+#endif /* __AOV_TRIGGER_H */
index 29b040a7783b9084e968d6be360039a0d3d84e54..5046835159cd1a847861dab1102d5f195ee68d29 100755 (executable)
 #include "madera.h"
 #include "wm_adsp.h"
 
+#if IS_ENABLED(CONFIG_SND_SOC_AOV_TRIGGER)
+#include "aov_trigger.h"
+#endif
 #define CS47L35_NUM_ADSP       3
 #define CS47L35_MONO_OUTPUTS   1
 
+#define ADSP2_CONTROL  0x0
+#define ADSP2_CORE_ENA 0x0002
+
 struct cs47l35 {
        struct madera_priv core;
        struct madera_fll fll;
 };
 
+static const int cs47l35_fx_inputs[] = {
+       MADERA_MIXER_INPUTS_4_N(MADERA_EQ1MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_EQ2MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_EQ3MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_EQ4MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_DRC1LMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_DRC1RMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_DRC2LMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_DRC2RMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_HPLP1MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_HPLP2MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_HPLP3MIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_HPLP4MIX_INPUT_1_SOURCE, 2),
+};
+
+static const int cs47l35_isrc1_fsl_inputs[] = {
+       MADERA_MIXER_INPUTS_4_N(MADERA_ISRC1INT1MIX_INPUT_1_SOURCE, 8),
+};
+
+static const int cs47l35_isrc1_fsh_inputs[] = {
+       MADERA_MIXER_INPUTS_4_N(MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE, 8),
+};
+
+static const int cs47l35_isrc2_fsl_inputs[] = {
+       MADERA_MIXER_INPUTS_4_N(MADERA_ISRC2INT1MIX_INPUT_1_SOURCE, 8),
+};
+
+static const int cs47l35_isrc2_fsh_inputs[] = {
+       MADERA_MIXER_INPUTS_4_N(MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE, 8),
+};
+
+static const int cs47l35_out_inputs[] = {
+       MADERA_MIXER_INPUTS_4_N(MADERA_OUT1LMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_OUT1RMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_OUT4LMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_OUT5LMIX_INPUT_1_SOURCE, 2),
+       MADERA_MIXER_INPUTS_4_N(MADERA_OUT5RMIX_INPUT_1_SOURCE, 2),
+};
+
+static const int cs47l35_spd1_inputs[] = {
+       MADERA_MIXER_INPUTS_2_N(MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE, 8),
+};
+
+static const int cs47l35_dsp1_inputs[] = {
+       MADERA_DSP_MIXER_INPUTS(MADERA_DSP1LMIX_INPUT_1_SOURCE),
+};
+
+static const int cs47l35_dsp2_inputs[] = {
+       MADERA_DSP_MIXER_INPUTS(MADERA_DSP2LMIX_INPUT_1_SOURCE),
+};
+
+static const int cs47l35_dsp3_inputs[] = {
+       MADERA_DSP_MIXER_INPUTS(MADERA_DSP3LMIX_INPUT_1_SOURCE),
+};
+
+
 static const struct wm_adsp_region cs47l35_dsp1_regions[] = {
        { .type = WMFW_ADSP2_PM, .base = 0x080000 },
        { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 },
@@ -81,6 +143,58 @@ static SOC_ENUM_SINGLE_DECL(cs47l35_outdemux_enum, SND_SOC_NOPM, 0,
 static const struct snd_kcontrol_new cs47l35_outdemux =
        SOC_DAPM_ENUM_EXT("HPOUT1 Demux", cs47l35_outdemux_enum,
                          snd_soc_dapm_get_enum_double, madera_out1_demux_put);
+static int cs47l35_get_sources(unsigned int reg,
+                              const unsigned int **cur_sources, int *lim)
+{
+       int ret = 0;
+
+       switch (reg) {
+       case MADERA_FX_CTRL1:
+               *cur_sources = cs47l35_fx_inputs;
+               *lim = ARRAY_SIZE(cs47l35_fx_inputs);
+               break;
+       case MADERA_ISRC_1_CTRL_1:
+               *cur_sources = cs47l35_isrc1_fsh_inputs;
+               *lim = ARRAY_SIZE(cs47l35_isrc1_fsh_inputs);
+               break;
+       case MADERA_ISRC_1_CTRL_2:
+               *cur_sources = cs47l35_isrc1_fsl_inputs;
+               *lim = ARRAY_SIZE(cs47l35_isrc1_fsl_inputs);
+               break;
+       case MADERA_ISRC_2_CTRL_1:
+               *cur_sources = cs47l35_isrc2_fsh_inputs;
+               *lim = ARRAY_SIZE(cs47l35_isrc2_fsh_inputs);
+               break;
+       case MADERA_ISRC_2_CTRL_2:
+               *cur_sources = cs47l35_isrc2_fsl_inputs;
+               *lim = ARRAY_SIZE(cs47l35_isrc2_fsl_inputs);
+               break;
+       case MADERA_OUTPUT_RATE_1:
+               *cur_sources = cs47l35_out_inputs;
+               *lim = ARRAY_SIZE(cs47l35_out_inputs);
+               break;
+       case MADERA_SPD1_TX_CONTROL:
+               *cur_sources = cs47l35_spd1_inputs;
+               *lim = ARRAY_SIZE(cs47l35_spd1_inputs);
+               break;
+       case MADERA_DSP1_CONFIG_1:
+               *cur_sources = cs47l35_dsp1_inputs;
+               *lim = ARRAY_SIZE(cs47l35_dsp1_inputs);
+               break;
+       case MADERA_DSP2_CONFIG_1:
+               *cur_sources = cs47l35_dsp2_inputs;
+               *lim = ARRAY_SIZE(cs47l35_dsp2_inputs);
+               break;
+       case MADERA_DSP3_CONFIG_1:
+               *cur_sources = cs47l35_dsp3_inputs;
+               *lim = ARRAY_SIZE(cs47l35_dsp3_inputs);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
 
 static int cs47l35_adsp_power_ev(struct snd_soc_dapm_widget *w,
                                 struct snd_kcontrol *kcontrol,
@@ -116,6 +230,58 @@ static int cs47l35_adsp_power_ev(struct snd_soc_dapm_widget *w,
        return wm_adsp2_early_event(w, kcontrol, event, freq);
 }
 
+static int cs47l35_get_dsp_state(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)
+               kcontrol->private_value;
+       struct wm_adsp *dsp = &dsps[mc->shift];
+       unsigned int val;
+
+       regmap_read(dsp->regmap, dsp->base + ADSP2_CONTROL, &val);
+       if (val & ADSP2_CORE_ENA)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int cs47l35_put_dsp_state(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return 0;
+}
+
+static int cs47l35_get_trig_state(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct cs47l35 *cs47l35 = snd_soc_codec_get_drvdata(codec);
+       struct madera_priv *priv = &cs47l35->core;
+       /* DSP3, Channel 1 */
+       struct wm_adsp_compr *compr = priv->adsp[2].compr[0];
+       if (compr)
+               ucontrol->value.integer.value[0] = compr->freed;
+       return 0;
+}
+
+static int cs47l35_put_trig_state(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct cs47l35 *cs47l35 = snd_soc_codec_get_drvdata(codec);
+       struct madera_priv *priv = &cs47l35->core;
+       /* DSP3, Channel 1 */
+       struct wm_adsp_compr *compr = priv->adsp[2].compr[0];
+       int value = ucontrol->value.integer.value[0];
+
+       if (compr)
+               compr->freed = value;
+       return 0;
+}
 #define CS47L35_NG_SRC(name, base) \
        SOC_SINGLE(name " NG HPOUT1L Switch",  base,  0, 1, 0), \
        SOC_SINGLE(name " NG HPOUT1R Switch",  base,  1, 1, 0), \
@@ -225,6 +391,16 @@ SOC_SINGLE("IN2L HPF Switch", MADERA_IN2L_CONTROL,
 SOC_SINGLE("IN2R HPF Switch", MADERA_IN2R_CONTROL,
           MADERA_IN2R_HPF_SHIFT, 1, 0),
 
+SOC_SINGLE_EXT("Set Trigger State Switch", SND_SOC_NOPM, 0, 1, 0,
+              cs47l35_get_trig_state,
+              cs47l35_put_trig_state),
+SOC_SINGLE_EXT("Get DSP1 State", SND_SOC_NOPM, 0, 1, 0, cs47l35_get_dsp_state,
+              cs47l35_put_dsp_state),
+SOC_SINGLE_EXT("Get DSP2 State", SND_SOC_NOPM, 1, 1, 0, cs47l35_get_dsp_state,
+              cs47l35_put_dsp_state),
+SOC_SINGLE_EXT("Get DSP3 State", SND_SOC_NOPM, 2, 1, 0, cs47l35_get_dsp_state,
+              cs47l35_put_dsp_state),
+
 SOC_SINGLE_TLV("IN1L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1L,
               MADERA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv),
 SOC_SINGLE_TLV("IN1R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1R,
@@ -237,6 +413,20 @@ SOC_SINGLE_TLV("IN2R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2R,
 SOC_ENUM("Input Ramp Up", madera_in_vi_ramp),
 SOC_ENUM("Input Ramp Down", madera_in_vd_ramp),
 
+MADERA_FRF_BYTES("FRF COEFF 1L", MADERA_FRF_COEFFICIENT_1L_1,
+                                MADERA_FRF_COEFFICIENT_LEN),
+MADERA_FRF_BYTES("FRF COEFF 1R", MADERA_FRF_COEFFICIENT_1R_1,
+                                MADERA_FRF_COEFFICIENT_LEN),
+MADERA_FRF_BYTES("FRF COEFF 4L", CS47L35_FRF_COEFFICIENT_4L_1,
+                                MADERA_FRF_COEFFICIENT_LEN),
+MADERA_FRF_BYTES("FRF COEFF 5L", CS47L35_FRF_COEFFICIENT_5L_1,
+                                MADERA_FRF_COEFFICIENT_LEN),
+MADERA_FRF_BYTES("FRF COEFF 5R", CS47L35_FRF_COEFFICIENT_5R_1,
+                                MADERA_FRF_COEFFICIENT_LEN),
+
+SND_SOC_BYTES("DAC COMP 1", MADERA_DAC_COMP_1, 1),
+SND_SOC_BYTES("DAC COMP 2", MADERA_DAC_COMP_2, 1),
+
 MADERA_MIXER_CONTROLS("EQ1", MADERA_EQ1MIX_INPUT_1_SOURCE),
 MADERA_MIXER_CONTROLS("EQ2", MADERA_EQ2MIX_INPUT_1_SOURCE),
 MADERA_MIXER_CONTROLS("EQ3", MADERA_EQ3MIX_INPUT_1_SOURCE),
@@ -375,6 +565,10 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_5L,
 SOC_DOUBLE("SPKDAT1 Switch", MADERA_PDM_SPK1_CTRL_1, MADERA_SPK1L_MUTE_SHIFT,
           MADERA_SPK1R_MUTE_SHIFT, 1, 1),
 
+SOC_DOUBLE_EXT("HPOUT1 DRE Switch", MADERA_DRE_ENABLE,
+          MADERA_DRE1L_ENA_SHIFT, MADERA_DRE1R_ENA_SHIFT, 1, 0,
+          snd_soc_get_volsw, madera_dre_put),
+
 SOC_DOUBLE("HPOUT1 EDRE Switch", MADERA_EDRE_ENABLE,
           MADERA_EDRE_OUT1L_THR1_ENA_SHIFT,
           MADERA_EDRE_OUT1R_THR1_ENA_SHIFT, 1, 0),
@@ -505,6 +699,20 @@ MADERA_MUX_ENUMS(ISRC2DEC2, MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE);
 MADERA_MUX_ENUMS(ISRC2DEC3, MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE);
 MADERA_MUX_ENUMS(ISRC2DEC4, MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE);
 
+static const char * const cs47l35_memory_mux_texts[] = {
+       "None",
+       "Shared Memory",
+};
+
+static const struct soc_enum cs47l35_memory_enum =
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(cs47l35_memory_mux_texts),
+                       cs47l35_memory_mux_texts);
+
+static const struct snd_kcontrol_new cs47l35_memory_mux[] = {
+       SOC_DAPM_ENUM("DSP2 Virtual Input", cs47l35_memory_enum),
+       SOC_DAPM_ENUM("DSP3 Virtual Input", cs47l35_memory_enum),
+};
+
 static const char * const cs47l35_aec_loopback_texts[] = {
        "HPOUT1L", "HPOUT1R", "SPKOUT", "SPKDAT1L", "SPKDAT1R",
 };
@@ -622,6 +830,8 @@ SND_SOC_DAPM_SUPPLY("PWMCLK", SND_SOC_NOPM,
                    madera_domain_clk_ev,
                    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
+SND_SOC_DAPM_SUPPLY("GPSW", MADERA_GP_SWITCH_1,
+               0, 0, NULL, 0),
 SND_SOC_DAPM_SIGGEN("TONE"),
 SND_SOC_DAPM_SIGGEN("NOISE"),
 
@@ -631,11 +841,18 @@ SND_SOC_DAPM_INPUT("IN1BL"),
 SND_SOC_DAPM_INPUT("IN1BR"),
 SND_SOC_DAPM_INPUT("IN2L"),
 SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("DSP Virtual Input"),
 
 SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
 SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
 
-SND_SOC_DAPM_OUTPUT("DSP Trigger Out"),
+SND_SOC_DAPM_OUTPUT("DSP1 Trigger Out"),
+SND_SOC_DAPM_OUTPUT("DSP2 Trigger Out"),
+SND_SOC_DAPM_OUTPUT("DSP3 Trigger Out"),
+
+SND_SOC_DAPM_OUTPUT("DSP1 Virtual Output"),
+SND_SOC_DAPM_OUTPUT("DSP2 Virtual Output"),
+SND_SOC_DAPM_OUTPUT("DSP3 Virtual Output"),
 
 SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[0]),
 SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[1]),
@@ -916,6 +1133,11 @@ MADERA_DSP_WIDGETS(DSP1, "DSP1"),
 MADERA_DSP_WIDGETS(DSP2, "DSP2"),
 MADERA_DSP_WIDGETS(DSP3, "DSP3"),
 
+SND_SOC_DAPM_MUX("DSP2 Virtual Input", SND_SOC_NOPM, 0, 0,
+                     &cs47l35_memory_mux[0]),
+SND_SOC_DAPM_MUX("DSP3 Virtual Input", SND_SOC_NOPM, 0, 0,
+                     &cs47l35_memory_mux[1]),
+
 SND_SOC_DAPM_SWITCH("DSP1 Trigger Output", SND_SOC_NOPM, 0, 0,
                    &madera_dsp_trigger_output_mux[0]),
 SND_SOC_DAPM_SWITCH("DSP2 Trigger Output", SND_SOC_NOPM, 0, 0,
@@ -1119,6 +1341,10 @@ static const struct snd_soc_dapm_route cs47l35_dapm_routes[] = {
        { "IN2L", NULL, "SYSCLK" },
        { "IN2R", NULL, "SYSCLK" },
 
+       { "DSP1", NULL, "DSPCLK"},
+       { "DSP2", NULL, "DSPCLK"},
+       { "DSP3", NULL, "DSPCLK"},
+
        { "MICBIAS1", NULL, "MICVDD" },
        { "MICBIAS2", NULL, "MICVDD" },
 
@@ -1189,9 +1415,13 @@ static const struct snd_soc_dapm_route cs47l35_dapm_routes[] = {
        { "Slim1 Capture", NULL, "SYSCLK" },
        { "Slim2 Capture", NULL, "SYSCLK" },
 
+       { "Voice Control CPU", NULL, "Voice Control DSP" },
        { "Voice Control DSP", NULL, "DSP3" },
+       { "Voice Control CPU", NULL, "SYSCLK" },
+       { "Voice Control DSP", NULL, "SYSCLK" },
 
        { "Audio Trace DSP", NULL, "DSP1" },
+       { "Audio Trace DSP", NULL, "SYSCLK" },
 
        { "IN1L Mux", "A", "IN1AL" },
        { "IN1L Mux", "B", "IN1BL" },
@@ -1257,14 +1487,36 @@ static const struct snd_soc_dapm_route cs47l35_dapm_routes[] = {
        MADERA_DSP_ROUTES("DSP2"),
        MADERA_DSP_ROUTES("DSP3"),
 
-       { "DSP Trigger Out", NULL, "DSP1 Trigger Output" },
-       { "DSP Trigger Out", NULL, "DSP2 Trigger Output" },
-       { "DSP Trigger Out", NULL, "DSP3 Trigger Output" },
+       { "DSP2 Preloader", NULL, "DSP2 Virtual Input" },
+       { "DSP2 Virtual Input", "Shared Memory", "DSP3" },
+       { "DSP3 Preloader", NULL, "DSP3 Virtual Input" },
+       { "DSP3 Virtual Input", "Shared Memory", "DSP2" },
+
+       { "DSP1 Trigger Out", NULL, "SYSCLK" },
+       { "DSP1 Trigger Out", NULL, "DSP1 Trigger Output" },
+       { "DSP2 Trigger Out", NULL, "DSP2 Trigger Output" },
+       { "DSP3 Trigger Out", NULL, "DSP3 Trigger Output" },
 
        { "DSP1 Trigger Output", "Switch", "DSP1" },
        { "DSP2 Trigger Output", "Switch", "DSP2" },
        { "DSP3 Trigger Output", "Switch", "DSP3" },
 
+       { "DSP1 Preloader", NULL, "DSP Virtual Input" },
+       { "DSP1 Trigger Out", NULL, "DSP1 Virtual Output" },
+       { "DSP1 Virtual Output", NULL, "SYSCLK" },
+
+       { "DSP2 Preloader", NULL, "DSP Virtual Input" },
+       { "DSP2 Trigger Out", NULL, "DSP2 Virtual Output" },
+       { "DSP2 Virtual Output", NULL, "SYSCLK" },
+
+       { "DSP3 Preloader", NULL, "DSP Virtual Input" },
+       { "DSP3 Trigger Out", NULL, "DSP3 Virtual Output" },
+       { "DSP3 Virtual Output", NULL, "SYSCLK" },
+
+       {"LHPF1 Input 1", NULL, "DSP Virtual Input"},
+       {"LHPF2 Input 1", NULL, "DSP Virtual Input"},
+       {"LHPF3 Input 1", NULL, "DSP Virtual Input"},
+
        MADERA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
        MADERA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
        MADERA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
@@ -1485,6 +1737,69 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
                        .formats = MADERA_FORMATS,
                },
        },
+       {
+               .name = "cs47l35-dsp1-cpu-txt",
+               .capture = {
+                       .stream_name = "Text DSP1 CPU",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MADERA_RATES,
+                       .formats = MADERA_FORMATS,
+               },
+               .compress_new = snd_soc_new_compress,
+       },
+       {
+               .name = "cs47l35-dsp1-txt",
+               .capture = {
+                       .stream_name = "Text DSP1",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MADERA_RATES,
+                       .formats = MADERA_FORMATS,
+               },
+       },
+       {
+               .name = "cs47l35-dsp2-cpu-txt",
+               .capture = {
+                       .stream_name = "Text DSP2 CPU",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MADERA_RATES,
+                       .formats = MADERA_FORMATS,
+               },
+               .compress_new = snd_soc_new_compress,
+       },
+       {
+               .name = "cs47l35-dsp2-txt",
+               .capture = {
+                       .stream_name = "Text DSP2",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MADERA_RATES,
+                       .formats = MADERA_FORMATS,
+               },
+       },
+       {
+               .name = "cs47l35-dsp3-cpu-txt",
+               .capture = {
+                       .stream_name = "Text DSP3 CPU",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MADERA_RATES,
+                       .formats = MADERA_FORMATS,
+               },
+               .compress_new = snd_soc_new_compress,
+       },
+       {
+               .name = "cs47l35-dsp3-txt",
+               .capture = {
+                       .stream_name = "Text DSP3",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MADERA_RATES,
+                       .formats = MADERA_FORMATS,
+               },
+       },
 };
 
 static int cs47l35_open(struct snd_compr_stream *stream)
@@ -1495,15 +1810,30 @@ static int cs47l35_open(struct snd_compr_stream *stream)
        struct madera *madera = priv->madera;
        int n_adsp, channel;
 
-       channel = 0;
        dev_dbg(madera->dev,
                        "Open compr stream '%s' for DAI %d '%s'\n",
                        stream->name, rtd->codec_dai->id, rtd->codec_dai->name);
 
        if (strcmp(rtd->codec_dai->name, "cs47l35-dsp-voicectrl") == 0) {
+       /* DSP 3 channel 1 */
                n_adsp = 2;
+               channel = 0;
        } else if (strcmp(rtd->codec_dai->name, "cs47l35-dsp-trace") == 0) {
+       /* DSP 1 channel 1 */
                n_adsp = 0;
+               channel = 0;
+       } else if (strcmp(rtd->codec_dai->name, "cs47l35-dsp1-txt") == 0) {
+       /* DSP 1 channel 2 */
+               n_adsp = 0;
+               channel = 1;
+       } else if (strcmp(rtd->codec_dai->name, "cs47l35-dsp3-txt") == 0) {
+       /* DSP 3 channel 2 */
+               n_adsp = 2;
+               channel = 1;
+       } else if (strcmp(rtd->codec_dai->name, "cs47l35-dsp2-txt") == 0) {
+       /* DSP 2 channel 1 */
+               n_adsp = 1;
+               channel = 0;
        } else {
                dev_err(madera->dev,
                        "No suitable compressed stream for DAI '%s'\n",
@@ -1514,25 +1844,101 @@ static int cs47l35_open(struct snd_compr_stream *stream)
        return wm_adsp_compr_open(&priv->adsp[n_adsp], stream, channel);
 }
 
+static int cs47l35_panic_check(struct cs47l35 *cs47l35, int dev, int *reg)
+{
+       struct madera_priv *priv = &cs47l35->core;
+       struct madera *madera = priv->madera;
+       unsigned int val, scratch1;
+       struct madera_voice_trigger_info trig_info;
+
+       *reg = MADERA_DSP1_SCRATCH_1 + (0x80000 * dev);
+       regmap_read(madera->regmap_32bit, *reg, &val);
+
+       val = val >> 16;
+       if ((val & 0x3fff) == 0)
+               return val;
+
+       dev_err(madera->dev, "DSP%d Panic %x\n", dev, val);
+
+       scratch1 = val;
+       memset(trig_info.err_msg, 0, sizeof(trig_info.err_msg));
+
+       regmap_read(madera->regmap_32bit, *reg, &val);
+       trig_info.err_msg[1] = (u16)val;
+       trig_info.err_msg[0] = (u16)(val >> 16);
+
+       regmap_read(madera->regmap_32bit, *reg+2, &val);
+       trig_info.err_msg[2] = (u16)val;
+       trig_info.err_msg[3] = (u16)(val >> 16);
+
+
+       /* Panic callback */
+       trig_info.core_num = dev;
+       trig_info.code = MADERA_TRIGGER_PANIC;
+       madera_call_notifiers(madera,
+                             MADERA_NOTIFY_VOICE_TRIGGER,
+                             &trig_info);
+
+       /* Clean panic field */
+       scratch1 &= 0xc000;
+       regmap_write(madera->regmap_32bit, *reg, (scratch1<<16));
+
+       return scratch1;
+}
+
+static int cs47l35_text_event(struct cs47l35 *cs47l35, int dev)
+{
+       struct madera_priv *priv = &cs47l35->core;
+       struct madera *madera = priv->madera;
+
+       dev_dbg(madera->dev, "DSP%d Text event\n", dev);
+       return 0;
+}
+
 static irqreturn_t cs47l35_adsp2_irq(int irq, void *data)
 {
        struct cs47l35 *cs47l35 = data;
        struct madera_priv *priv = &cs47l35->core;
        struct madera *madera = priv->madera;
        struct madera_voice_trigger_info trig_info;
+       int i, scratch_reg, reg, ret;
        int serviced = 0, channel = 0;
-       int i, ret;
 
-       for (i = 0; i < CS47L35_NUM_ADSP; ++i) {
-               ret = wm_adsp_compr_handle_irq(&priv->adsp[i], channel);
-               if (ret != -ENODEV)
-                       serviced++;
-               if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
-                       trig_info.core_num = i + 1;
+       for (i = 0; i < CS47L35_NUM_ADSP; i++) {
+
+               scratch_reg = cs47l35_panic_check(cs47l35, i, &reg);
+               dev_dbg(madera->dev, "dsp %d, scratch_reg %x\n", i, scratch_reg);
+               if ((scratch_reg & 0x3fff) == 0) {
+                       if (scratch_reg & 0x4000) {
+                               /* Clear code bit */
+                               scratch_reg &= 0xbfff;
+                               scratch_reg = scratch_reg << 16;
+                               regmap_write(madera->regmap_32bit, reg,
+                                       scratch_reg);
+                       trig_info.core_num = i;
+                       trig_info.code = MADERA_TRIGGER_VOICE;
                        madera_call_notifiers(madera,
                                              MADERA_NOTIFY_VOICE_TRIGGER,
                                              &trig_info);
+                       channel = 0;
+                       dev_dbg(madera->dev, "Call AOV voice trigger notifier\n");
+                       }
+
+                       /* Text interrupt */
+                       if (scratch_reg & 0x8000) {
+                               /* Clear event bit */
+                               scratch_reg &= 0x7fff;
+                               scratch_reg = scratch_reg << 16;
+                               regmap_write(madera->regmap_32bit, reg,
+                                       scratch_reg);
+                               dev_dbg(madera->dev, "Calling Text Callback\n");
+                               cs47l35_text_event(cs47l35, i);
+                               channel = 1;
+                       }
                }
+               ret = wm_adsp_compr_handle_irq(&priv->adsp[i], channel);
+               if (ret != -ENODEV)
+                       serviced++;
        }
 
        if (!serviced) {
@@ -1584,15 +1990,20 @@ static int cs47l35_codec_probe(struct snd_soc_codec *codec)
        if (ret)
                return ret;
 
+
+
        for (i = 0; i < CS47L35_NUM_ADSP; i++)
                wm_adsp2_codec_probe(&cs47l35->core.adsp[i], codec);
-
+#if IS_ENABLED(CONFIG_SND_SOC_AOV_TRIGGER)
+       aov_trigger_register_notifier(codec);
+#endif
        return 0;
 }
 
 static int cs47l35_codec_remove(struct snd_soc_codec *codec)
 {
        struct cs47l35 *cs47l35 = snd_soc_codec_get_drvdata(codec);
+
        int i;
 
        for (i = 0; i < CS47L35_NUM_ADSP; i++)
@@ -1662,6 +2073,10 @@ static int cs47l35_probe(struct platform_device *pdev)
 
        BUILD_BUG_ON(ARRAY_SIZE(cs47l35_dai) > MADERA_MAX_DAI);
 
+       /* FX Rate has the largest number of sources */
+       BUILD_BUG_ON(ARRAY_SIZE(cs47l35->core.mixer_sources_cache) <
+                    ARRAY_SIZE(cs47l35_fx_inputs));
+
        /* quick exit if Madera irqchip driver hasn't completed probe */
        if (!madera->irq_dev) {
                dev_dbg(&pdev->dev, "irqchip driver not ready\n");
@@ -1681,6 +2096,7 @@ static int cs47l35_probe(struct platform_device *pdev)
        cs47l35->core.madera = madera;
        cs47l35->core.dev = &pdev->dev;
        cs47l35->core.num_inputs = 4;
+       cs47l35->core.get_sources = cs47l35_get_sources;
 
        ret = madera_core_init(&cs47l35->core);
        if (ret)
index 15cc39b78bf22d64d4a18788fffd76b017e4564d..737b1aec6e219b811b34cf063223dacd84ec2ac2 100755 (executable)
@@ -315,6 +315,15 @@ int madera_set_channel_map(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       /*
+        * same reason with stashed_slim_dev, there is no clever way to link
+        * codec and slimbus driver on madera based platform. whenever codec
+        * calls slimbus driver, it will keep its client codec pointer and use
+        * it as a bridge to call codec related functions.
+        */
+       if (dai->codec != NULL)
+               slim_set_clientdata(stashed_slim_dev, dai->codec);
+
        if (!priv->slim_logic_addr) {
                madera_slim_get_la(stashed_slim_dev, &laddr);
                priv->slim_logic_addr = laddr;
@@ -468,6 +477,38 @@ static int madera_slim_audio_probe(struct slim_device *slim)
        return 0;
 }
 
+static int madera_slim_device_reset(struct slim_device *slim)
+{
+       struct snd_soc_codec *codec;
+
+       if (slim == NULL)
+               return -EINVAL;
+
+       codec = slim_get_devicedata(slim);
+       if (codec != NULL) {
+               dev_info(&slim->dev, "%s handle SLIM RESET\n", __func__);
+               snd_soc_card_change_online_state(codec->component.card, 1);
+       }
+
+       return 0;
+}
+
+static int madera_slim_device_down(struct slim_device *slim)
+{
+       struct snd_soc_codec *codec;
+
+       if (slim == NULL)
+               return -EINVAL;
+
+       codec = slim_get_devicedata(slim);
+       if (codec != NULL) {
+               dev_info(&slim->dev, "%s handle SLIM DOWN\n", __func__);
+               snd_soc_card_change_online_state(codec->component.card, 0);
+       }
+
+       return 0;
+}
+
 static struct slim_driver madera_slim_audio = {
        .driver = {
                .name = "madera-slim-audio",
@@ -475,6 +516,8 @@ static struct slim_driver madera_slim_audio = {
        },
        .probe = madera_slim_audio_probe,
        .id_table = madera_slim_id,
+       .reset_device = madera_slim_device_reset,
+       .device_down = madera_slim_device_down,
 };
 
 static int __init madera_slim_audio_init(void)
index 7d8f9800c082b3b2bf072cacfe55554af8688e3f..e9e0a4fcae7a7c682c1f1244fa67dd94c870b831 100755 (executable)
@@ -4,7 +4,7 @@
 #include <sound/soc.h>
 
 #define MADERA_SLIMBUS_MAX_CHANNELS 8
-#define CONFIG_SND_SOC_MADERA_SLIMBUS 1
+#define CONFIG_SND_SOC_MADERA_SLIMBUS 0
 #ifdef CONFIG_SND_SOC_MADERA_SLIMBUS
 #include <linux/slimbus/slimbus.h>
 
old mode 100644 (file)
new mode 100755 (executable)
index 5d13a60..7aed44a
@@ -4950,6 +4950,35 @@ int madera_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
                return 0;
 }
 EXPORT_SYMBOL_GPL(madera_set_output_mode);
+int madera_frf_bytes_put(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct madera_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct madera *madera = priv->madera;
+       int ret, len;
+       void *data;
+
+       len = params->num_regs * component->val_bytes;
+
+       data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
+       if (!data)
+               return -ENOMEM;
+
+       mutex_lock(&madera->reg_setting_lock);
+       regmap_write(madera->regmap, 0x80, 0x3);
+
+       ret = regmap_raw_write(madera->regmap, params->base, data, len);
+
+       regmap_write(madera->regmap, 0x80, 0x0);
+       mutex_unlock(&madera->reg_setting_lock);
+
+       kfree(data);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(madera_frf_bytes_put);
 
 static bool madera_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
 {
old mode 100644 (file)
new mode 100755 (executable)
index cfa4cf3..6f5f231
 #define MADERA_DOM_GRP_DFC             28
 #define MADERA_N_DOM_GRPS              29
 
-#define MADERA_MAX_DAI                 11
+#define MADERA_MAX_DAI                 17
 #define MADERA_MAX_ADSP                        7
 
+#define MADERA_MAX_AIF_SOURCES         32
+#define MADERA_MAX_MIXER_SOURCES       48
 #define MADERA_NUM_MIXER_INPUTS                148
 
+#define MADERA_FRF_COEFFICIENT_LEN     4
+
 struct madera;
 struct wm_adsp;
-
+/* Voice trigger event codes */
+enum {
+       MADERA_TRIGGER_VOICE,
+       MADERA_TRIGGER_TEXT,
+       MADERA_TRIGGER_PANIC
+};
 struct madera_voice_trigger_info {
        /** Which core triggered, 1-based (1 = DSP1, ...) */
        int core_num;
+       int code;
+       u16 err_msg[4];
 };
 
 struct madera_dai_priv {
@@ -150,6 +161,18 @@ struct madera_priv {
        int tdm_slots[MADERA_MAX_AIF];
 
        int domain_group_ref[MADERA_N_DOM_GRPS];
+       unsigned int aif_sources_cache[MADERA_MAX_AIF_SOURCES];
+       unsigned int mixer_sources_cache[MADERA_MAX_MIXER_SOURCES];
+
+       int (*get_sources)(unsigned int reg, const unsigned int **cur_sources,
+                          int *lim);
+
+
+       u32 rx1_samplerate;
+       u32 rx1_sampleszbits;
+       u32 rx2_samplerate;
+       u32 rx2_sampleszbits;
+
 };
 
 struct madera_fll_cfg {
@@ -318,6 +341,29 @@ extern unsigned int madera_mixer_values[MADERA_NUM_MIXER_INPUTS];
        ((unsigned long)&(struct soc_bytes) { .base = xbase,    \
         .num_regs = 1 }) }
 
+#define MADERA_FRF_BYTES(xname, xbase, xregs)                  \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
+       .info = snd_soc_bytes_info, .get = snd_soc_bytes_get,   \
+       .put = madera_frf_bytes_put, .private_value =           \
+       ((unsigned long)&(struct soc_bytes) {.base = xbase,     \
+        .num_regs = xregs }) }
+
+/* 2 mixer inputs with a stride of n in the register address */
+#define MADERA_MIXER_INPUTS_2_N(_reg, n)       \
+       (_reg),                                 \
+       (_reg) + (1 * (n))
+
+/* 4 mixer inputs with a stride of n in the register address */
+#define MADERA_MIXER_INPUTS_4_N(_reg, n)               \
+       MADERA_MIXER_INPUTS_2_N(_reg, n),               \
+       MADERA_MIXER_INPUTS_2_N(_reg + (2 * n), n)
+
+#define MADERA_DSP_MIXER_INPUTS(_reg)          \
+       MADERA_MIXER_INPUTS_4_N(_reg, 2),       \
+       MADERA_MIXER_INPUTS_4_N(_reg + 8, 2),   \
+       MADERA_MIXER_INPUTS_4_N(_reg + 16, 8),  \
+       MADERA_MIXER_INPUTS_2_N(_reg + 48, 8)
+
 #define MADERA_RATES SNDRV_PCM_RATE_KNOT
 
 #define MADERA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -430,6 +476,9 @@ int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol);
 int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol);
+extern int madera_frf_bytes_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol);
+                               
 int madera_set_adsp_clk(struct madera_priv *priv, int dsp_num,
                        unsigned int freq);