get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/810585/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 810585,
    "url": "http://patchwork.ozlabs.org/api/patches/810585/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/patch/1504704043-8052-15-git-send-email-rf@opensource.wolfsonmicro.com/",
    "project": {
        "id": 42,
        "url": "http://patchwork.ozlabs.org/api/projects/42/?format=api",
        "name": "Linux GPIO development",
        "link_name": "linux-gpio",
        "list_id": "linux-gpio.vger.kernel.org",
        "list_email": "linux-gpio@vger.kernel.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1504704043-8052-15-git-send-email-rf@opensource.wolfsonmicro.com>",
    "list_archive_url": null,
    "date": "2017-09-06T13:20:40",
    "name": "[v5,14/17] ASoC: madera: Add common support for Cirrus Logic Madera codecs",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "c7d49b89b83af37bf3cda9df5308e310ee603283",
    "submitter": {
        "id": 65141,
        "url": "http://patchwork.ozlabs.org/api/people/65141/?format=api",
        "name": "Richard Fitzgerald",
        "email": "rf@opensource.wolfsonmicro.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-gpio/patch/1504704043-8052-15-git-send-email-rf@opensource.wolfsonmicro.com/mbox/",
    "series": [
        {
            "id": 1804,
            "url": "http://patchwork.ozlabs.org/api/series/1804/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/list/?series=1804",
            "date": "2017-09-06T13:20:36",
            "name": "Add support for Cirrus Logic CS47L35/L85/L90/L91 codecs",
            "version": 5,
            "mbox": "http://patchwork.ozlabs.org/series/1804/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/810585/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/810585/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linux-gpio-owner@vger.kernel.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-gpio-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ppops.net;\n\tspf=none smtp.mailfrom=rf@opensource.wolfsonmicro.com"
        ],
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xnPQ20gnvz9t2R\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed,  6 Sep 2017 23:22:18 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1754688AbdIFNWQ (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tWed, 6 Sep 2017 09:22:16 -0400",
            "from mx0b-001ae601.pphosted.com ([67.231.152.168]:42812 \"EHLO\n\tmx0b-001ae601.pphosted.com\" rhost-flags-OK-OK-OK-OK)\n\tby vger.kernel.org with ESMTP id S1754561AbdIFNVN (ORCPT\n\t<rfc822; linux-gpio@vger.kernel.org>); Wed, 6 Sep 2017 09:21:13 -0400",
            "from pps.filterd (m0077474.ppops.net [127.0.0.1])\n\tby mx0b-001ae601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv86DJnVt029121; Wed, 6 Sep 2017 08:20:48 -0500",
            "from mail1.cirrus.com (mail1.cirrus.com [141.131.3.20])\n\tby mx0b-001ae601.pphosted.com with ESMTP id 2cqs2mav6j-1;\n\tWed, 06 Sep 2017 08:20:47 -0500",
            "from EX17.ad.cirrus.com (unknown [172.20.9.81])\n\tby mail1.cirrus.com (Postfix) with ESMTP id 38CCD6121AD4;\n\tWed,  6 Sep 2017 08:20:47 -0500 (CDT)",
            "from imbe.wolfsonmicro.main (198.61.95.81) by EX17.ad.cirrus.com\n\t(172.20.9.81) with Microsoft SMTP Server id 14.3.301.0;\n\tWed, 6 Sep 2017 14:20:45 +0100",
            "from rf-debian.ad.cirrus.com (rf-debian.ad.cirrus.com\n\t[198.90.223.45]) by imbe.wolfsonmicro.main (8.14.4/8.14.4) with ESMTP\n\tid v86DKhDY032150;        Wed, 6 Sep 2017 14:20:45 +0100"
        ],
        "From": "Richard Fitzgerald <rf@opensource.wolfsonmicro.com>",
        "To": "<lee.jones@linaro.org>, <broonie@kernel.org>,\n\t<linus.walleij@linaro.org>, <gnurou@gmail.com>,\n\t<robh+dt@kernel.org>, <tglx@linutronix.de>, <jason@lakedaemon.net>",
        "CC": "<alsa-devel@alsa-project.org>, <patches@opensource.wolfsonmicro.com>,\n\t<linux-gpio@vger.kernel.org>, <devicetree@vger.kernel.org>,\n\t<linux-kernel@vger.kernel.org>",
        "Subject": "[PATCH v5 14/17] ASoC: madera: Add common support for Cirrus Logic\n\tMadera codecs",
        "Date": "Wed, 6 Sep 2017 14:20:40 +0100",
        "Message-ID": "<1504704043-8052-15-git-send-email-rf@opensource.wolfsonmicro.com>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1504704043-8052-1-git-send-email-rf@opensource.wolfsonmicro.com>",
        "References": "<1504704043-8052-1-git-send-email-rf@opensource.wolfsonmicro.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Proofpoint-Spam-Details": "rule=notspam policy=default score=0\n\tpriorityscore=1501 malwarescore=0\n\tsuspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015\n\tlowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam\n\tadjust=0\n\treason=mlx scancount=1 engine=8.0.1-1707230000\n\tdefinitions=main-1709060186",
        "Sender": "linux-gpio-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<linux-gpio.vger.kernel.org>",
        "X-Mailing-List": "linux-gpio@vger.kernel.org"
    },
    "content": "The Cirrus Logic Madera codecs are a family of related codecs with\nextensive digital and analogue I/O, digital mixing and routing,\nsignal processing and programmable DSPs.\n\nThis patch adds common support code shared by all Madera codecs.\n\nSigned-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>\nSigned-off-by: Nariman Poushin <nariman@opensource.wolfsonmicro.com>\nSigned-off-by: Nikesh Oswal <Nikesh.Oswal@wolfsonmicro.com>\nSigned-off-by: Piotr Stankiewicz <piotrs@opensource.wolfsonmicro.com>\nSigned-off-by: Ajit Pandey <ajit.pandey@incubesol.com>\nSigned-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>\n---\nChanges since V4:\n- renaming of bus error interrupts to match new names in registers.h\n- include madera-irq.c in madera.c\n- fixed return of wrong variable in madera_get_variable_u32_array\n\n MAINTAINERS                  |    4 +\n include/sound/madera-pdata.h |   61 +\n sound/soc/codecs/Kconfig     |    5 +\n sound/soc/codecs/Makefile    |    2 +\n sound/soc/codecs/madera.c    | 4439 ++++++++++++++++++++++++++++++++++++++++++\n sound/soc/codecs/madera.h    |  470 +++++\n 6 files changed, 4981 insertions(+)\n create mode 100644 include/sound/madera-pdata.h\n create mode 100644 sound/soc/codecs/madera.c\n create mode 100644 sound/soc/codecs/madera.h",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 92f02b7..ecb3043 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -3427,14 +3427,18 @@ W:\thttps://github.com/CirrusLogic/linux-drivers/wiki\n S:\tSupported\n F:\tDocumentation/devicetree/bindings/mfd/madera.txt\n F:\tDocumentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt\n+F:\tDocumentation/devicetree/bindings/sound/madera.txt\n F:\tinclude/dt-bindings/sound/madera*\n F:\tinclude/linux/irqchip/irq-madera*\n F:\tinclude/linux/mfd/madera/*\n+F:\tinclude/sound/madera*\n F:\tdrivers/gpio/gpio-madera*\n F:\tdrivers/irqchip/irq-madera*\n F:\tdrivers/mfd/madera*\n F:\tdrivers/mfd/cs47l*\n F:\tdrivers/pinctrl/cirrus/*\n+F:\tsound/soc/codecs/cs47l*\n+F:\tsound/soc/codecs/madera*\n \n CLEANCACHE API\n M:\tKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>\ndiff --git a/include/sound/madera-pdata.h b/include/sound/madera-pdata.h\nnew file mode 100644\nindex 0000000..47f6b44\n--- /dev/null\n+++ b/include/sound/madera-pdata.h\n@@ -0,0 +1,61 @@\n+/*\n+ * Platform data for Madera codec driver\n+ *\n+ * Copyright 2016-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#ifndef MADERA_CODEC_PDATA_H\n+#define MADERA_CODEC_PDATA_H\n+\n+#include <linux/kernel.h>\n+\n+#define MADERA_MAX_INPUT\t\t6\n+#define MADERA_MAX_MUXED_CHANNELS\t4\n+#define MADERA_MAX_OUTPUT\t\t6\n+#define MADERA_MAX_AIF\t\t\t4\n+#define MADERA_MAX_PDM_SPK\t\t2\n+#define MADERA_MAX_DSP\t\t\t7\n+\n+/**\n+ * struct madera_codec_pdata\n+ *\n+ * @max_channels_clocked: Maximum number of channels that I2S clocks will be\n+ *\t\t\t  generated for. Useful when clock master for systems\n+ *\t\t\t  where the I2S bus has multiple data lines.\n+ * @dmic_ref:\t\t  Indicates how the MICBIAS pins have been externally\n+ *\t\t\t  connected to DMICs on each input. A value of 0\n+ *\t\t\t  indicates MICVDD and is the default. Other values are:\n+ *\t\t\t  For CS47L35 one of the CS47L35_DMIC_REF_xxx values\n+ *\t\t\t  For all other codecs one of the MADERA_DMIC_REF_xxx\n+ *\t\t\t  Also see the datasheet for a description of the\n+ *\t\t\t  INn_DMIC_SUP field.\n+ * @inmode:\t\t  Mode for the ADC inputs. One of the MADERA_INMODE_xxx\n+ *\t\t\t  values. Two-dimensional array\n+ *\t\t\t  [input_number][channel number], with four slots per\n+ *\t\t\t  input in the order\n+ *\t\t\t  [n][0]=INnAL [n][1]=INnAR [n][2]=INnBL [n][3]=INnBR\n+ * @out_mono:\t\t  For each output set the value to TRUE to indicate that\n+ *\t\t\t  the output is mono. [0]=OUT1, [1]=OUT2, ...\n+ * @pdm_fmt:\t\t  PDM speaker data format. See the PDM_SPKn_FMT field in\n+ *\t\t\t  the datasheet for a description of this value.\n+ * @pdm_mute:\t\t  PDM mute format. See the PDM_SPKn_CTRL_1 register\n+ *\t\t\t  in the datasheet for a description of this value.\n+ */\n+struct madera_codec_pdata {\n+\tu32 max_channels_clocked[MADERA_MAX_AIF];\n+\n+\tu32 dmic_ref[MADERA_MAX_INPUT];\n+\n+\tu32 inmode[MADERA_MAX_INPUT][MADERA_MAX_MUXED_CHANNELS];\n+\n+\tbool out_mono[MADERA_MAX_OUTPUT];\n+\n+\tu32 pdm_fmt[MADERA_MAX_PDM_SPK];\n+\tu32 pdm_mute[MADERA_MAX_PDM_SPK];\n+};\n+\n+#endif\ndiff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig\nindex c367d11..44a2978 100644\n--- a/sound/soc/codecs/Kconfig\n+++ b/sound/soc/codecs/Kconfig\n@@ -252,10 +252,12 @@ config SND_SOC_WM_HUBS\n config SND_SOC_WM_ADSP\n \ttristate\n \tselect SND_SOC_COMPRESS\n+\tdefault y if SND_SOC_MADERA=y\n \tdefault y if SND_SOC_CS47L24=y\n \tdefault y if SND_SOC_WM5102=y\n \tdefault y if SND_SOC_WM5110=y\n \tdefault y if SND_SOC_WM2200=y\n+\tdefault m if SND_SOC_MADERA=m\n \tdefault m if SND_SOC_CS47L24=m\n \tdefault m if SND_SOC_WM5102=m\n \tdefault m if SND_SOC_WM5110=m\n@@ -591,6 +593,9 @@ config SND_SOC_ISABELLE\n config SND_SOC_LM49453\n \ttristate\n \n+config SND_SOC_MADERA\n+\ttristate\n+\n config SND_SOC_MAX98088\n        tristate\n \ndiff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile\nindex 77c1818..e1ab86a 100644\n--- a/sound/soc/codecs/Makefile\n+++ b/sound/soc/codecs/Makefile\n@@ -79,6 +79,7 @@ snd-soc-jz4740-codec-objs := jz4740.o\n snd-soc-l3-objs := l3.o\n snd-soc-lm4857-objs := lm4857.o\n snd-soc-lm49453-objs := lm49453.o\n+snd-soc-madera-objs := madera.o\n snd-soc-max9768-objs := max9768.o\n snd-soc-max98088-objs := max98088.o\n snd-soc-max98090-objs := max98090.o\n@@ -319,6 +320,7 @@ obj-$(CONFIG_SND_SOC_JZ4740_CODEC)\t+= snd-soc-jz4740-codec.o\n obj-$(CONFIG_SND_SOC_L3)\t+= snd-soc-l3.o\n obj-$(CONFIG_SND_SOC_LM4857)\t+= snd-soc-lm4857.o\n obj-$(CONFIG_SND_SOC_LM49453)   += snd-soc-lm49453.o\n+obj-$(CONFIG_SND_SOC_MADERA)\t+= snd-soc-madera.o\n obj-$(CONFIG_SND_SOC_MAX9768)\t+= snd-soc-max9768.o\n obj-$(CONFIG_SND_SOC_MAX98088)\t+= snd-soc-max98088.o\n obj-$(CONFIG_SND_SOC_MAX98090)\t+= snd-soc-max98090.o\ndiff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c\nnew file mode 100644\nindex 0000000..be03755\n--- /dev/null\n+++ b/sound/soc/codecs/madera.c\n@@ -0,0 +1,4439 @@\n+/*\n+ * madera.c - Cirrus Logic Madera class codecs common support\n+ *\n+ * Copyright 2015-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#include <linux/delay.h>\n+#include <linux/gcd.h>\n+#include <linux/module.h>\n+#include <linux/pm_runtime.h>\n+#include <linux/slab.h>\n+#include <sound/pcm.h>\n+#include <sound/pcm_params.h>\n+#include <sound/tlv.h>\n+\n+#include <linux/irqchip/irq-madera.h>\n+#include <linux/mfd/madera/core.h>\n+#include <linux/mfd/madera/registers.h>\n+#include <linux/mfd/madera/pdata.h>\n+#include <sound/madera-pdata.h>\n+\n+#include <dt-bindings/sound/madera.h>\n+\n+#include \"madera.h\"\n+\n+#define MADERA_AIF_BCLK_CTRL\t\t\t0x00\n+#define MADERA_AIF_TX_PIN_CTRL\t\t\t0x01\n+#define MADERA_AIF_RX_PIN_CTRL\t\t\t0x02\n+#define MADERA_AIF_RATE_CTRL\t\t\t0x03\n+#define MADERA_AIF_FORMAT\t\t\t0x04\n+#define MADERA_AIF_RX_BCLK_RATE\t\t\t0x06\n+#define MADERA_AIF_FRAME_CTRL_1\t\t\t0x07\n+#define MADERA_AIF_FRAME_CTRL_2\t\t\t0x08\n+#define MADERA_AIF_FRAME_CTRL_3\t\t\t0x09\n+#define MADERA_AIF_FRAME_CTRL_4\t\t\t0x0A\n+#define MADERA_AIF_FRAME_CTRL_5\t\t\t0x0B\n+#define MADERA_AIF_FRAME_CTRL_6\t\t\t0x0C\n+#define MADERA_AIF_FRAME_CTRL_7\t\t\t0x0D\n+#define MADERA_AIF_FRAME_CTRL_8\t\t\t0x0E\n+#define MADERA_AIF_FRAME_CTRL_9\t\t\t0x0F\n+#define MADERA_AIF_FRAME_CTRL_10\t\t0x10\n+#define MADERA_AIF_FRAME_CTRL_11\t\t0x11\n+#define MADERA_AIF_FRAME_CTRL_12\t\t0x12\n+#define MADERA_AIF_FRAME_CTRL_13\t\t0x13\n+#define MADERA_AIF_FRAME_CTRL_14\t\t0x14\n+#define MADERA_AIF_FRAME_CTRL_15\t\t0x15\n+#define MADERA_AIF_FRAME_CTRL_16\t\t0x16\n+#define MADERA_AIF_FRAME_CTRL_17\t\t0x17\n+#define MADERA_AIF_FRAME_CTRL_18\t\t0x18\n+#define MADERA_AIF_TX_ENABLES\t\t\t0x19\n+#define MADERA_AIF_RX_ENABLES\t\t\t0x1A\n+#define MADERA_AIF_FORCE_WRITE\t\t\t0x1B\n+\n+#define MADERA_DSP_CONFIG_1_OFFS\t\t0x00\n+#define MADERA_DSP_CONFIG_2_OFFS\t\t0x02\n+\n+#define MADERA_DSP_CLK_SEL_MASK\t\t\t0x70000\n+#define MADERA_DSP_CLK_SEL_SHIFT\t\t16\n+\n+#define MADERA_DSP_RATE_MASK\t\t\t0x7800\n+#define MADERA_DSP_RATE_SHIFT\t\t\t11\n+\n+#define MADERA_SYSCLK_6MHZ\t\t\t0\n+#define MADERA_SYSCLK_12MHZ\t\t\t1\n+#define MADERA_SYSCLK_24MHZ\t\t\t2\n+#define MADERA_SYSCLK_49MHZ\t\t\t3\n+#define MADERA_SYSCLK_98MHZ\t\t\t4\n+\n+#define MADERA_DSPCLK_9MHZ\t\t\t0\n+#define MADERA_DSPCLK_18MHZ\t\t\t1\n+#define MADERA_DSPCLK_36MHZ\t\t\t2\n+#define MADERA_DSPCLK_73MHZ\t\t\t3\n+#define MADERA_DSPCLK_147MHZ\t\t\t4\n+\n+#define MADERA_FLL_VCO_CORNER\t\t\t141900000\n+#define MADERA_FLL_MAX_FREF\t\t\t13500000\n+#define MADERA_FLL_MAX_N\t\t\t1023\n+#define MADERA_FLL_MIN_FOUT\t\t\t90000000\n+#define MADERA_FLL_MAX_FOUT\t\t\t100000000\n+#define MADERA_FLL_MAX_FRATIO\t\t\t16\n+#define MADERA_FLL_MAX_REFDIV\t\t\t8\n+#define MADERA_FLL_OUTDIV\t\t\t3\n+#define MADERA_FLL_VCO_MULT\t\t\t3\n+#define MADERA_FLLAO_MAX_FREF\t\t\t12288000\n+#define MADERA_FLLAO_MIN_N\t\t\t4\n+#define MADERA_FLLAO_MAX_N\t\t\t1023\n+#define MADERA_FLLAO_MAX_FBDIV\t\t\t254\n+\n+#define MADERA_FLL_SYNCHRONISER_OFFS\t\t0x10\n+#define CS47L35_FLL_SYNCHRONISER_OFFS\t\t0xE\n+#define MADERA_FLL_CONTROL_1_OFFS\t\t0x1\n+#define MADERA_FLL_CONTROL_2_OFFS\t\t0x2\n+#define MADERA_FLL_CONTROL_3_OFFS\t\t0x3\n+#define MADERA_FLL_CONTROL_4_OFFS\t\t0x4\n+#define MADERA_FLL_CONTROL_5_OFFS\t\t0x5\n+#define MADERA_FLL_CONTROL_6_OFFS\t\t0x6\n+#define MADERA_FLL_LOOP_FILTER_TEST_1_OFFS\t0x7\n+#define MADERA_FLL_NCO_TEST_0_OFFS\t\t0x8\n+#define MADERA_FLL_CONTROL_7_OFFS\t\t0x9\n+#define MADERA_FLL_EFS_2_OFFS\t\t\t0xA\n+#define MADERA_FLL_SYNCHRONISER_1_OFFS\t\t0x1\n+#define MADERA_FLL_SYNCHRONISER_2_OFFS\t\t0x2\n+#define MADERA_FLL_SYNCHRONISER_3_OFFS\t\t0x3\n+#define MADERA_FLL_SYNCHRONISER_4_OFFS\t\t0x4\n+#define MADERA_FLL_SYNCHRONISER_5_OFFS\t\t0x5\n+#define MADERA_FLL_SYNCHRONISER_6_OFFS\t\t0x6\n+#define MADERA_FLL_SYNCHRONISER_7_OFFS\t\t0x7\n+#define MADERA_FLL_SPREAD_SPECTRUM_OFFS\t\t0x9\n+#define MADERA_FLL_GPIO_CLOCK_OFFS\t\t0xA\n+\n+#define MADERA_FLLAO_CONTROL_1_OFFS\t\t0x1\n+#define MADERA_FLLAO_CONTROL_2_OFFS\t\t0x2\n+#define MADERA_FLLAO_CONTROL_3_OFFS\t\t0x3\n+#define MADERA_FLLAO_CONTROL_4_OFFS\t\t0x4\n+#define MADERA_FLLAO_CONTROL_5_OFFS\t\t0x5\n+#define MADERA_FLLAO_CONTROL_6_OFFS\t\t0x6\n+#define MADERA_FLLAO_CONTROL_7_OFFS\t\t0x8\n+#define MADERA_FLLAO_CONTROL_8_OFFS\t\t0xA\n+#define MADERA_FLLAO_CONTROL_9_OFFS\t\t0xB\n+#define MADERA_FLLAO_CONTROL_10_OFFS\t\t0xC\n+#define MADERA_FLLAO_CONTROL_11_OFFS\t\t0xD\n+\n+#define MADERA_FMT_DSP_MODE_A\t\t\t0\n+#define MADERA_FMT_DSP_MODE_B\t\t\t1\n+#define MADERA_FMT_I2S_MODE\t\t\t2\n+#define MADERA_FMT_LEFT_JUSTIFIED_MODE\t\t3\n+\n+#define madera_fll_err(_fll, fmt, ...) \\\n+\tdev_err(_fll->madera->dev, \"FLL%d: \" fmt, _fll->id, ##__VA_ARGS__)\n+#define madera_fll_warn(_fll, fmt, ...) \\\n+\tdev_warn(_fll->madera->dev, \"FLL%d: \" fmt, _fll->id, ##__VA_ARGS__)\n+#define madera_fll_dbg(_fll, fmt, ...) \\\n+\tdev_dbg(_fll->madera->dev, \"FLL%d: \" fmt, _fll->id, ##__VA_ARGS__)\n+\n+#define madera_aif_err(_dai, fmt, ...) \\\n+\tdev_err(_dai->dev, \"AIF%d: \" fmt, _dai->id, ##__VA_ARGS__)\n+#define madera_aif_warn(_dai, fmt, ...) \\\n+\tdev_warn(_dai->dev, \"AIF%d: \" fmt, _dai->id, ##__VA_ARGS__)\n+#define madera_aif_dbg(_dai, fmt, ...) \\\n+\tdev_dbg(_dai->dev, \"AIF%d: \" fmt, _dai->id, ##__VA_ARGS__)\n+\n+static const int madera_dsp_bus_error_irqs[MADERA_MAX_ADSP] = {\n+\tMADERA_IRQ_DSP1_BUS_ERR,\n+\tMADERA_IRQ_DSP2_BUS_ERR,\n+\tMADERA_IRQ_DSP3_BUS_ERR,\n+\tMADERA_IRQ_DSP4_BUS_ERR,\n+\tMADERA_IRQ_DSP5_BUS_ERR,\n+\tMADERA_IRQ_DSP6_BUS_ERR,\n+\tMADERA_IRQ_DSP7_BUS_ERR,\n+};\n+\n+void madera_spin_sysclk(struct madera_priv *priv)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int val;\n+\tint ret, i;\n+\n+\t/* Skip this if the chip is down */\n+\tif (pm_runtime_suspended(madera->dev))\n+\t\treturn;\n+\n+\t/*\n+\t * Just read a register a few times to ensure the internal\n+\t * oscillator sends out a few clocks.\n+\t */\n+\tfor (i = 0; i < 4; i++) {\n+\t\tret = regmap_read(madera->regmap, MADERA_SOFTWARE_RESET, &val);\n+\t\tif (ret)\n+\t\t\tdev_err(madera->dev,\n+\t\t\t\t\"%s Failed to read register: %d (%d)\\n\",\n+\t\t\t\t__func__, ret, i);\n+\t}\n+\n+\tudelay(300);\n+}\n+EXPORT_SYMBOL_GPL(madera_spin_sysclk);\n+\n+int madera_sysclk_ev(struct snd_soc_dapm_widget *w,\n+\t\t     struct snd_kcontrol *kcontrol, int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\n+\tmadera_spin_sysclk(priv);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_sysclk_ev);\n+\n+static int madera_check_speaker_overheat(struct madera *madera,\n+\t\t\t\t\t bool *warn, bool *shutdown)\n+{\n+\tunsigned int val;\n+\tint ret;\n+\n+\tret = regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_15, &val);\n+\tif (ret) {\n+\t\tdev_err(madera->dev, \"Failed to read thermal status: %d\\n\",\n+\t\t\tret);\n+\t\treturn ret;\n+\t}\n+\n+\t*warn = val & MADERA_SPK_OVERHEAT_WARN_STS1;\n+\t*shutdown = val & MADERA_SPK_OVERHEAT_STS1;\n+\n+\treturn 0;\n+}\n+\n+int madera_spk_ev(struct snd_soc_dapm_widget *w,\n+\t\t  struct snd_kcontrol *kcontrol, int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\tbool warn, shutdown;\n+\tint ret;\n+\n+\tswitch (event) {\n+\tcase SND_SOC_DAPM_POST_PMU:\n+\t\tret = madera_check_speaker_overheat(madera, &warn, &shutdown);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tif (shutdown) {\n+\t\t\tdev_crit(madera->dev,\n+\t\t\t\t \"Speaker not enabled due to temperature\\n\");\n+\t\t\treturn -EBUSY;\n+\t\t}\n+\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t   1 << w->shift, 1 << w->shift);\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_PRE_PMD:\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t   1 << w->shift, 0);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_spk_ev);\n+\n+static irqreturn_t madera_thermal_warn(int irq, void *data)\n+{\n+\tstruct madera *madera = data;\n+\tbool warn, shutdown;\n+\tint ret;\n+\n+\tret = madera_check_speaker_overheat(madera, &warn, &shutdown);\n+\tif (ret)\n+\t\tshutdown = true; /* for safety attempt to shutdown on error */\n+\n+\tif (shutdown) {\n+\t\tdev_crit(madera->dev, \"Thermal shutdown\\n\");\n+\t\tret = regmap_update_bits(madera->regmap,\n+\t\t\t\t\t MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t\t MADERA_OUT4L_ENA |\n+\t\t\t\t\t MADERA_OUT4R_ENA, 0);\n+\t\tif (ret != 0)\n+\t\t\tdev_crit(madera->dev,\n+\t\t\t\t \"Failed to disable speaker outputs: %d\\n\",\n+\t\t\t\t ret);\n+\t} else if (warn) {\n+\t\tdev_crit(madera->dev, \"Thermal warning\\n\");\n+\t}\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+int madera_init_overheat(struct madera_priv *priv)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tint ret;\n+\n+\tret = madera_request_irq(madera, MADERA_IRQ_SPK_OVERHEAT_WARN,\n+\t\t\t\t \"Thermal warning\", madera_thermal_warn,\n+\t\t\t\t madera);\n+\tif (ret)\n+\t\tdev_warn(madera->dev,\n+\t\t\t\"Failed to get thermal warning IRQ: %d\\n\", ret);\n+\n+\tret = madera_request_irq(madera, MADERA_IRQ_SPK_OVERHEAT,\n+\t\t\t\t \"Thermal shutdown\", madera_thermal_warn,\n+\t\t\t\t madera);\n+\tif (ret)\n+\t\tdev_warn(madera->dev,\n+\t\t\t\"Failed to get thermal shutdown IRQ: %d\\n\", ret);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_init_overheat);\n+\n+int madera_free_overheat(struct madera_priv *priv)\n+{\n+\tstruct madera *madera = priv->madera;\n+\n+\tmadera_free_irq(madera, MADERA_IRQ_SPK_OVERHEAT_WARN, madera);\n+\tmadera_free_irq(madera, MADERA_IRQ_SPK_OVERHEAT, madera);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_free_overheat);\n+\n+static int madera_get_variable_u32_array(struct madera_priv *priv,\n+\t\t\t\t\t const char *propname,\n+\t\t\t\t\t u32 *dest,\n+\t\t\t\t\t int n_max,\n+\t\t\t\t\t int multiple)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tint n, ret;\n+\n+\tn = device_property_read_u32_array(madera->dev, propname, NULL, 0);\n+\tif (n == -EINVAL) {\n+\t\treturn 0;\t/* missing, ignore */\n+\t} else if (n < 0) {\n+\t\tdev_warn(madera->dev, \"%s malformed (%d)\\n\",\n+\t\t\t propname, n);\n+\t\treturn n;\n+\t} else if ((n % multiple) != 0) {\n+\t\tdev_warn(madera->dev, \"%s not a multiple of %d entries\\n\",\n+\t\t\t propname, multiple);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (n > n_max)\n+\t\tn = n_max;\n+\n+\tret = device_property_read_u32_array(madera->dev, propname, dest, n);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\telse\n+\t\treturn n;\n+}\n+\n+static void madera_prop_get_inmode(struct madera_priv *priv)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tu32 tmp[MADERA_MAX_INPUT * MADERA_MAX_MUXED_CHANNELS];\n+\tint n, i, in_idx, ch_idx;\n+\n+\tBUILD_BUG_ON(ARRAY_SIZE(madera->pdata.codec.inmode) !=\n+\t\t     MADERA_MAX_INPUT);\n+\tBUILD_BUG_ON(ARRAY_SIZE(madera->pdata.codec.inmode[0]) !=\n+\t\t     MADERA_MAX_MUXED_CHANNELS);\n+\n+\tn = madera_get_variable_u32_array(priv,\n+\t\t\t\t\t  \"cirrus,inmode\",\n+\t\t\t\t\t  tmp,\n+\t\t\t\t\t  ARRAY_SIZE(tmp),\n+\t\t\t\t\t  MADERA_MAX_MUXED_CHANNELS);\n+\tif (n < 0)\n+\t\treturn;\n+\n+\tin_idx = 0;\n+\tch_idx = 0;\n+\tfor (i = 0; i < n; ++i) {\n+\t\tmadera->pdata.codec.inmode[in_idx][ch_idx] = tmp[i];\n+\n+\t\tif (++ch_idx == MADERA_MAX_MUXED_CHANNELS) {\n+\t\t\tch_idx = 0;\n+\t\t\t++in_idx;\n+\t\t}\n+\t}\n+}\n+\n+static void madera_prop_get_pdata(struct madera_priv *priv)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tstruct madera_codec_pdata *pdata = &madera->pdata.codec;\n+\tu32 out_mono[ARRAY_SIZE(pdata->out_mono)];\n+\tint i, ret;\n+\n+\tret = madera_get_variable_u32_array(priv,\n+\t\t\t\t\t\"cirrus,max-channels-clocked\",\n+\t\t\t\t\tpdata->max_channels_clocked,\n+\t\t\t\t\tARRAY_SIZE(pdata->max_channels_clocked),\n+\t\t\t\t\t1);\n+\tif (ret < 0)\n+\t\treturn;\n+\n+\tmadera_prop_get_inmode(priv);\n+\n+\tmemset(out_mono, 0, sizeof(out_mono));\n+\tret = device_property_read_u32_array(madera->dev,\n+\t\t\t\t\t     \"cirrus,out-mono\",\n+\t\t\t\t\t     out_mono,\n+\t\t\t\t\t     ARRAY_SIZE(out_mono));\n+\tif (ret == 0)\n+\t\tfor (i = 0; i < ARRAY_SIZE(out_mono); ++i)\n+\t\t\tpdata->out_mono[i] = !!out_mono[i];\n+\n+\tmadera_get_variable_u32_array(priv,\n+\t\t\t\t      \"cirrus,pdm-fmt\",\n+\t\t\t\t      pdata->pdm_fmt,\n+\t\t\t\t      ARRAY_SIZE(pdata->pdm_fmt),\n+\t\t\t\t      1);\n+\n+\tmadera_get_variable_u32_array(priv,\n+\t\t\t\t      \"cirrus,pdm-mute\",\n+\t\t\t\t      pdata->pdm_mute,\n+\t\t\t\t      ARRAY_SIZE(pdata->pdm_mute),\n+\t\t\t\t      1);\n+\n+\tmadera_get_variable_u32_array(priv,\n+\t\t\t\t      \"cirrus,dmic-ref\",\n+\t\t\t\t      pdata->dmic_ref,\n+\t\t\t\t      ARRAY_SIZE(pdata->dmic_ref),\n+\t\t\t\t      1);\n+}\n+\n+int madera_core_init(struct madera_priv *priv)\n+{\n+\tBUILD_BUG_ON(ARRAY_SIZE(madera_mixer_texts) != MADERA_NUM_MIXER_INPUTS);\n+\tBUILD_BUG_ON(ARRAY_SIZE(madera_mixer_values) != MADERA_NUM_MIXER_INPUTS);\n+\t/* trap undersized array initializers */\n+\tBUILD_BUG_ON(!madera_sample_rate_text[MADERA_SAMPLE_RATE_ENUM_SIZE - 1]);\n+\tBUILD_BUG_ON(!madera_sample_rate_val[MADERA_SAMPLE_RATE_ENUM_SIZE - 1]);\n+\n+\tif (!dev_get_platdata(priv->madera->dev))\n+\t\tmadera_prop_get_pdata(priv);\n+\n+\tmutex_init(&priv->rate_lock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_core_init);\n+\n+int madera_core_destroy(struct madera_priv *priv)\n+{\n+\tmutex_destroy(&priv->rate_lock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_core_destroy);\n+\n+static void madera_debug_dump_domain_groups(const struct madera_priv *priv)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(priv->domain_group_ref); ++i)\n+\t\tdev_dbg(madera->dev, \"domain_grp_ref[%d]=%d\\n\", i,\n+\t\t\tpriv->domain_group_ref[i]);\n+}\n+\n+int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,\n+\t\t\t struct snd_kcontrol *kcontrol,\n+\t\t\t int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tint dom_grp = w->shift;\n+\n+\tif (dom_grp >= ARRAY_SIZE(priv->domain_group_ref)) {\n+\t\tWARN(true, \"%s dom_grp exceeds array size\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/*\n+\t * We can't rely on the DAPM mutex for locking because we need a lock\n+\t * that can safely be called in hw_params\n+\t */\n+\tmutex_lock(&priv->rate_lock);\n+\n+\tswitch (event) {\n+\tcase SND_SOC_DAPM_PRE_PMU:\n+\t\tdev_dbg(priv->madera->dev, \"Inc ref on domain group %d\\n\",\n+\t\t\tdom_grp);\n+\t\t++priv->domain_group_ref[dom_grp];\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_POST_PMD:\n+\t\tdev_dbg(priv->madera->dev, \"Dec ref on domain group %d\\n\",\n+\t\t\tdom_grp);\n+\t\t--priv->domain_group_ref[dom_grp];\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tmadera_debug_dump_domain_groups(priv);\n+\n+\tmutex_unlock(&priv->rate_lock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_domain_clk_ev);\n+\n+int madera_out1_demux_put(struct snd_kcontrol *kcontrol,\n+\t\t\t  struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);\n+\tstruct snd_soc_dapm_context *dapm =\n+\t\tsnd_soc_dapm_kcontrol_dapm(kcontrol);\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\tstruct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\n+\tunsigned int ep_sel, mux, change;\n+\tint ret, demux_change_ret;\n+\tbool out_mono, restore_out = true;\n+\n+\tif (ucontrol->value.enumerated.item[0] > e->items - 1)\n+\t\treturn -EINVAL;\n+\n+\tmux = ucontrol->value.enumerated.item[0];\n+\tep_sel = mux << MADERA_EP_SEL_SHIFT;\n+\n+\tsnd_soc_dapm_mutex_lock(dapm);\n+\n+\tchange = snd_soc_test_bits(codec, MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t   MADERA_EP_SEL_MASK, ep_sel);\n+\tif (!change)\n+\t\tgoto end;\n+\n+\t/* EP_SEL should not be modified while HP or EP driver is enabled */\n+\tret = regmap_update_bits(madera->regmap,\n+\t\t\t\t MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t MADERA_OUT1L_ENA |\n+\t\t\t\t MADERA_OUT1R_ENA, 0);\n+\tif (ret)\n+\t\tdev_warn(madera->dev, \"Failed to disable outputs: %d\\n\", ret);\n+\n+\tusleep_range(2000, 3000); /* wait for wseq to complete */\n+\n+\t/*\n+\t * if HP detection clamp is applied while switching to HPOUT\n+\t * OUT1 should remain disabled and EDRE should be set to manual\n+\t */\n+\tif (!ep_sel &&\n+\t    (madera->out_clamp[0] || madera->out_shorted[0]))\n+\t\trestore_out = false;\n+\n+\t/* change demux setting */\n+\tdemux_change_ret = regmap_update_bits(madera->regmap,\n+\t\t\t\t\t      MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t\t      MADERA_EP_SEL_MASK, ep_sel);\n+\tif (demux_change_ret) {\n+\t\tdev_err(madera->dev, \"Failed to set OUT1 demux: %d\\n\",\n+\t\t\tdemux_change_ret);\n+\t} else {\n+\t\t/* apply correct setting for mono mode */\n+\t\tif (!ep_sel && !madera->pdata.codec.out_mono[0])\n+\t\t\tout_mono = false; /* stereo HP */\n+\t\telse\n+\t\t\tout_mono = true; /* EP or mono HP */\n+\n+\t\tret = madera_set_output_mode(codec, 1, out_mono);\n+\t\tif (ret)\n+\t\t\tdev_warn(madera->dev,\n+\t\t\t\t \"Failed to set output mode: %d\\n\", ret);\n+\t}\n+\n+\t/* restore output state if allowed */\n+\tif (restore_out) {\n+\t\tret = regmap_update_bits(madera->regmap,\n+\t\t\t\t\t MADERA_OUTPUT_ENABLES_1,\n+\t\t\t\t\t MADERA_OUT1L_ENA |\n+\t\t\t\t\t MADERA_OUT1R_ENA,\n+\t\t\t\t\t madera->hp_ena);\n+\t\tif (ret)\n+\t\t\tdev_warn(madera->dev,\n+\t\t\t\t \"Failed to restore earpiece outputs: %d\\n\",\n+\t\t\t\t ret);\n+\t\telse if (madera->hp_ena)\n+\t\t\tmsleep(34); /* wait for enable wseq */\n+\t\telse\n+\t\t\tusleep_range(2000, 3000); /* wait for disable wseq */\n+\t}\n+\n+end:\n+\tsnd_soc_dapm_mutex_unlock(dapm);\n+\n+\treturn snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);\n+}\n+EXPORT_SYMBOL_GPL(madera_out1_demux_put);\n+\n+\n+static int madera_inmux_put(struct snd_kcontrol *kcontrol,\n+\t\t\t    struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);\n+\tstruct snd_soc_dapm_context *dapm =\n+\t\tsnd_soc_dapm_kcontrol_dapm(kcontrol);\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\tstruct soc_enum *e = (struct soc_enum *) kcontrol->private_value;\n+\tunsigned int mux, src_val, src_mask, gang_reg, dmode_reg, dmode_val;\n+\tunsigned int inmode_a, inmode_gang, inmode;\n+\tbool changed = false;\n+\tint ret;\n+\n+\tmux = ucontrol->value.enumerated.item[0];\n+\tif (mux > 1)\n+\t\treturn -EINVAL;\n+\n+\tsrc_val = mux << e->shift_l;\n+\tsrc_mask = e->mask << e->shift_l;\n+\n+\tswitch (e->reg) {\n+\tcase MADERA_ADC_DIGITAL_VOLUME_1L:\n+\t\tinmode_a = madera->pdata.codec.inmode[0][0];\n+\t\tinmode = madera->pdata.codec.inmode[0][2 * mux];\n+\t\tinmode_gang = madera->pdata.codec.inmode[0][1 + (2 * mux)];\n+\t\tgang_reg = MADERA_ADC_DIGITAL_VOLUME_1R;\n+\t\tdmode_reg = MADERA_IN1L_CONTROL;\n+\t\tbreak;\n+\tcase MADERA_ADC_DIGITAL_VOLUME_1R:\n+\t\tinmode_a = madera->pdata.codec.inmode[0][0];\n+\t\tinmode = madera->pdata.codec.inmode[0][1 + (2 * mux)];\n+\t\tinmode_gang = madera->pdata.codec.inmode[0][2 * mux];\n+\t\tgang_reg = MADERA_ADC_DIGITAL_VOLUME_1L;\n+\t\tdmode_reg = MADERA_IN1L_CONTROL;\n+\t\tbreak;\n+\tcase MADERA_ADC_DIGITAL_VOLUME_2L:\n+\t\tinmode_a = madera->pdata.codec.inmode[1][0];\n+\t\tinmode = madera->pdata.codec.inmode[1][2 * mux];\n+\t\tinmode_gang = madera->pdata.codec.inmode[1][1 + (2 * mux)];\n+\t\tgang_reg = MADERA_ADC_DIGITAL_VOLUME_2R;\n+\t\tdmode_reg = MADERA_IN2L_CONTROL;\n+\t\tbreak;\n+\tcase MADERA_ADC_DIGITAL_VOLUME_2R:\n+\t\tinmode_a = madera->pdata.codec.inmode[1][0];\n+\t\tinmode = madera->pdata.codec.inmode[1][1 + (2 * mux)];\n+\t\tinmode_gang = madera->pdata.codec.inmode[1][2 * mux];\n+\t\tgang_reg = MADERA_ADC_DIGITAL_VOLUME_2L;\n+\t\tdmode_reg = MADERA_IN2L_CONTROL;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* SE mask and shift is same for all channels */\n+\tsrc_mask |= MADERA_IN1L_SRC_SE_MASK;\n+\tif (inmode & MADERA_INMODE_SE)\n+\t\tsrc_val |= 1 << MADERA_IN1L_SRC_SE_SHIFT;\n+\n+\tdev_dbg(madera->dev,\n+\t\t\"mux=%u reg=0x%x inmode_a=0x%x inmode=0x%x mask=0x%x val=0x%x\\n\",\n+\t\tmux, e->reg, inmode_a, inmode, src_mask, src_val);\n+\n+\tret = snd_soc_component_update_bits(dapm->component,\n+\t\t\t\t\t    e->reg,\n+\t\t\t\t\t    src_mask,\n+\t\t\t\t\t    src_val);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\telse if (ret)\n+\t\tchanged = true;\n+\n+\tif (inmode_a == MADERA_INMODE_DMIC) {\n+\t\tif (mux)\n+\t\t\tdmode_val = 0; /* B always analogue */\n+\t\telse\n+\t\t\tdmode_val = 1 << MADERA_IN1_MODE_SHIFT; /* DMIC */\n+\n+\t\tdev_dbg(madera->dev, \"dmode_val=0x%x\\n\", dmode_val);\n+\n+\t\tret = snd_soc_component_update_bits(dapm->component,\n+\t\t\t\t\t\t    dmode_reg,\n+\t\t\t\t\t\t    MADERA_IN1_MODE_MASK,\n+\t\t\t\t\t\t    dmode_val);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\t/* if A is digital we must switch both channels together */\n+\t\tswitch (madera->type) {\n+\t\tcase CS47L85:\n+\t\tcase WM1840:\n+\t\t\tif (e->reg == MADERA_ADC_DIGITAL_VOLUME_1L)\n+\t\t\t\tgoto out;\t/* not ganged */\n+\t\t\tbreak;\n+\t\tcase CS47L90:\n+\t\tcase CS47L91:\n+\t\t\tif (e->reg == MADERA_ADC_DIGITAL_VOLUME_2L)\n+\t\t\t\tgoto out;\t/* not ganged */\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* ganged channels can have different analogue modes */\n+\t\tif (inmode_gang & MADERA_INMODE_SE)\n+\t\t\tsrc_val |= 1 << MADERA_IN1L_SRC_SE_SHIFT;\n+\t\telse\n+\t\t\tsrc_val &= ~(1 << MADERA_IN1L_SRC_SE_SHIFT);\n+\n+\t\tdev_dbg(madera->dev,\n+\t\t\t\"gang_reg=0x%x inmode_gang=0x%x gang_val=0x%x\\n\",\n+\t\t\tgang_reg, inmode_gang, src_val);\n+\n+\t\tret = snd_soc_component_update_bits(dapm->component,\n+\t\t\t\t\t\t    gang_reg,\n+\t\t\t\t\t\t    src_mask,\n+\t\t\t\t\t\t    src_val);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t\telse if (ret)\n+\t\t\tchanged = true;\n+\t}\n+\n+out:\n+\tif (changed)\n+\t\treturn snd_soc_dapm_mux_update_power(dapm, kcontrol,\n+\t\t\t\t\t\t     mux, e, NULL);\n+\telse\n+\t\treturn 0;\n+}\n+\n+static const char * const madera_inmux_texts[] = {\n+\t\"A\",\n+\t\"B\",\n+};\n+\n+static SOC_ENUM_SINGLE_DECL(madera_in1muxl_enum,\n+\t\t\t    MADERA_ADC_DIGITAL_VOLUME_1L,\n+\t\t\t    MADERA_IN1L_SRC_SHIFT,\n+\t\t\t    madera_inmux_texts);\n+\n+static SOC_ENUM_SINGLE_DECL(madera_in1muxr_enum,\n+\t\t\t    MADERA_ADC_DIGITAL_VOLUME_1R,\n+\t\t\t    MADERA_IN1R_SRC_SHIFT,\n+\t\t\t    madera_inmux_texts);\n+\n+static SOC_ENUM_SINGLE_DECL(madera_in2muxl_enum,\n+\t\t\t    MADERA_ADC_DIGITAL_VOLUME_2L,\n+\t\t\t    MADERA_IN2L_SRC_SHIFT,\n+\t\t\t    madera_inmux_texts);\n+\n+static SOC_ENUM_SINGLE_DECL(madera_in2muxr_enum,\n+\t\t\t    MADERA_ADC_DIGITAL_VOLUME_2R,\n+\t\t\t    MADERA_IN2R_SRC_SHIFT,\n+\t\t\t    madera_inmux_texts);\n+\n+const struct snd_kcontrol_new madera_inmux[] = {\n+\tSOC_DAPM_ENUM_EXT(\"IN1L Mux\", madera_in1muxl_enum,\n+\t\t\t  snd_soc_dapm_get_enum_double, madera_inmux_put),\n+\tSOC_DAPM_ENUM_EXT(\"IN1R Mux\", madera_in1muxr_enum,\n+\t\t\t  snd_soc_dapm_get_enum_double, madera_inmux_put),\n+\tSOC_DAPM_ENUM_EXT(\"IN2L Mux\", madera_in2muxl_enum,\n+\t\t\t  snd_soc_dapm_get_enum_double, madera_inmux_put),\n+\tSOC_DAPM_ENUM_EXT(\"IN2R Mux\", madera_in2muxr_enum,\n+\t\t\t  snd_soc_dapm_get_enum_double, madera_inmux_put),\n+};\n+EXPORT_SYMBOL_GPL(madera_inmux);\n+\n+static bool madera_can_change_grp_rate(const struct madera_priv *priv,\n+\t\t\t\t       unsigned int reg)\n+{\n+\tint count;\n+\n+\tswitch (reg) {\n+\tcase MADERA_FX_CTRL1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_FX];\n+\t\tbreak;\n+\tcase MADERA_ASRC1_RATE1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ASRC1_RATE_1];\n+\t\tbreak;\n+\tcase MADERA_ASRC1_RATE2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ASRC1_RATE_2];\n+\t\tbreak;\n+\tcase MADERA_ASRC2_RATE1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ASRC2_RATE_1];\n+\t\tbreak;\n+\tcase MADERA_ASRC2_RATE2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ASRC2_RATE_2];\n+\t\tbreak;\n+\tcase MADERA_ISRC_1_CTRL_1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC1_INT];\n+\t\tbreak;\n+\tcase MADERA_ISRC_1_CTRL_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC1_DEC];\n+\t\tbreak;\n+\tcase MADERA_ISRC_2_CTRL_1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC2_INT];\n+\t\tbreak;\n+\tcase MADERA_ISRC_2_CTRL_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC2_DEC];\n+\t\tbreak;\n+\tcase MADERA_ISRC_3_CTRL_1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC3_INT];\n+\t\tbreak;\n+\tcase MADERA_ISRC_3_CTRL_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC3_DEC];\n+\t\tbreak;\n+\tcase MADERA_ISRC_4_CTRL_1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC4_INT];\n+\t\tbreak;\n+\tcase MADERA_ISRC_4_CTRL_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_ISRC4_DEC];\n+\t\tbreak;\n+\tcase MADERA_OUTPUT_RATE_1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_OUT];\n+\t\tbreak;\n+\tcase MADERA_SPD1_TX_CONTROL:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_SPD];\n+\t\tbreak;\n+\tcase MADERA_DSP1_CONFIG_1:\n+\tcase MADERA_DSP1_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP1];\n+\t\tbreak;\n+\tcase MADERA_DSP2_CONFIG_1:\n+\tcase MADERA_DSP2_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP2];\n+\t\tbreak;\n+\tcase MADERA_DSP3_CONFIG_1:\n+\tcase MADERA_DSP3_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP3];\n+\t\tbreak;\n+\tcase MADERA_DSP4_CONFIG_1:\n+\tcase MADERA_DSP4_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP4];\n+\t\tbreak;\n+\tcase MADERA_DSP5_CONFIG_1:\n+\tcase MADERA_DSP5_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP5];\n+\t\tbreak;\n+\tcase MADERA_DSP6_CONFIG_1:\n+\tcase MADERA_DSP6_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP6];\n+\t\tbreak;\n+\tcase MADERA_DSP7_CONFIG_1:\n+\tcase MADERA_DSP7_CONFIG_2:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_DSP7];\n+\t\tbreak;\n+\tcase MADERA_AIF1_RATE_CTRL:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_AIF1];\n+\t\tbreak;\n+\tcase MADERA_AIF2_RATE_CTRL:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_AIF2];\n+\t\tbreak;\n+\tcase MADERA_AIF3_RATE_CTRL:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_AIF3];\n+\t\tbreak;\n+\tcase MADERA_AIF4_RATE_CTRL:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_AIF4];\n+\t\tbreak;\n+\tcase MADERA_SLIMBUS_RATES_1:\n+\tcase MADERA_SLIMBUS_RATES_2:\n+\tcase MADERA_SLIMBUS_RATES_3:\n+\tcase MADERA_SLIMBUS_RATES_4:\n+\tcase MADERA_SLIMBUS_RATES_5:\n+\tcase MADERA_SLIMBUS_RATES_6:\n+\tcase MADERA_SLIMBUS_RATES_7:\n+\tcase MADERA_SLIMBUS_RATES_8:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_SLIMBUS];\n+\t\tbreak;\n+\tcase MADERA_PWM_DRIVE_1:\n+\t\tcount = priv->domain_group_ref[MADERA_DOM_GRP_PWM];\n+\t\tbreak;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+\n+\tdev_dbg(priv->madera->dev, \"Rate reg 0x%x group ref %d\\n\", reg, count);\n+\n+\tif (count)\n+\t\treturn false;\n+\telse\n+\t\treturn true;\n+}\n+\n+int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,\n+\t\t\t struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\n+\tunsigned int cached_rate;\n+\tconst int adsp_num = e->shift_l;\n+\tint item;\n+\n+\tmutex_lock(&priv->rate_lock);\n+\tcached_rate = priv->adsp_rate_cache[adsp_num];\n+\tmutex_unlock(&priv->rate_lock);\n+\n+\titem = snd_soc_enum_val_to_item(e, cached_rate);\n+\tucontrol->value.enumerated.item[0] = item;\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_adsp_rate_get);\n+\n+int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,\n+\t\t\t struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\n+\tconst int adsp_num = e->shift_l;\n+\tconst unsigned int item = ucontrol->value.enumerated.item[0];\n+\tint ret;\n+\n+\tif (item >= e->items)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * We don't directly write the rate register here but we want to\n+\t * maintain consistent behaviour that rate domains cannot be changed\n+\t * while in use since this is a hardware requirement\n+\t */\n+\tmutex_lock(&priv->rate_lock);\n+\n+\tif (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].base)) {\n+\t\tdev_warn(priv->madera->dev,\n+\t\t\t \"Cannot change '%s' while in use by active audio paths\\n\",\n+\t\t\t kcontrol->id.name);\n+\t\tret = -EBUSY;\n+\t} else {\n+\t\t/* Volatile register so defer until the codec is powered up */\n+\t\tpriv->adsp_rate_cache[adsp_num] = e->values[item];\n+\t\tret = 0;\n+\t}\n+\n+\tmutex_unlock(&priv->rate_lock);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_adsp_rate_put);\n+\n+static const struct soc_enum madera_adsp_rate_enum[] = {\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 1, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 2, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 3, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 4, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 5, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 6, 0xf, MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+};\n+\n+const struct snd_kcontrol_new madera_adsp_rate_controls[] = {\n+\tSOC_ENUM_EXT(\"DSP1 Rate\", madera_adsp_rate_enum[0],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+\tSOC_ENUM_EXT(\"DSP2 Rate\", madera_adsp_rate_enum[1],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+\tSOC_ENUM_EXT(\"DSP3 Rate\", madera_adsp_rate_enum[2],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+\tSOC_ENUM_EXT(\"DSP4 Rate\", madera_adsp_rate_enum[3],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+\tSOC_ENUM_EXT(\"DSP5 Rate\", madera_adsp_rate_enum[4],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+\tSOC_ENUM_EXT(\"DSP6 Rate\", madera_adsp_rate_enum[5],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+\tSOC_ENUM_EXT(\"DSP7 Rate\", madera_adsp_rate_enum[6],\n+\t\t     madera_adsp_rate_get, madera_adsp_rate_put),\n+};\n+EXPORT_SYMBOL_GPL(madera_adsp_rate_controls);\n+\n+static int madera_write_adsp_clk_setting(struct madera_priv *priv,\n+\t\t\t\t\t struct wm_adsp *dsp,\n+\t\t\t\t\t unsigned int freq)\n+{\n+\tunsigned int val;\n+\tunsigned int mask = MADERA_DSP_RATE_MASK;\n+\tint ret;\n+\n+\t/*\n+\t * Take snapshot of rate. There will always be a race condition\n+\t * between this code and setting the rate control. Wrapping the entire\n+\t * function in the lock won't change that so don't bother\n+\t */\n+\tmutex_lock(&priv->rate_lock);\n+\tval = priv->adsp_rate_cache[dsp->num - 1] << MADERA_DSP_RATE_SHIFT;\n+\tmutex_unlock(&priv->rate_lock);\n+\n+\tswitch (priv->madera->type) {\n+\tcase CS47L35:\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\t/* use legacy frequency registers */\n+\t\tmask |= MADERA_DSP_CLK_SEL_MASK;\n+\t\tval |= (freq << MADERA_DSP_CLK_SEL_SHIFT);\n+\t\tbreak;\n+\tdefault:\n+\t\t/* Configure exact dsp frequency */\n+\t\tdev_dbg(priv->madera->dev, \"Set DSP frequency to 0x%x\\n\", freq);\n+\n+\t\tret = regmap_write(dsp->regmap,\n+\t\t\t\t   dsp->base + MADERA_DSP_CONFIG_2_OFFS, freq);\n+\t\tif (ret)\n+\t\t\tgoto err;\n+\t\tbreak;\n+\t}\n+\n+\tret = regmap_update_bits(dsp->regmap,\n+\t\t\t\t dsp->base + MADERA_DSP_CONFIG_1_OFFS,\n+\t\t\t\t mask, val);\n+\n+\tdev_dbg(priv->madera->dev, \"Set DSP clocking to 0x%x\\n\", val);\n+\n+\treturn 0;\n+\n+err:\n+\tdev_err(dsp->dev, \"Failed to set DSP%d clock: %d\\n\", dsp->num, ret);\n+\n+\treturn ret;\n+}\n+\n+int madera_set_adsp_clk(struct madera_priv *priv, int dsp_num,\n+\t\t\tunsigned int freq)\n+{\n+\tstruct wm_adsp *dsp = &priv->adsp[dsp_num];\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int cur, new;\n+\tint ret;\n+\n+\t/*\n+\t * This is called at a higher DAPM priority than the mux widgets so\n+\t * the muxes are still off at this point and it's safe to change\n+\t * the rate domain control\n+\t */\n+\n+\tret = regmap_read(dsp->regmap,  dsp->base, &cur);\n+\tif (ret) {\n+\t\tdev_err(madera->dev,\n+\t\t\t\"Failed to read current DSP rate: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tcur &= MADERA_DSP_RATE_MASK;\n+\n+\tmutex_lock(&priv->rate_lock);\n+\tnew = priv->adsp_rate_cache[dsp->num - 1] << MADERA_DSP_RATE_SHIFT;\n+\tmutex_unlock(&priv->rate_lock);\n+\n+\tif (new == cur) {\n+\t\tdev_dbg(madera->dev, \"DSP rate not changed\\n\");\n+\t\treturn madera_write_adsp_clk_setting(priv, dsp, freq);\n+\t} else {\n+\t\tdev_dbg(madera->dev, \"DSP rate changed\\n\");\n+\n+\t\t/* The write must be guarded by a number of SYSCLK cycles */\n+\t\tmadera_spin_sysclk(priv);\n+\t\tret = madera_write_adsp_clk_setting(priv, dsp, freq);\n+\t\tmadera_spin_sysclk(priv);\n+\t\treturn ret;\n+\t}\n+}\n+EXPORT_SYMBOL_GPL(madera_set_adsp_clk);\n+\n+int madera_rate_put(struct snd_kcontrol *kcontrol,\n+\t\t    struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\n+\tunsigned int item = ucontrol->value.enumerated.item[0];\n+\tunsigned int val;\n+\tint ret;\n+\n+\tif (item >= e->items)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * Prevent the domain powering up while we're checking whether it's\n+\t * safe to change rate domain\n+\t */\n+\tmutex_lock(&priv->rate_lock);\n+\n+\tret = snd_soc_component_read(dapm->component, e->reg, &val);\n+\tif (ret < 0) {\n+\t\tdev_warn(priv->madera->dev, \"Failed to read 0x%x (%d)\\n\",\n+\t\t\t e->reg, ret);\n+\t\tgoto out;\n+\t}\n+\tval >>= e->shift_l;\n+\tval &= e->mask;\n+\tif (snd_soc_enum_item_to_val(e, item) == val) {\n+\t\tret = 0;\n+\t\tgoto out;\n+\t}\n+\n+\tif (!madera_can_change_grp_rate(priv, e->reg)) {\n+\t\tdev_warn(priv->madera->dev,\n+\t\t\t \"Cannot change '%s' while in use by active audio paths\\n\",\n+\t\t\t kcontrol->id.name);\n+\t\tret = -EBUSY;\n+\t} else {\n+\t\t/* The write must be guarded by a number of SYSCLK cycles */\n+\t\tmadera_spin_sysclk(priv);\n+\t\tret = snd_soc_put_enum_double(kcontrol, ucontrol);\n+\t\tmadera_spin_sysclk(priv);\n+\t}\n+out:\n+\tmutex_unlock(&priv->rate_lock);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_rate_put);\n+\n+static void madera_configure_input_mode(struct madera *madera)\n+{\n+\tunsigned int dig_mode, ana_mode_l, ana_mode_r;\n+\tint max_analogue_inputs, i;\n+\n+\tswitch (madera->type) {\n+\tcase CS47L35:\n+\t\tmax_analogue_inputs = 2;\n+\t\tbreak;\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\tmax_analogue_inputs = 3;\n+\t\tbreak;\n+\tdefault:\n+\t\tmax_analogue_inputs = 2;\n+\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * Initialize input modes from the A settings. For muxed inputs the\n+\t * B settings will be applied if the mux is changed\n+\t */\n+\tfor (i = 0; i < max_analogue_inputs; i++) {\n+\t\tdev_dbg(madera->dev, \"IN%d mode %u:%u:%u:%u\\n\", i + 1,\n+\t\t\tmadera->pdata.codec.inmode[i][0],\n+\t\t\tmadera->pdata.codec.inmode[i][1],\n+\t\t\tmadera->pdata.codec.inmode[i][2],\n+\t\t\tmadera->pdata.codec.inmode[i][3]);\n+\n+\t\tdig_mode = madera->pdata.codec.dmic_ref[i] <<\n+\t\t\t   MADERA_IN1_DMIC_SUP_SHIFT;\n+\n+\t\tswitch (madera->pdata.codec.inmode[i][0]) {\n+\t\tcase MADERA_INMODE_DIFF:\n+\t\t\tana_mode_l = 0;\n+\t\t\tbreak;\n+\t\tcase MADERA_INMODE_SE:\n+\t\t\tana_mode_l = 1 << MADERA_IN1L_SRC_SE_SHIFT;\n+\t\t\tbreak;\n+\t\tcase MADERA_INMODE_DMIC:\n+\t\t\tana_mode_l = 0;\n+\t\t\tdig_mode |= 1 << MADERA_IN1_MODE_SHIFT;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tdev_warn(madera->dev,\n+\t\t\t\t \"IN%dAL Illegal inmode %u ignored\\n\",\n+\t\t\t\t i + 1, madera->pdata.codec.inmode[i][0]);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tswitch (madera->pdata.codec.inmode[i][1]) {\n+\t\tcase MADERA_INMODE_DIFF:\n+\t\tcase MADERA_INMODE_DMIC:\n+\t\t\tana_mode_r = 0;\n+\t\t\tbreak;\n+\t\tcase MADERA_INMODE_SE:\n+\t\t\tana_mode_r = 1 << MADERA_IN1R_SRC_SE_SHIFT;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tdev_warn(madera->dev,\n+\t\t\t\t \"IN%dAR Illegal inmode %u ignored\\n\",\n+\t\t\t\t i + 1, madera->pdata.codec.inmode[i][1]);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tdev_dbg(madera->dev,\n+\t\t\t\"IN%dA DMIC mode=0x%x Analogue mode=0x%x,0x%x\\n\",\n+\t\t\ti + 1, dig_mode, ana_mode_l, ana_mode_r);\n+\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   MADERA_IN1L_CONTROL + (i * 8),\n+\t\t\t\t   MADERA_IN1_DMIC_SUP_MASK |\n+\t\t\t\t   MADERA_IN1_MODE_MASK,\n+\t\t\t\t   dig_mode);\n+\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   MADERA_ADC_DIGITAL_VOLUME_1L + (i * 8),\n+\t\t\t\t   MADERA_IN1L_SRC_SE_MASK, ana_mode_l);\n+\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   MADERA_ADC_DIGITAL_VOLUME_1R + (i * 8),\n+\t\t\t\t   MADERA_IN1R_SRC_SE_MASK, ana_mode_r);\n+\t}\n+}\n+\n+int madera_init_inputs(struct snd_soc_codec *codec,\n+\t\t       const char * const *dmic_inputs, int n_dmic_inputs,\n+\t\t       const char * const *dmic_refs, int n_dmic_refs)\n+{\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int ref;\n+\tint i, ret;\n+\tstruct snd_soc_dapm_route routes[2];\n+\n+\tmemset(&routes, 0, sizeof(routes));\n+\n+\tmadera_configure_input_mode(madera);\n+\n+\tfor (i = 0; i < n_dmic_inputs / 2; ++i) {\n+\t\tref = madera->pdata.codec.dmic_ref[i];\n+\t\tif (ref >= n_dmic_refs) {\n+\t\t\tdev_err(madera->dev,\n+\t\t\t\t\"Illegal DMIC ref %u for IN%d\\n\", ref, i);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\troutes[0].source = dmic_refs[ref];\n+\t\troutes[1].source = dmic_refs[ref];\n+\t\troutes[0].sink = dmic_inputs[i * 2];\n+\t\troutes[1].sink = dmic_inputs[(i * 2) + 1];\n+\n+\t\tret = snd_soc_dapm_add_routes(dapm, routes, 2);\n+\t\tif (ret)\n+\t\t\tdev_warn(madera->dev,\n+\t\t\t\t \"Failed to add routes for %s->(%s,%s) (%d)\\n\",\n+\t\t\t\t routes[0].source,\n+\t\t\t\t routes[0].sink,\n+\t\t\t\t routes[1].sink,\n+\t\t\t\t ret);\n+\t}\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_init_inputs);\n+\n+static const struct snd_soc_dapm_route madera_mono_routes[] = {\n+\t{ \"OUT1R\", NULL, \"OUT1L\" },\n+\t{ \"OUT2R\", NULL, \"OUT2L\" },\n+\t{ \"OUT3R\", NULL, \"OUT3L\" },\n+\t{ \"OUT4R\", NULL, \"OUT4L\" },\n+\t{ \"OUT5R\", NULL, \"OUT5L\" },\n+\t{ \"OUT6R\", NULL, \"OUT6L\" },\n+};\n+\n+int madera_init_outputs(struct snd_soc_codec *codec, int n_mono_routes)\n+{\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tconst struct madera_codec_pdata *pdata = &madera->pdata.codec;\n+\tunsigned int val;\n+\tint i;\n+\n+\tif (n_mono_routes > MADERA_MAX_OUTPUT) {\n+\t\tdev_warn(madera->dev,\n+\t\t\t \"Requested %d mono outputs, using maximum allowed %d\\n\",\n+\t\t\t n_mono_routes, MADERA_MAX_OUTPUT);\n+\t\tn_mono_routes = MADERA_MAX_OUTPUT;\n+\t}\n+\n+\tfor (i = 0; i < n_mono_routes; i++) {\n+\t\t/* Default is 0 so noop with defaults */\n+\t\tif (pdata->out_mono[i]) {\n+\t\t\tval = MADERA_OUT1_MONO;\n+\t\t\tsnd_soc_dapm_add_routes(dapm,\n+\t\t\t\t\t\t&madera_mono_routes[i], 1);\n+\t\t} else {\n+\t\t\tval = 0;\n+\t\t}\n+\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   MADERA_OUTPUT_PATH_CONFIG_1L + (i * 8),\n+\t\t\t\t   MADERA_OUT1_MONO, val);\n+\n+\t\tdev_dbg(madera->dev, \"OUT%d mono=0x%x\\n\", i + 1, val);\n+\t}\n+\n+\tfor (i = 0; i < MADERA_MAX_PDM_SPK; i++) {\n+\t\tdev_dbg(madera->dev, \"PDM%d fmt=0x%x mute=0x%x\\n\", i + 1,\n+\t\t\tpdata->pdm_fmt[i], pdata->pdm_mute[i]);\n+\n+\t\tif (pdata->pdm_mute[i])\n+\t\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t\t   MADERA_PDM_SPK1_CTRL_1 + (i * 2),\n+\t\t\t\t\t   MADERA_SPK1_MUTE_ENDIAN_MASK |\n+\t\t\t\t\t   MADERA_SPK1_MUTE_SEQ1_MASK,\n+\t\t\t\t\t   pdata->pdm_mute[i]);\n+\n+\t\tif (pdata->pdm_fmt[i])\n+\t\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t\t   MADERA_PDM_SPK1_CTRL_2 + (i * 2),\n+\t\t\t\t\t   MADERA_SPK1_FMT_MASK,\n+\t\t\t\t\t   pdata->pdm_fmt[i]);\n+\t}\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_init_outputs);\n+\n+int madera_init_bus_error_irq(struct madera_priv *priv, int dsp_num,\n+\t\t\t      irq_handler_t handler)\n+{\n+\tstruct madera *madera = priv->madera;\n+\tint ret;\n+\n+\tret = madera_request_irq(madera,\n+\t\t\t\t madera_dsp_bus_error_irqs[dsp_num],\n+\t\t\t\t \"ADSP2 bus error\",\n+\t\t\t\t handler,\n+\t\t\t\t &priv->adsp[dsp_num]);\n+\tif (ret)\n+\t\tdev_err(madera->dev,\n+\t\t\t\"Failed to request DSP Lock region IRQ: %d\\n\", ret);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_init_bus_error_irq);\n+\n+void madera_destroy_bus_error_irq(struct madera_priv *priv, int dsp_num)\n+{\n+\tstruct madera *madera = priv->madera;\n+\n+\tmadera_free_irq(madera,\n+\t\t\tmadera_dsp_bus_error_irqs[dsp_num],\n+\t\t\t&priv->adsp[dsp_num]);\n+}\n+EXPORT_SYMBOL_GPL(madera_destroy_bus_error_irq);\n+\n+const char * const madera_mixer_texts[] = {\n+\t\"None\",\n+\t\"Tone Generator 1\",\n+\t\"Tone Generator 2\",\n+\t\"Haptics\",\n+\t\"AEC1\",\n+\t\"AEC2\",\n+\t\"Mic Mute Mixer\",\n+\t\"Noise Generator\",\n+\t\"IN1L\",\n+\t\"IN1R\",\n+\t\"IN2L\",\n+\t\"IN2R\",\n+\t\"IN3L\",\n+\t\"IN3R\",\n+\t\"IN4L\",\n+\t\"IN4R\",\n+\t\"IN5L\",\n+\t\"IN5R\",\n+\t\"IN6L\",\n+\t\"IN6R\",\n+\t\"AIF1RX1\",\n+\t\"AIF1RX2\",\n+\t\"AIF1RX3\",\n+\t\"AIF1RX4\",\n+\t\"AIF1RX5\",\n+\t\"AIF1RX6\",\n+\t\"AIF1RX7\",\n+\t\"AIF1RX8\",\n+\t\"AIF2RX1\",\n+\t\"AIF2RX2\",\n+\t\"AIF2RX3\",\n+\t\"AIF2RX4\",\n+\t\"AIF2RX5\",\n+\t\"AIF2RX6\",\n+\t\"AIF2RX7\",\n+\t\"AIF2RX8\",\n+\t\"AIF3RX1\",\n+\t\"AIF3RX2\",\n+\t\"AIF4RX1\",\n+\t\"AIF4RX2\",\n+\t\"SLIMRX1\",\n+\t\"SLIMRX2\",\n+\t\"SLIMRX3\",\n+\t\"SLIMRX4\",\n+\t\"SLIMRX5\",\n+\t\"SLIMRX6\",\n+\t\"SLIMRX7\",\n+\t\"SLIMRX8\",\n+\t\"EQ1\",\n+\t\"EQ2\",\n+\t\"EQ3\",\n+\t\"EQ4\",\n+\t\"DRC1L\",\n+\t\"DRC1R\",\n+\t\"DRC2L\",\n+\t\"DRC2R\",\n+\t\"LHPF1\",\n+\t\"LHPF2\",\n+\t\"LHPF3\",\n+\t\"LHPF4\",\n+\t\"DSP1.1\",\n+\t\"DSP1.2\",\n+\t\"DSP1.3\",\n+\t\"DSP1.4\",\n+\t\"DSP1.5\",\n+\t\"DSP1.6\",\n+\t\"DSP2.1\",\n+\t\"DSP2.2\",\n+\t\"DSP2.3\",\n+\t\"DSP2.4\",\n+\t\"DSP2.5\",\n+\t\"DSP2.6\",\n+\t\"DSP3.1\",\n+\t\"DSP3.2\",\n+\t\"DSP3.3\",\n+\t\"DSP3.4\",\n+\t\"DSP3.5\",\n+\t\"DSP3.6\",\n+\t\"DSP4.1\",\n+\t\"DSP4.2\",\n+\t\"DSP4.3\",\n+\t\"DSP4.4\",\n+\t\"DSP4.5\",\n+\t\"DSP4.6\",\n+\t\"DSP5.1\",\n+\t\"DSP5.2\",\n+\t\"DSP5.3\",\n+\t\"DSP5.4\",\n+\t\"DSP5.5\",\n+\t\"DSP5.6\",\n+\t\"DSP6.1\",\n+\t\"DSP6.2\",\n+\t\"DSP6.3\",\n+\t\"DSP6.4\",\n+\t\"DSP6.5\",\n+\t\"DSP6.6\",\n+\t\"DSP7.1\",\n+\t\"DSP7.2\",\n+\t\"DSP7.3\",\n+\t\"DSP7.4\",\n+\t\"DSP7.5\",\n+\t\"DSP7.6\",\n+\t\"ASRC1IN1L\",\n+\t\"ASRC1IN1R\",\n+\t\"ASRC1IN2L\",\n+\t\"ASRC1IN2R\",\n+\t\"ASRC2IN1L\",\n+\t\"ASRC2IN1R\",\n+\t\"ASRC2IN2L\",\n+\t\"ASRC2IN2R\",\n+\t\"ISRC1INT1\",\n+\t\"ISRC1INT2\",\n+\t\"ISRC1INT3\",\n+\t\"ISRC1INT4\",\n+\t\"ISRC1DEC1\",\n+\t\"ISRC1DEC2\",\n+\t\"ISRC1DEC3\",\n+\t\"ISRC1DEC4\",\n+\t\"ISRC2INT1\",\n+\t\"ISRC2INT2\",\n+\t\"ISRC2INT3\",\n+\t\"ISRC2INT4\",\n+\t\"ISRC2DEC1\",\n+\t\"ISRC2DEC2\",\n+\t\"ISRC2DEC3\",\n+\t\"ISRC2DEC4\",\n+\t\"ISRC3INT1\",\n+\t\"ISRC3INT2\",\n+\t\"ISRC3INT3\",\n+\t\"ISRC3INT4\",\n+\t\"ISRC3DEC1\",\n+\t\"ISRC3DEC2\",\n+\t\"ISRC3DEC3\",\n+\t\"ISRC3DEC4\",\n+\t\"ISRC4INT1\",\n+\t\"ISRC4INT2\",\n+\t\"ISRC4DEC1\",\n+\t\"ISRC4DEC2\",\n+\t\"DFC1\",\n+\t\"DFC2\",\n+\t\"DFC3\",\n+\t\"DFC4\",\n+\t\"DFC5\",\n+\t\"DFC6\",\n+\t\"DFC7\",\n+\t\"DFC8\",\n+};\n+EXPORT_SYMBOL_GPL(madera_mixer_texts);\n+\n+unsigned int madera_mixer_values[] = {\n+\t0x00,\t/* None */\n+\t0x04,\t/* Tone Generator 1 */\n+\t0x05,\t/* Tone Generator 2 */\n+\t0x06,\t/* Haptics */\n+\t0x08,\t/* AEC */\n+\t0x09,\t/* AEC2 */\n+\t0x0c,\t/* Noise mixer */\n+\t0x0d,\t/* Comfort noise */\n+\t0x10,\t/* IN1L */\n+\t0x11,\n+\t0x12,\n+\t0x13,\n+\t0x14,\n+\t0x15,\n+\t0x16,\n+\t0x17,\n+\t0x18,\n+\t0x19,\n+\t0x1A,\n+\t0x1B,\n+\t0x20,\t/* AIF1RX1 */\n+\t0x21,\n+\t0x22,\n+\t0x23,\n+\t0x24,\n+\t0x25,\n+\t0x26,\n+\t0x27,\n+\t0x28,\t/* AIF2RX1 */\n+\t0x29,\n+\t0x2a,\n+\t0x2b,\n+\t0x2c,\n+\t0x2d,\n+\t0x2e,\n+\t0x2f,\n+\t0x30,\t/* AIF3RX1 */\n+\t0x31,\n+\t0x34,\t/* AIF4RX1 */\n+\t0x35,\n+\t0x38,\t/* SLIMRX1 */\n+\t0x39,\n+\t0x3a,\n+\t0x3b,\n+\t0x3c,\n+\t0x3d,\n+\t0x3e,\n+\t0x3f,\n+\t0x50,\t/* EQ1 */\n+\t0x51,\n+\t0x52,\n+\t0x53,\n+\t0x58,\t/* DRC1L */\n+\t0x59,\n+\t0x5a,\n+\t0x5b,\n+\t0x60,\t/* LHPF1 */\n+\t0x61,\n+\t0x62,\n+\t0x63,\n+\t0x68,\t/* DSP1.1 */\n+\t0x69,\n+\t0x6a,\n+\t0x6b,\n+\t0x6c,\n+\t0x6d,\n+\t0x70,\t/* DSP2.1 */\n+\t0x71,\n+\t0x72,\n+\t0x73,\n+\t0x74,\n+\t0x75,\n+\t0x78,\t/* DSP3.1 */\n+\t0x79,\n+\t0x7a,\n+\t0x7b,\n+\t0x7c,\n+\t0x7d,\n+\t0x80,\t/* DSP4.1 */\n+\t0x81,\n+\t0x82,\n+\t0x83,\n+\t0x84,\n+\t0x85,\n+\t0x88,\t/* DSP5.1 */\n+\t0x89,\n+\t0x8a,\n+\t0x8b,\n+\t0x8c,\n+\t0x8d,\n+\t0xc0,\t/* DSP6.1 */\n+\t0xc1,\n+\t0xc2,\n+\t0xc3,\n+\t0xc4,\n+\t0xc5,\n+\t0xc8,\t/* DSP7.1 */\n+\t0xc9,\n+\t0xca,\n+\t0xcb,\n+\t0xcc,\n+\t0xcd,\n+\t0x90,\t/* ASRC1IN1L */\n+\t0x91,\n+\t0x92,\n+\t0x93,\n+\t0x94,\t/* ASRC2IN1L */\n+\t0x95,\n+\t0x96,\n+\t0x97,\n+\t0xa0,\t/* ISRC1INT1 */\n+\t0xa1,\n+\t0xa2,\n+\t0xa3,\n+\t0xa4,\t/* ISRC1DEC1 */\n+\t0xa5,\n+\t0xa6,\n+\t0xa7,\n+\t0xa8,\t/* ISRC2DEC1 */\n+\t0xa9,\n+\t0xaa,\n+\t0xab,\n+\t0xac,\t/* ISRC2INT1 */\n+\t0xad,\n+\t0xae,\n+\t0xaf,\n+\t0xb0,\t/* ISRC3DEC1 */\n+\t0xb1,\n+\t0xb2,\n+\t0xb3,\n+\t0xb4,\t/* ISRC3INT1 */\n+\t0xb5,\n+\t0xb6,\n+\t0xb7,\n+\t0xb8,\t/* ISRC4INT1 */\n+\t0xb9,\n+\t0xbc,\t/* ISRC4DEC1 */\n+\t0xbd,\n+\t0xf8,\t/* DFC1 */\n+\t0xf9,\n+\t0xfa,\n+\t0xfb,\n+\t0xfc,\n+\t0xfd,\n+\t0xfe,\n+\t0xff,\t/* DFC8 */\n+};\n+EXPORT_SYMBOL_GPL(madera_mixer_values);\n+\n+const DECLARE_TLV_DB_SCALE(madera_ana_tlv, 0, 100, 0);\n+EXPORT_SYMBOL_GPL(madera_ana_tlv);\n+\n+const DECLARE_TLV_DB_SCALE(madera_eq_tlv, -1200, 100, 0);\n+EXPORT_SYMBOL_GPL(madera_eq_tlv);\n+\n+const DECLARE_TLV_DB_SCALE(madera_digital_tlv, -6400, 50, 0);\n+EXPORT_SYMBOL_GPL(madera_digital_tlv);\n+\n+const DECLARE_TLV_DB_SCALE(madera_noise_tlv, -13200, 600, 0);\n+EXPORT_SYMBOL_GPL(madera_noise_tlv);\n+\n+const DECLARE_TLV_DB_SCALE(madera_ng_tlv, -12000, 600, 0);\n+EXPORT_SYMBOL_GPL(madera_ng_tlv);\n+\n+const DECLARE_TLV_DB_SCALE(madera_mixer_tlv, -3200, 100, 0);\n+EXPORT_SYMBOL_GPL(madera_mixer_tlv);\n+\n+const char * const madera_sample_rate_text[MADERA_SAMPLE_RATE_ENUM_SIZE] = {\n+\t\"12kHz\", \"24kHz\", \"48kHz\", \"96kHz\", \"192kHz\", \"384kHz\",\n+\t\"11.025kHz\", \"22.05kHz\", \"44.1kHz\", \"88.2kHz\", \"176.4kHz\", \"352.8kHz\",\n+\t\"4kHz\", \"8kHz\", \"16kHz\", \"32kHz\",\n+};\n+EXPORT_SYMBOL_GPL(madera_sample_rate_text);\n+\n+const unsigned int madera_sample_rate_val[MADERA_SAMPLE_RATE_ENUM_SIZE] = {\n+\t0x01, 0x02, 0x03, 0x04, 0x05, 0x06,\n+\t0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,\n+\t0x10, 0x11, 0x12, 0x13,\n+};\n+EXPORT_SYMBOL_GPL(madera_sample_rate_val);\n+\n+const char *madera_sample_rate_val_to_name(unsigned int rate_val)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(madera_sample_rate_val); ++i) {\n+\t\tif (madera_sample_rate_val[i] == rate_val)\n+\t\t\treturn madera_sample_rate_text[i];\n+\t}\n+\n+\treturn \"Illegal\";\n+}\n+EXPORT_SYMBOL_GPL(madera_sample_rate_val_to_name);\n+\n+const struct soc_enum madera_sample_rate[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_SAMPLE_RATE_2,\n+\t\t\t      MADERA_SAMPLE_RATE_2_SHIFT, 0x1f,\n+\t\t\t      MADERA_SAMPLE_RATE_ENUM_SIZE,\n+\t\t\t      madera_sample_rate_text,\n+\t\t\t      madera_sample_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_SAMPLE_RATE_3,\n+\t\t\t      MADERA_SAMPLE_RATE_3_SHIFT, 0x1f,\n+\t\t\t      MADERA_SAMPLE_RATE_ENUM_SIZE,\n+\t\t\t      madera_sample_rate_text,\n+\t\t\t      madera_sample_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ASYNC_SAMPLE_RATE_2,\n+\t\t\t      MADERA_ASYNC_SAMPLE_RATE_2_SHIFT, 0x1f,\n+\t\t\t      MADERA_SAMPLE_RATE_ENUM_SIZE,\n+\t\t\t      madera_sample_rate_text,\n+\t\t\t      madera_sample_rate_val),\n+\n+};\n+EXPORT_SYMBOL_GPL(madera_sample_rate);\n+\n+const char * const madera_rate_text[MADERA_RATE_ENUM_SIZE] = {\n+\t\"SYNCCLK rate 1\", \"SYNCCLK rate 2\", \"SYNCCLK rate 3\",\n+\t\"ASYNCCLK rate 1\", \"ASYNCCLK rate 2\",\n+};\n+EXPORT_SYMBOL_GPL(madera_rate_text);\n+\n+const unsigned int madera_rate_val[MADERA_RATE_ENUM_SIZE] = {\n+\t0x0, 0x1, 0x2, 0x8, 0x9,\n+};\n+EXPORT_SYMBOL_GPL(madera_rate_val);\n+\n+const char * const madera_dfc_width_text[MADERA_DFC_WIDTH_ENUM_SIZE] = {\n+\t\"8bit\", \"16bit\", \"20bit\", \"24bit\", \"32bit\",\n+};\n+EXPORT_SYMBOL_GPL(madera_dfc_width_text);\n+\n+const unsigned int madera_dfc_width_val[MADERA_DFC_WIDTH_ENUM_SIZE] = {\n+\t7, 15, 19, 23, 31,\n+};\n+EXPORT_SYMBOL_GPL(madera_dfc_width_val);\n+\n+const char * const madera_dfc_type_text[MADERA_DFC_TYPE_ENUM_SIZE] = {\n+\t\"Fixed\", \"Unsigned Fixed\", \"Single Precision Floating\",\n+\t\"Half Precision Floating\", \"Arm Alternative Floating\",\n+};\n+EXPORT_SYMBOL_GPL(madera_dfc_type_text);\n+\n+const unsigned int madera_dfc_type_val[MADERA_DFC_TYPE_ENUM_SIZE] = {\n+\t0, 1, 2, 4, 5,\n+};\n+EXPORT_SYMBOL_GPL(madera_dfc_type_val);\n+\n+const struct soc_enum madera_dfc_width[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC1_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC1_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC2_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC2_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC3_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC3_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC4_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC4_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC5_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC5_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC6_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC6_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC7_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC7_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC8_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC8_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_WIDTH_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_width_text),\n+\t\t\t      madera_dfc_width_text,\n+\t\t\t      madera_dfc_width_val),\n+};\n+EXPORT_SYMBOL_GPL(madera_dfc_width);\n+\n+const struct soc_enum madera_dfc_type[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC1_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC1_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC2_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC2_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC3_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC3_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC4_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC4_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC5_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC5_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC6_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC6_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC7_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC7_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC8_RX,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_RX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DFC8_TX,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_MASK >>\n+\t\t\t      MADERA_DFC1_TX_DATA_TYPE_SHIFT,\n+\t\t\t      ARRAY_SIZE(madera_dfc_type_text),\n+\t\t\t      madera_dfc_type_text,\n+\t\t\t      madera_dfc_type_val),\n+};\n+EXPORT_SYMBOL_GPL(madera_dfc_type);\n+\n+const struct soc_enum madera_isrc_fsh[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_1_CTRL_1,\n+\t\t\t      MADERA_ISRC1_FSH_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_2_CTRL_1,\n+\t\t\t      MADERA_ISRC2_FSH_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_3_CTRL_1,\n+\t\t\t      MADERA_ISRC3_FSH_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_4_CTRL_1,\n+\t\t\t      MADERA_ISRC4_FSH_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\n+};\n+EXPORT_SYMBOL_GPL(madera_isrc_fsh);\n+\n+const struct soc_enum madera_isrc_fsl[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_1_CTRL_2,\n+\t\t\t      MADERA_ISRC1_FSL_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_2_CTRL_2,\n+\t\t\t      MADERA_ISRC2_FSL_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_3_CTRL_2,\n+\t\t\t      MADERA_ISRC3_FSL_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ISRC_4_CTRL_2,\n+\t\t\t      MADERA_ISRC4_FSL_SHIFT, 0xf,\n+\t\t\t      MADERA_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\n+};\n+EXPORT_SYMBOL_GPL(madera_isrc_fsl);\n+\n+const struct soc_enum madera_asrc1_rate[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE1,\n+\t\t\t      MADERA_ASRC1_RATE1_SHIFT, 0xf,\n+\t\t\t      MADERA_SYNC_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE2,\n+\t\t\t      MADERA_ASRC1_RATE1_SHIFT, 0xf,\n+\t\t\t      MADERA_ASYNC_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text + MADERA_SYNC_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_val + MADERA_SYNC_RATE_ENUM_SIZE),\n+\n+};\n+EXPORT_SYMBOL_GPL(madera_asrc1_rate);\n+\n+const struct soc_enum madera_asrc2_rate[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE1,\n+\t\t\t      MADERA_ASRC2_RATE1_SHIFT, 0xf,\n+\t\t\t      MADERA_SYNC_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text, madera_rate_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE2,\n+\t\t\t      MADERA_ASRC2_RATE2_SHIFT, 0xf,\n+\t\t\t      MADERA_ASYNC_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_text + MADERA_SYNC_RATE_ENUM_SIZE,\n+\t\t\t      madera_rate_val + MADERA_SYNC_RATE_ENUM_SIZE),\n+\n+};\n+EXPORT_SYMBOL_GPL(madera_asrc2_rate);\n+\n+static const char * const madera_vol_ramp_text[] = {\n+\t\"0ms/6dB\", \"0.5ms/6dB\", \"1ms/6dB\", \"2ms/6dB\", \"4ms/6dB\", \"8ms/6dB\",\n+\t\"15ms/6dB\", \"30ms/6dB\",\n+};\n+\n+SOC_ENUM_SINGLE_DECL(madera_in_vd_ramp,\n+\t\t     MADERA_INPUT_VOLUME_RAMP,\n+\t\t     MADERA_IN_VD_RAMP_SHIFT,\n+\t\t     madera_vol_ramp_text);\n+EXPORT_SYMBOL_GPL(madera_in_vd_ramp);\n+\n+SOC_ENUM_SINGLE_DECL(madera_in_vi_ramp,\n+\t\t     MADERA_INPUT_VOLUME_RAMP,\n+\t\t     MADERA_IN_VI_RAMP_SHIFT,\n+\t\t     madera_vol_ramp_text);\n+EXPORT_SYMBOL_GPL(madera_in_vi_ramp);\n+\n+SOC_ENUM_SINGLE_DECL(madera_out_vd_ramp,\n+\t\t     MADERA_OUTPUT_VOLUME_RAMP,\n+\t\t     MADERA_OUT_VD_RAMP_SHIFT,\n+\t\t     madera_vol_ramp_text);\n+EXPORT_SYMBOL_GPL(madera_out_vd_ramp);\n+\n+SOC_ENUM_SINGLE_DECL(madera_out_vi_ramp,\n+\t\t     MADERA_OUTPUT_VOLUME_RAMP,\n+\t\t     MADERA_OUT_VI_RAMP_SHIFT,\n+\t\t     madera_vol_ramp_text);\n+EXPORT_SYMBOL_GPL(madera_out_vi_ramp);\n+\n+static const char * const madera_lhpf_mode_text[] = {\n+\t\"Low-pass\", \"High-pass\"\n+};\n+\n+SOC_ENUM_SINGLE_DECL(madera_lhpf1_mode,\n+\t\t     MADERA_HPLPF1_1,\n+\t\t     MADERA_LHPF1_MODE_SHIFT,\n+\t\t     madera_lhpf_mode_text);\n+EXPORT_SYMBOL_GPL(madera_lhpf1_mode);\n+\n+SOC_ENUM_SINGLE_DECL(madera_lhpf2_mode,\n+\t\t     MADERA_HPLPF2_1,\n+\t\t     MADERA_LHPF2_MODE_SHIFT,\n+\t\t     madera_lhpf_mode_text);\n+EXPORT_SYMBOL_GPL(madera_lhpf2_mode);\n+\n+SOC_ENUM_SINGLE_DECL(madera_lhpf3_mode,\n+\t\t     MADERA_HPLPF3_1,\n+\t\t     MADERA_LHPF3_MODE_SHIFT,\n+\t\t     madera_lhpf_mode_text);\n+EXPORT_SYMBOL_GPL(madera_lhpf3_mode);\n+\n+SOC_ENUM_SINGLE_DECL(madera_lhpf4_mode,\n+\t\t     MADERA_HPLPF4_1,\n+\t\t     MADERA_LHPF4_MODE_SHIFT,\n+\t\t     madera_lhpf_mode_text);\n+EXPORT_SYMBOL_GPL(madera_lhpf4_mode);\n+\n+static const char * const madera_ng_hold_text[] = {\n+\t\"30ms\", \"120ms\", \"250ms\", \"500ms\",\n+};\n+\n+SOC_ENUM_SINGLE_DECL(madera_ng_hold,\n+\t\t     MADERA_NOISE_GATE_CONTROL,\n+\t\t     MADERA_NGATE_HOLD_SHIFT,\n+\t\t     madera_ng_hold_text);\n+EXPORT_SYMBOL_GPL(madera_ng_hold);\n+\n+static const char * const madera_in_hpf_cut_text[] = {\n+\t\"2.5Hz\", \"5Hz\", \"10Hz\", \"20Hz\", \"40Hz\"\n+};\n+\n+SOC_ENUM_SINGLE_DECL(madera_in_hpf_cut_enum,\n+\t\t     MADERA_HPF_CONTROL,\n+\t\t     MADERA_IN_HPF_CUT_SHIFT,\n+\t\t     madera_in_hpf_cut_text);\n+EXPORT_SYMBOL_GPL(madera_in_hpf_cut_enum);\n+\n+static const char * const madera_in_dmic_osr_text[MADERA_OSR_ENUM_SIZE] = {\n+\t\"384kHz\", \"768kHz\", \"1.536MHz\", \"3.072MHz\", \"6.144MHz\",\n+};\n+\n+static const unsigned int madera_in_dmic_osr_val[MADERA_OSR_ENUM_SIZE] = {\n+\t2, 3, 4, 5, 6,\n+};\n+\n+const struct soc_enum madera_in_dmic_osr[] = {\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DMIC1L_CONTROL, MADERA_IN1_OSR_SHIFT,\n+\t\t\t      0x7, MADERA_OSR_ENUM_SIZE,\n+\t\t\t      madera_in_dmic_osr_text, madera_in_dmic_osr_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DMIC2L_CONTROL, MADERA_IN2_OSR_SHIFT,\n+\t\t\t      0x7, MADERA_OSR_ENUM_SIZE,\n+\t\t\t      madera_in_dmic_osr_text, madera_in_dmic_osr_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DMIC3L_CONTROL, MADERA_IN3_OSR_SHIFT,\n+\t\t\t      0x7, MADERA_OSR_ENUM_SIZE,\n+\t\t\t      madera_in_dmic_osr_text, madera_in_dmic_osr_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DMIC4L_CONTROL, MADERA_IN4_OSR_SHIFT,\n+\t\t\t      0x7, MADERA_OSR_ENUM_SIZE,\n+\t\t\t      madera_in_dmic_osr_text, madera_in_dmic_osr_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DMIC5L_CONTROL, MADERA_IN5_OSR_SHIFT,\n+\t\t\t      0x7, MADERA_OSR_ENUM_SIZE,\n+\t\t\t      madera_in_dmic_osr_text, madera_in_dmic_osr_val),\n+\tSOC_VALUE_ENUM_SINGLE(MADERA_DMIC6L_CONTROL, MADERA_IN6_OSR_SHIFT,\n+\t\t\t      0x7, MADERA_OSR_ENUM_SIZE,\n+\t\t\t      madera_in_dmic_osr_text, madera_in_dmic_osr_val),\n+};\n+EXPORT_SYMBOL_GPL(madera_in_dmic_osr);\n+\n+static const char * const madera_anc_input_src_text[] = {\n+\t\"None\", \"IN1\", \"IN2\", \"IN3\", \"IN4\", \"IN5\", \"IN6\",\n+};\n+\n+static const char * const madera_anc_channel_src_text[] = {\n+\t\"None\", \"Left\", \"Right\", \"Combine\",\n+};\n+\n+const struct soc_enum madera_anc_input_src[] = {\n+\tSOC_ENUM_SINGLE(MADERA_ANC_SRC,\n+\t\t\tMADERA_IN_RXANCL_SEL_SHIFT,\n+\t\t\tARRAY_SIZE(madera_anc_input_src_text),\n+\t\t\tmadera_anc_input_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_FCL_ADC_REFORMATTER_CONTROL,\n+\t\t\tMADERA_FCL_MIC_MODE_SEL,\n+\t\t\tARRAY_SIZE(madera_anc_channel_src_text),\n+\t\t\tmadera_anc_channel_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_ANC_SRC,\n+\t\t\tMADERA_IN_RXANCR_SEL_SHIFT,\n+\t\t\tARRAY_SIZE(madera_anc_input_src_text),\n+\t\t\tmadera_anc_input_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_FCR_ADC_REFORMATTER_CONTROL,\n+\t\t\tMADERA_FCR_MIC_MODE_SEL,\n+\t\t\tARRAY_SIZE(madera_anc_channel_src_text),\n+\t\t\tmadera_anc_channel_src_text),\n+};\n+EXPORT_SYMBOL_GPL(madera_anc_input_src);\n+\n+static const char * const madera_anc_ng_texts[] = {\n+\t\"None\", \"Internal\", \"External\",\n+};\n+\n+SOC_ENUM_SINGLE_DECL(madera_anc_ng_enum, SND_SOC_NOPM, 0, madera_anc_ng_texts);\n+EXPORT_SYMBOL_GPL(madera_anc_ng_enum);\n+\n+static const char * const madera_out_anc_src_text[] = {\n+\t\"None\", \"RXANCL\", \"RXANCR\",\n+};\n+\n+const struct soc_enum madera_output_anc_src[] = {\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_1L,\n+\t\t\tMADERA_OUT1L_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_1R,\n+\t\t\tMADERA_OUT1R_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_2L,\n+\t\t\tMADERA_OUT2L_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_2R,\n+\t\t\tMADERA_OUT2R_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_3L,\n+\t\t\tMADERA_OUT3L_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_3R,\n+\t\t\tMADERA_OUT3R_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_4L,\n+\t\t\tMADERA_OUT4L_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_4R,\n+\t\t\tMADERA_OUT4R_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_5L,\n+\t\t\tMADERA_OUT5L_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_5R,\n+\t\t\tMADERA_OUT5R_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_6L,\n+\t\t\tMADERA_OUT6L_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+\tSOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_6R,\n+\t\t\tMADERA_OUT6R_ANC_SRC_SHIFT,\n+\t\t\tARRAY_SIZE(madera_out_anc_src_text),\n+\t\t\tmadera_out_anc_src_text),\n+};\n+EXPORT_SYMBOL_GPL(madera_output_anc_src);\n+\n+int madera_dfc_put(struct snd_kcontrol *kcontrol,\n+\t\t   struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tstruct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\n+\tunsigned int reg = e->reg;\n+\tunsigned int val;\n+\tint ret = 0;\n+\n+\treg = ((reg / 6) * 6) - 2;\n+\n+\tsnd_soc_dapm_mutex_lock(dapm);\n+\n+\tval = snd_soc_read(codec, reg);\n+\tif (val & MADERA_DFC1_ENA) {\n+\t\tret = -EBUSY;\n+\t\tdev_err(codec->dev, \"Can't change mode on an active DFC\\n\");\n+\t\tgoto exit;\n+\t}\n+\n+\tret = snd_soc_put_enum_double(kcontrol, ucontrol);\n+exit:\n+\tsnd_soc_dapm_mutex_unlock(dapm);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_dfc_put);\n+\n+int madera_lp_mode_put(struct snd_kcontrol *kcontrol,\n+\t\t       struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct soc_mixer_control *mc =\n+\t\t(struct soc_mixer_control *)kcontrol->private_value;\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tunsigned int reg, mask;\n+\tint ret;\n+\n+\tsnd_soc_dapm_mutex_lock(dapm);\n+\n+\t/* Cannot change lp mode on an active input */\n+\treg = snd_soc_read(codec, MADERA_INPUT_ENABLES);\n+\tmask = (mc->reg - MADERA_ADC_DIGITAL_VOLUME_1L) / 4;\n+\tmask ^= 0x1; /* Flip bottom bit for channel order */\n+\n+\tif ((reg) & (1 << mask)) {\n+\t\tret = -EBUSY;\n+\t\tdev_err(codec->dev,\n+\t\t\t\"Can't change lp mode on an active input\\n\");\n+\t\tgoto exit;\n+\t}\n+\n+\tret = snd_soc_put_volsw(kcontrol, ucontrol);\n+\n+exit:\n+\tsnd_soc_dapm_mutex_unlock(dapm);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_lp_mode_put);\n+\n+const struct snd_kcontrol_new madera_dsp_trigger_output_mux[] = {\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+};\n+EXPORT_SYMBOL_GPL(madera_dsp_trigger_output_mux);\n+\n+const struct snd_kcontrol_new madera_drc_activity_output_mux[] = {\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+\tSOC_DAPM_SINGLE(\"Switch\", SND_SOC_NOPM, 0, 1, 0),\n+};\n+EXPORT_SYMBOL_GPL(madera_drc_activity_output_mux);\n+\n+static void madera_in_set_vu(struct madera_priv *priv, bool enable)\n+{\n+\tunsigned int val;\n+\tint i, ret;\n+\n+\tif (enable)\n+\t\tval = MADERA_IN_VU;\n+\telse\n+\t\tval = 0;\n+\n+\tfor (i = 0; i < priv->num_inputs; i++) {\n+\t\tret = regmap_update_bits(priv->madera->regmap,\n+\t\t\t\t    MADERA_ADC_DIGITAL_VOLUME_1L + (i * 4),\n+\t\t\t\t    MADERA_IN_VU, val);\n+\t\tif (ret)\n+\t\t\tdev_warn(priv->madera->dev,\n+\t\t\t\t \"Failed to modify VU bits: %d\\n\", ret);\n+\t}\n+}\n+\n+int madera_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,\n+\t\t int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tunsigned int reg;\n+\n+\tif (w->shift % 2)\n+\t\treg = MADERA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);\n+\telse\n+\t\treg = MADERA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);\n+\n+\tswitch (event) {\n+\tcase SND_SOC_DAPM_PRE_PMU:\n+\t\tpriv->in_pending++;\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_POST_PMU:\n+\t\tpriv->in_pending--;\n+\t\tsnd_soc_update_bits(codec, reg, MADERA_IN1L_MUTE, 0);\n+\n+\t\t/* If this is the last input pending then allow VU */\n+\t\tif (priv->in_pending == 0) {\n+\t\t\tusleep_range(1000, 3000);\n+\t\t\tmadera_in_set_vu(priv, true);\n+\t\t}\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_PRE_PMD:\n+\t\tsnd_soc_update_bits(codec, reg,\n+\t\t\t\t    MADERA_IN1L_MUTE | MADERA_IN_VU,\n+\t\t\t\t    MADERA_IN1L_MUTE | MADERA_IN_VU);\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_POST_PMD:\n+\t\t/* Disable volume updates if no inputs are enabled */\n+\t\treg = snd_soc_read(codec, MADERA_INPUT_ENABLES);\n+\t\tif (reg == 0)\n+\t\t\tmadera_in_set_vu(priv, false);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_in_ev);\n+\n+int madera_dre_put(struct snd_kcontrol *kcontrol,\n+\t\t   struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tint ret;\n+\n+\tsnd_soc_dapm_mutex_lock(dapm);\n+\n+\tret = snd_soc_put_volsw(kcontrol, ucontrol);\n+\n+\tsnd_soc_dapm_mutex_unlock(dapm);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_dre_put);\n+\n+int madera_out_ev(struct snd_soc_dapm_widget *w,\n+\t\t  struct snd_kcontrol *kcontrol, int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tint out_up_delay;\n+\n+\tswitch (madera->type) {\n+\tcase CS47L90:\n+\tcase CS47L91:\n+\t\tout_up_delay = 6;\n+\t\tbreak;\n+\tdefault:\n+\t\tout_up_delay = 17;\n+\t\tbreak;\n+\t}\n+\n+\tswitch (event) {\n+\tcase SND_SOC_DAPM_PRE_PMU:\n+\t\tswitch (w->shift) {\n+\t\tcase MADERA_OUT1L_ENA_SHIFT:\n+\t\tcase MADERA_OUT1R_ENA_SHIFT:\n+\t\tcase MADERA_OUT2L_ENA_SHIFT:\n+\t\tcase MADERA_OUT2R_ENA_SHIFT:\n+\t\tcase MADERA_OUT3L_ENA_SHIFT:\n+\t\tcase MADERA_OUT3R_ENA_SHIFT:\n+\t\t\tpriv->out_up_pending++;\n+\t\t\tpriv->out_up_delay += out_up_delay;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase SND_SOC_DAPM_POST_PMU:\n+\t\tswitch (w->shift) {\n+\t\tcase MADERA_OUT1L_ENA_SHIFT:\n+\t\tcase MADERA_OUT1R_ENA_SHIFT:\n+\t\tcase MADERA_OUT2L_ENA_SHIFT:\n+\t\tcase MADERA_OUT2R_ENA_SHIFT:\n+\t\tcase MADERA_OUT3L_ENA_SHIFT:\n+\t\tcase MADERA_OUT3R_ENA_SHIFT:\n+\t\t\tpriv->out_up_pending--;\n+\t\t\tif (!priv->out_up_pending) {\n+\t\t\t\tmsleep(priv->out_up_delay);\n+\t\t\t\tpriv->out_up_delay = 0;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase SND_SOC_DAPM_PRE_PMD:\n+\t\tswitch (w->shift) {\n+\t\tcase MADERA_OUT1L_ENA_SHIFT:\n+\t\tcase MADERA_OUT1R_ENA_SHIFT:\n+\t\tcase MADERA_OUT2L_ENA_SHIFT:\n+\t\tcase MADERA_OUT2R_ENA_SHIFT:\n+\t\tcase MADERA_OUT3L_ENA_SHIFT:\n+\t\tcase MADERA_OUT3R_ENA_SHIFT:\n+\t\t\tpriv->out_down_pending++;\n+\t\t\tpriv->out_down_delay++;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase SND_SOC_DAPM_POST_PMD:\n+\t\tswitch (w->shift) {\n+\t\tcase MADERA_OUT1L_ENA_SHIFT:\n+\t\tcase MADERA_OUT1R_ENA_SHIFT:\n+\t\tcase MADERA_OUT2L_ENA_SHIFT:\n+\t\tcase MADERA_OUT2R_ENA_SHIFT:\n+\t\tcase MADERA_OUT3L_ENA_SHIFT:\n+\t\tcase MADERA_OUT3R_ENA_SHIFT:\n+\t\t\tpriv->out_down_pending--;\n+\t\t\tif (!priv->out_down_pending) {\n+\t\t\t\tmsleep(priv->out_down_delay);\n+\t\t\t\tpriv->out_down_delay = 0;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_out_ev);\n+\n+int madera_hp_ev(struct snd_soc_dapm_widget *w,\n+\t\t struct snd_kcontrol *kcontrol, int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int mask = 1 << w->shift;\n+\tunsigned int out_num = w->shift / 2;\n+\tunsigned int val;\n+\tunsigned int ep_sel = 0;\n+\n+\tswitch (event) {\n+\tcase SND_SOC_DAPM_POST_PMU:\n+\t\tval = mask;\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_PRE_PMD:\n+\t\tval = 0;\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_PRE_PMU:\n+\tcase SND_SOC_DAPM_POST_PMD:\n+\t\treturn madera_out_ev(w, kcontrol, event);\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+\t/* Store the desired state for the HP outputs */\n+\tmadera->hp_ena &= ~mask;\n+\tmadera->hp_ena |= val;\n+\n+\t/* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */\n+\tregmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel);\n+\tep_sel &= MADERA_EP_SEL_MASK;\n+\n+\t/* Force off if HPDET clamp is active for this output */\n+\tif (!ep_sel &&\n+\t    (madera->out_clamp[out_num] || madera->out_shorted[out_num]))\n+\t\tval = 0;\n+\n+\tregmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, mask, val);\n+\n+\treturn madera_out_ev(w, kcontrol, event);\n+}\n+EXPORT_SYMBOL_GPL(madera_hp_ev);\n+\n+int madera_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,\n+\t\t  int event)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);\n+\tunsigned int val;\n+\n+\tswitch (event) {\n+\tcase SND_SOC_DAPM_POST_PMU:\n+\t\tval = 1 << w->shift;\n+\t\tbreak;\n+\tcase SND_SOC_DAPM_PRE_PMD:\n+\t\tval = 1 << (w->shift + 1);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+\tsnd_soc_write(codec, MADERA_CLOCK_CONTROL, val);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_anc_ev);\n+\n+static const unsigned int madera_opclk_ref_48k_rates[] = {\n+\t6144000,\n+\t12288000,\n+\t24576000,\n+\t49152000,\n+};\n+\n+static const unsigned int madera_opclk_ref_44k1_rates[] = {\n+\t5644800,\n+\t11289600,\n+\t22579200,\n+\t45158400,\n+};\n+\n+static int madera_set_opclk(struct snd_soc_codec *codec, unsigned int clk,\n+\t\t\t    unsigned int freq)\n+{\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tunsigned int reg;\n+\tconst unsigned int *rates;\n+\tint ref, div, refclk;\n+\n+\tBUILD_BUG_ON(ARRAY_SIZE(madera_opclk_ref_48k_rates) !=\n+\t\t     ARRAY_SIZE(madera_opclk_ref_44k1_rates));\n+\n+\tswitch (clk) {\n+\tcase MADERA_CLK_OPCLK:\n+\t\treg = MADERA_OUTPUT_SYSTEM_CLOCK;\n+\t\trefclk = priv->sysclk;\n+\t\tbreak;\n+\tcase MADERA_CLK_ASYNC_OPCLK:\n+\t\treg = MADERA_OUTPUT_ASYNC_CLOCK;\n+\t\trefclk = priv->asyncclk;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (refclk % 4000)\n+\t\trates = madera_opclk_ref_44k1_rates;\n+\telse\n+\t\trates = madera_opclk_ref_48k_rates;\n+\n+\tfor (ref = 0; ref < ARRAY_SIZE(madera_opclk_ref_48k_rates); ++ref) {\n+\t\tif (rates[ref] > refclk)\n+\t\t\tcontinue;\n+\n+\t\tdiv = 2;\n+\t\twhile ((rates[ref] / div >= freq) && (div <= 30)) {\n+\t\t\tif (rates[ref] / div == freq) {\n+\t\t\t\tdev_dbg(codec->dev, \"Configured %dHz OPCLK\\n\",\n+\t\t\t\t\tfreq);\n+\t\t\t\tsnd_soc_update_bits(codec, reg,\n+\t\t\t\t\t\t    MADERA_OPCLK_DIV_MASK |\n+\t\t\t\t\t\t    MADERA_OPCLK_SEL_MASK,\n+\t\t\t\t\t\t    (div <<\n+\t\t\t\t\t\t     MADERA_OPCLK_DIV_SHIFT) |\n+\t\t\t\t\t\t    ref);\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\tdiv += 2;\n+\t\t}\n+\t}\n+\n+\tdev_err(codec->dev, \"Unable to generate %dHz OPCLK\\n\", freq);\n+\n+\treturn -EINVAL;\n+}\n+\n+static int madera_get_sysclk_setting(unsigned int freq)\n+{\n+\tswitch (freq) {\n+\tcase 0:\n+\tcase 5644800:\n+\tcase 6144000:\n+\t\treturn 0;\n+\tcase 11289600:\n+\tcase 12288000:\n+\t\treturn MADERA_SYSCLK_12MHZ << MADERA_SYSCLK_FREQ_SHIFT;\n+\tcase 22579200:\n+\tcase 24576000:\n+\t\treturn MADERA_SYSCLK_24MHZ << MADERA_SYSCLK_FREQ_SHIFT;\n+\tcase 45158400:\n+\tcase 49152000:\n+\t\treturn MADERA_SYSCLK_49MHZ << MADERA_SYSCLK_FREQ_SHIFT;\n+\tcase 90316800:\n+\tcase 98304000:\n+\t\treturn MADERA_SYSCLK_98MHZ << MADERA_SYSCLK_FREQ_SHIFT;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+int madera_get_legacy_dspclk_setting(struct madera *madera, unsigned int freq)\n+{\n+\tswitch (freq) {\n+\tcase 0:\n+\t\treturn 0;\n+\tcase 45158400:\n+\tcase 49152000:\n+\t\tswitch (madera->type) {\n+\t\tcase CS47L85:\n+\t\tcase WM1840:\n+\t\t\tif (madera->rev < 3)\n+\t\t\t\treturn -EINVAL;\n+\t\t\telse\n+\t\t\t\treturn MADERA_SYSCLK_49MHZ <<\n+\t\t\t\t       MADERA_SYSCLK_FREQ_SHIFT;\n+\t\tdefault:\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\tcase 135475200:\n+\tcase 147456000:\n+\t\treturn MADERA_DSPCLK_147MHZ << MADERA_DSP_CLK_FREQ_LEGACY_SHIFT;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+EXPORT_SYMBOL_GPL(madera_get_legacy_dspclk_setting);\n+\n+static int madera_get_dspclk_setting(struct madera *madera,\n+\t\t\t\t     unsigned int freq,\n+\t\t\t\t     unsigned int *clock_2_val)\n+{\n+\tswitch (madera->type) {\n+\tcase CS47L35:\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\t*clock_2_val = 0; /* don't use MADERA_DSP_CLOCK_2 */\n+\t\treturn madera_get_legacy_dspclk_setting(madera, freq);\n+\tdefault:\n+\t\tif (freq > 150000000)\n+\t\t\treturn -EINVAL;\n+\n+\t\t/* Use new exact frequency control */\n+\t\t*clock_2_val = freq / 15625; /* freq * (2^6) / (10^6) */\n+\t\treturn 0;\n+\t}\n+}\n+\n+int madera_set_sysclk(struct snd_soc_codec *codec, int clk_id,\n+\t\t      int source, unsigned int freq, int dir)\n+{\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tchar *name;\n+\tunsigned int reg, clock_2_val = 0;\n+\tunsigned int mask = MADERA_SYSCLK_FREQ_MASK | MADERA_SYSCLK_SRC_MASK;\n+\tunsigned int val = source << MADERA_SYSCLK_SRC_SHIFT;\n+\tint clk_freq_sel, *clk;\n+\tint ret = 0;\n+\n+\tswitch (clk_id) {\n+\tcase MADERA_CLK_SYSCLK_1:\n+\t\tname = \"SYSCLK\";\n+\t\treg = MADERA_SYSTEM_CLOCK_1;\n+\t\tclk = &priv->sysclk;\n+\t\tclk_freq_sel = madera_get_sysclk_setting(freq);\n+\t\tmask |= MADERA_SYSCLK_FRAC;\n+\t\tbreak;\n+\tcase MADERA_CLK_ASYNCCLK_1:\n+\t\tname = \"ASYNCCLK\";\n+\t\treg = MADERA_ASYNC_CLOCK_1;\n+\t\tclk = &priv->asyncclk;\n+\t\tclk_freq_sel = madera_get_sysclk_setting(freq);\n+\t\tbreak;\n+\tcase MADERA_CLK_OPCLK:\n+\tcase MADERA_CLK_ASYNC_OPCLK:\n+\t\treturn madera_set_opclk(codec, clk_id, freq);\n+\tcase MADERA_CLK_DSPCLK:\n+\t\tname = \"DSPCLK\";\n+\t\treg = MADERA_DSP_CLOCK_1;\n+\t\tclk = &priv->dspclk;\n+\t\tclk_freq_sel = madera_get_dspclk_setting(madera, freq,\n+\t\t\t\t\t\t\t &clock_2_val);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (clk_freq_sel < 0) {\n+\t\tdev_err(madera->dev,\n+\t\t\t\"Failed to get clk setting for %dHZ\\n\", freq);\n+\t\treturn clk_freq_sel;\n+\t}\n+\n+\t*clk = freq;\n+\n+\tif (freq == 0) {\n+\t\tdev_dbg(madera->dev, \"%s cleared\\n\", name);\n+\t\treturn 0;\n+\t}\n+\n+\tval |= clk_freq_sel;\n+\n+\tif (clock_2_val) {\n+\t\tret = regmap_write(madera->regmap, MADERA_DSP_CLOCK_2,\n+\t\t\t\t   clock_2_val);\n+\t\tif (ret) {\n+\t\t\tdev_err(madera->dev,\n+\t\t\t\t\"Failed to write DSP_CONFIG2: %d\\n\", ret);\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\t/*\n+\t\t * We're using the frequency setting in MADERA_DSP_CLOCK_2 so\n+\t\t * don't change the frequency select bits in MADERA_DSP_CLOCK_1\n+\t\t */\n+\t\tmask = MADERA_SYSCLK_SRC_MASK;\n+\t}\n+\n+\tif (freq % 6144000)\n+\t\tval |= MADERA_SYSCLK_FRAC;\n+\n+\tdev_dbg(madera->dev, \"%s set to %uHz\", name, freq);\n+\n+\treturn regmap_update_bits(madera->regmap, reg, mask, val);\n+}\n+EXPORT_SYMBOL_GPL(madera_set_sysclk);\n+\n+static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tint lrclk, bclk, mode, base;\n+\n+\tbase = dai->driver->base;\n+\n+\tlrclk = 0;\n+\tbclk = 0;\n+\n+\tswitch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {\n+\tcase SND_SOC_DAIFMT_DSP_A:\n+\t\tmode = MADERA_FMT_DSP_MODE_A;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_DSP_B:\n+\t\tif ((fmt & SND_SOC_DAIFMT_MASTER_MASK)\n+\t\t\t\t!= SND_SOC_DAIFMT_CBM_CFM) {\n+\t\t\tmadera_aif_err(dai, \"DSP_B not valid in slave mode\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tmode = MADERA_FMT_DSP_MODE_B;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_I2S:\n+\t\tmode = MADERA_FMT_I2S_MODE;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_LEFT_J:\n+\t\tif ((fmt & SND_SOC_DAIFMT_MASTER_MASK)\n+\t\t\t\t!= SND_SOC_DAIFMT_CBM_CFM) {\n+\t\t\tmadera_aif_err(dai, \"LEFT_J not valid in slave mode\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tmode = MADERA_FMT_LEFT_JUSTIFIED_MODE;\n+\t\tbreak;\n+\tdefault:\n+\t\tmadera_aif_err(dai, \"Unsupported DAI format %d\\n\",\n+\t\t\t       fmt & SND_SOC_DAIFMT_FORMAT_MASK);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tswitch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {\n+\tcase SND_SOC_DAIFMT_CBS_CFS:\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_CBS_CFM:\n+\t\tlrclk |= MADERA_AIF1TX_LRCLK_MSTR;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_CBM_CFS:\n+\t\tbclk |= MADERA_AIF1_BCLK_MSTR;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_CBM_CFM:\n+\t\tbclk |= MADERA_AIF1_BCLK_MSTR;\n+\t\tlrclk |= MADERA_AIF1TX_LRCLK_MSTR;\n+\t\tbreak;\n+\tdefault:\n+\t\tmadera_aif_err(dai, \"Unsupported master mode %d\\n\",\n+\t\t\t       fmt & SND_SOC_DAIFMT_MASTER_MASK);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tswitch (fmt & SND_SOC_DAIFMT_INV_MASK) {\n+\tcase SND_SOC_DAIFMT_NB_NF:\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_IB_IF:\n+\t\tbclk |= MADERA_AIF1_BCLK_INV;\n+\t\tlrclk |= MADERA_AIF1TX_LRCLK_INV;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_IB_NF:\n+\t\tbclk |= MADERA_AIF1_BCLK_INV;\n+\t\tbreak;\n+\tcase SND_SOC_DAIFMT_NB_IF:\n+\t\tlrclk |= MADERA_AIF1TX_LRCLK_INV;\n+\t\tbreak;\n+\tdefault:\n+\t\tmadera_aif_err(dai, \"Unsupported invert mode %d\\n\",\n+\t\t\t       fmt & SND_SOC_DAIFMT_INV_MASK);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tregmap_update_bits(madera->regmap, base + MADERA_AIF_BCLK_CTRL,\n+\t\t\t   MADERA_AIF1_BCLK_INV | MADERA_AIF1_BCLK_MSTR,\n+\t\t\t   bclk);\n+\tregmap_update_bits(madera->regmap, base + MADERA_AIF_TX_PIN_CTRL,\n+\t\t\t   MADERA_AIF1TX_LRCLK_INV | MADERA_AIF1TX_LRCLK_MSTR,\n+\t\t\t   lrclk);\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   base + MADERA_AIF_RX_PIN_CTRL,\n+\t\t\t   MADERA_AIF1RX_LRCLK_INV | MADERA_AIF1RX_LRCLK_MSTR,\n+\t\t\t   lrclk);\n+\tregmap_update_bits(madera->regmap, base + MADERA_AIF_FORMAT,\n+\t\t\t   MADERA_AIF1_FMT_MASK, mode);\n+\n+\treturn 0;\n+}\n+\n+static const int madera_48k_bclk_rates[] = {\n+\t-1,\n+\t48000,\n+\t64000,\n+\t96000,\n+\t128000,\n+\t192000,\n+\t256000,\n+\t384000,\n+\t512000,\n+\t768000,\n+\t1024000,\n+\t1536000,\n+\t2048000,\n+\t3072000,\n+\t4096000,\n+\t6144000,\n+\t8192000,\n+\t12288000,\n+\t24576000,\n+};\n+\n+static const int madera_44k1_bclk_rates[] = {\n+\t-1,\n+\t44100,\n+\t58800,\n+\t88200,\n+\t117600,\n+\t177640,\n+\t235200,\n+\t352800,\n+\t470400,\n+\t705600,\n+\t940800,\n+\t1411200,\n+\t1881600,\n+\t2822400,\n+\t3763200,\n+\t5644800,\n+\t7526400,\n+\t11289600,\n+\t22579200,\n+};\n+\n+static const unsigned int madera_sr_vals[] = {\n+\t0,\n+\t12000,\n+\t24000,\n+\t48000,\n+\t96000,\n+\t192000,\n+\t384000,\n+\t768000,\n+\t0,\n+\t11025,\n+\t22050,\n+\t44100,\n+\t88200,\n+\t176400,\n+\t352800,\n+\t705600,\n+\t4000,\n+\t8000,\n+\t16000,\n+\t32000,\n+\t64000,\n+\t128000,\n+\t256000,\n+\t512000,\n+};\n+\n+#define MADERA_48K_RATE_MASK\t0x0F003E\n+#define MADERA_44K1_RATE_MASK\t0x003E00\n+#define MADERA_RATE_MASK\t(MADERA_48K_RATE_MASK | MADERA_44K1_RATE_MASK)\n+\n+static const struct snd_pcm_hw_constraint_list madera_constraint = {\n+\t.count\t= ARRAY_SIZE(madera_sr_vals),\n+\t.list\t= madera_sr_vals,\n+};\n+\n+static int madera_startup(struct snd_pcm_substream *substream,\n+\t\t\t  struct snd_soc_dai *dai)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];\n+\tunsigned int base_rate;\n+\n+\tif (!substream->runtime)\n+\t\treturn 0;\n+\n+\tswitch (dai_priv->clk) {\n+\tcase MADERA_CLK_SYSCLK_1:\n+\tcase MADERA_CLK_SYSCLK_2:\n+\tcase MADERA_CLK_SYSCLK_3:\n+\t\tbase_rate = priv->sysclk;\n+\t\tbreak;\n+\tcase MADERA_CLK_ASYNCCLK_1:\n+\tcase MADERA_CLK_ASYNCCLK_2:\n+\t\tbase_rate = priv->asyncclk;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+\tif (base_rate == 0)\n+\t\tdai_priv->constraint.mask = MADERA_RATE_MASK;\n+\telse if (base_rate % 4000)\n+\t\tdai_priv->constraint.mask = MADERA_44K1_RATE_MASK;\n+\telse\n+\t\tdai_priv->constraint.mask = MADERA_48K_RATE_MASK;\n+\n+\treturn snd_pcm_hw_constraint_list(substream->runtime, 0,\n+\t\t\t\t\t  SNDRV_PCM_HW_PARAM_RATE,\n+\t\t\t\t\t  &dai_priv->constraint);\n+}\n+\n+static int madera_hw_params_rate(struct snd_pcm_substream *substream,\n+\t\t\t\t struct snd_pcm_hw_params *params,\n+\t\t\t\t struct snd_soc_dai *dai)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];\n+\tint base = dai->driver->base;\n+\tint ret = 0;\n+\tint i, sr_val;\n+\tunsigned int cur, tar;\n+\tbool change_rate_domain = false;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(madera_sr_vals); i++)\n+\t\tif (madera_sr_vals[i] == params_rate(params))\n+\t\t\tbreak;\n+\n+\tif (i == ARRAY_SIZE(madera_sr_vals)) {\n+\t\tmadera_aif_err(dai, \"Unsupported sample rate %dHz\\n\",\n+\t\t\t\tparams_rate(params));\n+\t\treturn -EINVAL;\n+\t}\n+\tsr_val = i;\n+\n+\tif (base) {\n+\t\tswitch (dai_priv->clk) {\n+\t\tcase MADERA_CLK_SYSCLK_1:\n+\t\t\ttar = 0 << MADERA_AIF1_RATE_SHIFT;\n+\t\t\tbreak;\n+\t\tcase MADERA_CLK_SYSCLK_2:\n+\t\t\ttar = 1 << MADERA_AIF1_RATE_SHIFT;\n+\t\t\tbreak;\n+\t\tcase MADERA_CLK_SYSCLK_3:\n+\t\t\ttar = 2 << MADERA_AIF1_RATE_SHIFT;\n+\t\t\tbreak;\n+\t\tcase MADERA_CLK_ASYNCCLK_1:\n+\t\t\ttar = 8 << MADERA_AIF1_RATE_SHIFT;\n+\t\t\tbreak;\n+\t\tcase MADERA_CLK_ASYNCCLK_2:\n+\t\t\ttar = 9 << MADERA_AIF1_RATE_SHIFT;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tmadera_aif_err(dai, \"Illegal clock id %d\\n\",\n+\t\t\t\t       dai_priv->clk);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tret = regmap_read(priv->madera->regmap,\n+\t\t\t\t  base + MADERA_AIF_RATE_CTRL, &cur);\n+\t\tif (ret != 0) {\n+\t\t\tmadera_aif_err(dai, \"Failed to check rate: %d\\n\", ret);\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tif ((cur & MADERA_AIF1_RATE_MASK) !=\n+\t\t    (tar & MADERA_AIF1_RATE_MASK)) {\n+\t\t\tchange_rate_domain = true;\n+\n+\t\t\tmutex_lock(&priv->rate_lock);\n+\n+\t\t\tif (!madera_can_change_grp_rate(priv,\n+\t\t\t\t\t\tbase + MADERA_AIF_RATE_CTRL)) {\n+\t\t\t\tmadera_aif_warn(dai,\n+\t\t\t\t\t\t\"Cannot change rate while active\\n\");\n+\t\t\t\tret = -EBUSY;\n+\t\t\t\tgoto out;\n+\t\t\t}\n+\n+\t\t\t/* Guard the rate change with SYSCLK cycles */\n+\t\t\tmadera_spin_sysclk(priv);\n+\t\t}\n+\t}\n+\n+\tswitch (dai_priv->clk) {\n+\tcase MADERA_CLK_SYSCLK_1:\n+\t\tsnd_soc_update_bits(codec, MADERA_SAMPLE_RATE_1,\n+\t\t\t\t    MADERA_SAMPLE_RATE_1_MASK, sr_val);\n+\t\tif (base)\n+\t\t\tsnd_soc_update_bits(codec, base + MADERA_AIF_RATE_CTRL,\n+\t\t\t\t\t    MADERA_AIF1_RATE_MASK,\n+\t\t\t\t\t    0 << MADERA_AIF1_RATE_SHIFT);\n+\t\tbreak;\n+\tcase MADERA_CLK_SYSCLK_2:\n+\t\tsnd_soc_update_bits(codec, MADERA_SAMPLE_RATE_2,\n+\t\t\t\t    MADERA_SAMPLE_RATE_2_MASK, sr_val);\n+\t\tif (base)\n+\t\t\tsnd_soc_update_bits(codec, base + MADERA_AIF_RATE_CTRL,\n+\t\t\t\t\t    MADERA_AIF1_RATE_MASK,\n+\t\t\t\t\t    1 << MADERA_AIF1_RATE_SHIFT);\n+\t\tbreak;\n+\tcase MADERA_CLK_SYSCLK_3:\n+\t\tsnd_soc_update_bits(codec, MADERA_SAMPLE_RATE_3,\n+\t\t\t\t    MADERA_SAMPLE_RATE_3_MASK, sr_val);\n+\t\tif (base)\n+\t\t\tsnd_soc_update_bits(codec, base + MADERA_AIF_RATE_CTRL,\n+\t\t\t\t\t    MADERA_AIF1_RATE_MASK,\n+\t\t\t\t\t    2 << MADERA_AIF1_RATE_SHIFT);\n+\t\tbreak;\n+\tcase MADERA_CLK_ASYNCCLK_1:\n+\t\tsnd_soc_update_bits(codec, MADERA_ASYNC_SAMPLE_RATE_1,\n+\t\t\t\t    MADERA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);\n+\t\tif (base)\n+\t\t\tsnd_soc_update_bits(codec, base + MADERA_AIF_RATE_CTRL,\n+\t\t\t\t\t    MADERA_AIF1_RATE_MASK,\n+\t\t\t\t\t    8 << MADERA_AIF1_RATE_SHIFT);\n+\t\tbreak;\n+\tcase MADERA_CLK_ASYNCCLK_2:\n+\t\tsnd_soc_update_bits(codec, MADERA_ASYNC_SAMPLE_RATE_2,\n+\t\t\t\t    MADERA_ASYNC_SAMPLE_RATE_2_MASK, sr_val);\n+\t\tif (base)\n+\t\t\tsnd_soc_update_bits(codec, base + MADERA_AIF_RATE_CTRL,\n+\t\t\t\t\t    MADERA_AIF1_RATE_MASK,\n+\t\t\t\t\t    9 << MADERA_AIF1_RATE_SHIFT);\n+\t\tbreak;\n+\tdefault:\n+\t\tmadera_aif_err(dai, \"Invalid clock %d\\n\", dai_priv->clk);\n+\t\tret = -EINVAL;\n+\t}\n+\n+out:\n+\tif (change_rate_domain) {\n+\t\tmadera_spin_sysclk(priv);\n+\t\tmutex_unlock(&priv->rate_lock);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static bool madera_aif_cfg_changed(struct snd_soc_codec *codec,\n+\t\t\t\t   int base, int bclk, int lrclk, int frame)\n+{\n+\tint val;\n+\n+\tval = snd_soc_read(codec, base + MADERA_AIF_BCLK_CTRL);\n+\tif (bclk != (val & MADERA_AIF1_BCLK_FREQ_MASK))\n+\t\treturn true;\n+\n+\tval = snd_soc_read(codec, base + MADERA_AIF_RX_BCLK_RATE);\n+\tif (lrclk != (val & MADERA_AIF1RX_BCPF_MASK))\n+\t\treturn true;\n+\n+\tval = snd_soc_read(codec, base + MADERA_AIF_FRAME_CTRL_1);\n+\tif (frame != (val & (MADERA_AIF1TX_WL_MASK |\n+\t\t\t     MADERA_AIF1TX_SLOT_LEN_MASK)))\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static int madera_hw_params(struct snd_pcm_substream *substream,\n+\t\t\t    struct snd_pcm_hw_params *params,\n+\t\t\t    struct snd_soc_dai *dai)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tint base = dai->driver->base;\n+\tconst int *rates;\n+\tint i, ret, val;\n+\tunsigned int channels = params_channels(params);\n+\tunsigned int chan_limit =\n+\t\t\tmadera->pdata.codec.max_channels_clocked[dai->id - 1];\n+\tint tdm_width = priv->tdm_width[dai->id - 1];\n+\tint tdm_slots = priv->tdm_slots[dai->id - 1];\n+\tint bclk, lrclk, wl, frame, bclk_target, num_rates;\n+\tbool reconfig;\n+\tunsigned int aif_tx_state = 0, aif_rx_state = 0;\n+\n+\tif (params_rate(params) % 4000) {\n+\t\trates = &madera_44k1_bclk_rates[0];\n+\t\tnum_rates = ARRAY_SIZE(madera_44k1_bclk_rates);\n+\t} else {\n+\t\trates = &madera_48k_bclk_rates[0];\n+\t\tnum_rates = ARRAY_SIZE(madera_48k_bclk_rates);\n+\t}\n+\n+\twl = snd_pcm_format_width(params_format(params));\n+\n+\tif (tdm_slots) {\n+\t\tmadera_aif_dbg(dai, \"Configuring for %d %d bit TDM slots\\n\",\n+\t\t\t\ttdm_slots, tdm_width);\n+\t\tbclk_target = tdm_slots * tdm_width * params_rate(params);\n+\t\tchannels = tdm_slots;\n+\t} else {\n+\t\tbclk_target = snd_soc_params_to_bclk(params);\n+\t\ttdm_width = wl;\n+\t}\n+\n+\tif (chan_limit && chan_limit < channels) {\n+\t\tmadera_aif_dbg(dai, \"Limiting to %d channels\\n\", chan_limit);\n+\t\tbclk_target /= channels;\n+\t\tbclk_target *= chan_limit;\n+\t}\n+\n+\t/* Force multiple of 2 channels for I2S mode */\n+\tval = snd_soc_read(codec, base + MADERA_AIF_FORMAT);\n+\tval &= MADERA_AIF1_FMT_MASK;\n+\tif ((channels & 1) && (val == MADERA_FMT_I2S_MODE)) {\n+\t\tmadera_aif_dbg(dai, \"Forcing stereo mode\\n\");\n+\t\tbclk_target /= channels;\n+\t\tbclk_target *= channels + 1;\n+\t}\n+\n+\tfor (i = 0; i < num_rates; i++) {\n+\t\tif (rates[i] >= bclk_target &&\n+\t\t    rates[i] % params_rate(params) == 0) {\n+\t\t\tbclk = i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (i == num_rates) {\n+\t\tmadera_aif_err(dai, \"Unsupported sample rate %dHz\\n\",\n+\t\t\t\tparams_rate(params));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tlrclk = rates[bclk] / params_rate(params);\n+\n+\tmadera_aif_dbg(dai, \"BCLK %dHz LRCLK %dHz\\n\",\n+\t\t\trates[bclk], rates[bclk] / lrclk);\n+\n+\tframe = wl << MADERA_AIF1TX_WL_SHIFT | tdm_width;\n+\n+\treconfig = madera_aif_cfg_changed(codec, base, bclk, lrclk, frame);\n+\n+\tif (reconfig) {\n+\t\t/* Save AIF TX/RX state */\n+\t\taif_tx_state = snd_soc_read(codec,\n+\t\t\t\t\t    base + MADERA_AIF_TX_ENABLES);\n+\t\taif_rx_state = snd_soc_read(codec,\n+\t\t\t\t\t    base + MADERA_AIF_RX_ENABLES);\n+\t\t/* Disable AIF TX/RX before reconfiguring it */\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_TX_ENABLES, 0xff, 0x0);\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_RX_ENABLES, 0xff, 0x0);\n+\t}\n+\n+\tret = madera_hw_params_rate(substream, params, dai);\n+\tif (ret != 0)\n+\t\tgoto restore_aif;\n+\n+\tif (reconfig) {\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_BCLK_CTRL,\n+\t\t\t\t   MADERA_AIF1_BCLK_FREQ_MASK, bclk);\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_RX_BCLK_RATE,\n+\t\t\t\t   MADERA_AIF1RX_BCPF_MASK, lrclk);\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_FRAME_CTRL_1,\n+\t\t\t\t   MADERA_AIF1TX_WL_MASK |\n+\t\t\t\t   MADERA_AIF1TX_SLOT_LEN_MASK, frame);\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_FRAME_CTRL_2,\n+\t\t\t\t   MADERA_AIF1RX_WL_MASK |\n+\t\t\t\t   MADERA_AIF1RX_SLOT_LEN_MASK, frame);\n+\t}\n+\n+restore_aif:\n+\tif (reconfig) {\n+\t\t/* Restore AIF TX/RX state */\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_TX_ENABLES,\n+\t\t\t\t   0xff, aif_tx_state);\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   base + MADERA_AIF_RX_ENABLES,\n+\t\t\t\t   0xff, aif_rx_state);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int madera_is_syncclk(int clk_id)\n+{\n+\tswitch (clk_id) {\n+\tcase MADERA_CLK_SYSCLK_1:\n+\tcase MADERA_CLK_SYSCLK_2:\n+\tcase MADERA_CLK_SYSCLK_3:\n+\t\treturn 1;\n+\tcase MADERA_CLK_ASYNCCLK_1:\n+\tcase MADERA_CLK_ASYNCCLK_2:\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+static int madera_dai_set_sysclk(struct snd_soc_dai *dai,\n+\t\t\t\t int clk_id, unsigned int freq, int dir)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];\n+\tstruct snd_soc_dapm_route routes[2];\n+\tint is_sync;\n+\n+\tis_sync = madera_is_syncclk(clk_id);\n+\tif (is_sync < 0) {\n+\t\tdev_err(codec->dev, \"Illegal DAI clock id %d\\n\", clk_id);\n+\t\treturn is_sync;\n+\t}\n+\n+\tif (is_sync == madera_is_syncclk(dai_priv->clk))\n+\t\treturn 0;\n+\n+\tif (dai->active) {\n+\t\tdev_err(codec->dev, \"Can't change clock on active DAI %d\\n\",\n+\t\t\tdai->id);\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tdev_dbg(codec->dev, \"Setting AIF%d to %s\\n\", dai->id,\n+\t\tis_sync ? \"SYSCLK\" : \"ASYNCCLK\");\n+\n+\t/*\n+\t * A connection to SYSCLK is always required, we only add and remove\n+\t * a connection to ASYNCCLK\n+\t */\n+\tmemset(&routes, 0, sizeof(routes));\n+\troutes[0].sink = dai->driver->capture.stream_name;\n+\troutes[1].sink = dai->driver->playback.stream_name;\n+\troutes[0].source = \"ASYNCCLK\";\n+\troutes[1].source = \"ASYNCCLK\";\n+\n+\tif (is_sync)\n+\t\tsnd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));\n+\telse\n+\t\tsnd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));\n+\n+\tdai_priv->clk = clk_id;\n+\n+\treturn snd_soc_dapm_sync(dapm);\n+}\n+\n+static int madera_set_tristate(struct snd_soc_dai *dai, int tristate)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tint base = dai->driver->base;\n+\tunsigned int reg;\n+\tint ret;\n+\n+\tif (tristate)\n+\t\treg = MADERA_AIF1_TRI;\n+\telse\n+\t\treg = 0;\n+\n+\tret = snd_soc_update_bits(codec, base + MADERA_AIF_RATE_CTRL,\n+\t\t\t\t  MADERA_AIF1_TRI, reg);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\telse\n+\t\treturn 0;\n+}\n+\n+static void madera_set_channels_to_mask(struct snd_soc_dai *dai,\n+\t\t\t\t\tunsigned int base,\n+\t\t\t\t\tint channels, unsigned int mask)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tstruct madera *madera = priv->madera;\n+\tint slot, i;\n+\n+\tfor (i = 0; i < channels; ++i) {\n+\t\tslot = ffs(mask) - 1;\n+\t\tif (slot < 0)\n+\t\t\treturn;\n+\n+\t\tregmap_write(madera->regmap, base + i, slot);\n+\n+\t\tmask &= ~(1 << slot);\n+\t}\n+\n+\tif (mask)\n+\t\tmadera_aif_warn(dai, \"Too many channels in TDM mask\\n\");\n+}\n+\n+static int madera_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,\n+\t\t\t       unsigned int rx_mask, int slots, int slot_width)\n+{\n+\tstruct snd_soc_codec *codec = dai->codec;\n+\tstruct madera_priv *priv = snd_soc_codec_get_drvdata(codec);\n+\tint base = dai->driver->base;\n+\tint rx_max_chan = dai->driver->playback.channels_max;\n+\tint tx_max_chan = dai->driver->capture.channels_max;\n+\n+\t/* Only support TDM for the physical AIFs */\n+\tif (dai->id > MADERA_MAX_AIF)\n+\t\treturn -ENOTSUPP;\n+\n+\tif (slots == 0) {\n+\t\ttx_mask = (1 << tx_max_chan) - 1;\n+\t\trx_mask = (1 << rx_max_chan) - 1;\n+\t}\n+\n+\tmadera_set_channels_to_mask(dai, base + MADERA_AIF_FRAME_CTRL_3,\n+\t\t\t\t    tx_max_chan, tx_mask);\n+\tmadera_set_channels_to_mask(dai, base + MADERA_AIF_FRAME_CTRL_11,\n+\t\t\t\t    rx_max_chan, rx_mask);\n+\n+\tpriv->tdm_width[dai->id - 1] = slot_width;\n+\tpriv->tdm_slots[dai->id - 1] = slots;\n+\n+\treturn 0;\n+}\n+\n+const struct snd_soc_dai_ops madera_dai_ops = {\n+\t.startup = madera_startup,\n+\t.set_fmt = madera_set_fmt,\n+\t.set_tdm_slot = madera_set_tdm_slot,\n+\t.hw_params = madera_hw_params,\n+\t.set_sysclk = madera_dai_set_sysclk,\n+\t.set_tristate = madera_set_tristate,\n+};\n+EXPORT_SYMBOL_GPL(madera_dai_ops);\n+\n+const struct snd_soc_dai_ops madera_simple_dai_ops = {\n+\t.startup = madera_startup,\n+\t.hw_params = madera_hw_params_rate,\n+\t.set_sysclk = madera_dai_set_sysclk,\n+};\n+EXPORT_SYMBOL_GPL(madera_simple_dai_ops);\n+\n+int madera_init_dai(struct madera_priv *priv, int id)\n+{\n+\tstruct madera_dai_priv *dai_priv = &priv->dai[id];\n+\n+\tdai_priv->clk = MADERA_CLK_SYSCLK_1;\n+\tdai_priv->constraint = madera_constraint;\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_init_dai);\n+\n+static const struct {\n+\tunsigned int min;\n+\tunsigned int max;\n+\tu16 fratio;\n+\tint ratio;\n+} fll_sync_fratios[] = {\n+\t{       0,    64000, 4, 16 },\n+\t{   64000,   128000, 3,  8 },\n+\t{  128000,   256000, 2,  4 },\n+\t{  256000,  1000000, 1,  2 },\n+\t{ 1000000, 13500000, 0,  1 },\n+};\n+\n+static const unsigned int pseudo_fref_max[MADERA_FLL_MAX_FRATIO] = {\n+\t13500000,\n+\t 6144000,\n+\t 6144000,\n+\t 3072000,\n+\t 3072000,\n+\t 2822400,\n+\t 2822400,\n+\t 1536000,\n+\t 1536000,\n+\t 1536000,\n+\t 1536000,\n+\t 1536000,\n+\t 1536000,\n+\t 1536000,\n+\t 1536000,\n+\t  768000,\n+};\n+\n+struct madera_fll_gains {\n+\tunsigned int min;\n+\tunsigned int max;\n+\tint gain;\t\t/* main gain */\n+\tint alt_gain;\t\t/* alternate integer gain */\n+};\n+\n+static const struct madera_fll_gains madera_fll_sync_gains[] = {\n+\t{       0,   256000, 0, -1 },\n+\t{  256000,  1000000, 2, -1 },\n+\t{ 1000000, 13500000, 4, -1 },\n+};\n+\n+static const struct madera_fll_gains madera_fll_main_gains[] = {\n+\t{       0,   100000, 0, 2 },\n+\t{  100000,   375000, 2, 2 },\n+\t{  375000,   768000, 3, 2 },\n+\t{  768001,  1500000, 3, 3 },\n+\t{ 1500000,  6000000, 4, 3 },\n+\t{ 6000000, 13500000, 5, 3 },\n+};\n+\n+static int madera_find_sync_fratio(unsigned int fref, int *fratio)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(fll_sync_fratios); i++) {\n+\t\tif (fll_sync_fratios[i].min <= fref &&\n+\t\t    fref <= fll_sync_fratios[i].max) {\n+\t\t\tif (fratio)\n+\t\t\t\t*fratio = fll_sync_fratios[i].fratio;\n+\n+\t\t\treturn fll_sync_fratios[i].ratio;\n+\t\t}\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+static int madera_find_main_fratio(unsigned int fref, unsigned int fout,\n+\t\t\t\t   int *fratio)\n+{\n+\tint ratio = 1;\n+\n+\twhile ((fout / (ratio * fref)) > MADERA_FLL_MAX_N)\n+\t\tratio++;\n+\n+\tif (fratio)\n+\t\t*fratio = ratio - 1;\n+\n+\treturn ratio;\n+}\n+\n+static int madera_find_fratio(struct madera_fll *fll, unsigned int fref,\n+\t\t\t      bool sync, int *fratio)\n+{\n+\tswitch (fll->madera->type) {\n+\tcase CS47L35:\n+\t\tswitch (fll->madera->rev) {\n+\t\tcase 0:\n+\t\t\t/* rev A0 uses sync calculation for both loops */\n+\t\t\treturn madera_find_sync_fratio(fref, fratio);\n+\t\tdefault:\n+\t\t\tif (sync)\n+\t\t\t\treturn madera_find_sync_fratio(fref, fratio);\n+\t\t\telse\n+\t\t\t\treturn madera_find_main_fratio(fref,\n+\t\t\t\t\t\t\t       fll->fout,\n+\t\t\t\t\t\t\t       fratio);\n+\t\t}\n+\t\tbreak;\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\t/* these use the same calculation for main and sync loops */\n+\t\treturn madera_find_sync_fratio(fref, fratio);\n+\tdefault:\n+\t\tif (sync)\n+\t\t\treturn madera_find_sync_fratio(fref, fratio);\n+\t\telse\n+\t\t\treturn madera_find_main_fratio(fref, fll->fout, fratio);\n+\t}\n+}\n+\n+static int madera_calc_fratio(struct madera_fll *fll,\n+\t\t\t      struct madera_fll_cfg *cfg,\n+\t\t\t      unsigned int fref, bool sync)\n+{\n+\tint init_ratio, ratio;\n+\tint refdiv, div;\n+\n+\t/* fref must be <=13.5MHz, find initial refdiv */\n+\tdiv = 1;\n+\tcfg->refdiv = 0;\n+\twhile (fref > MADERA_FLL_MAX_FREF) {\n+\t\tdiv *= 2;\n+\t\tfref /= 2;\n+\t\tcfg->refdiv++;\n+\n+\t\tif (div > MADERA_FLL_MAX_REFDIV)\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Find an appropriate FLL_FRATIO */\n+\tinit_ratio = madera_find_fratio(fll, fref, sync, &cfg->fratio);\n+\tif (init_ratio < 0) {\n+\t\tmadera_fll_err(fll, \"Unable to find FRATIO for fref=%uHz\\n\",\n+\t\t\t\tfref);\n+\t\treturn init_ratio;\n+\t}\n+\n+\tif (!sync)\n+\t\tcfg->fratio = init_ratio - 1;\n+\n+\tswitch (fll->madera->type) {\n+\tcase CS47L35:\n+\t\tswitch (fll->madera->rev) {\n+\t\tcase 0:\n+\t\t\tif (sync)\n+\t\t\t\treturn init_ratio;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn init_ratio;\n+\t\t}\n+\t\tbreak;\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\tif (sync)\n+\t\t\treturn init_ratio;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn init_ratio;\n+\t}\n+\n+\t/*\n+\t * For CS47L35 rev A0, CS47L85 and WM1840 adjust FRATIO/refdiv to avoid\n+\t * integer mode if possible\n+\t */\n+\trefdiv = cfg->refdiv;\n+\n+\twhile (div <= MADERA_FLL_MAX_REFDIV) {\n+\t\t/*\n+\t\t * start from init_ratio because this may already give a\n+\t\t * fractional N.K\n+\t\t */\n+\t\tfor (ratio = init_ratio; ratio > 0; ratio--) {\n+\t\t\tif (fll->fout % (ratio * fref)) {\n+\t\t\t\tcfg->refdiv = refdiv;\n+\t\t\t\tcfg->fratio = ratio - 1;\n+\t\t\t\treturn ratio;\n+\t\t\t}\n+\t\t}\n+\n+\t\tfor (ratio = init_ratio + 1; ratio <= MADERA_FLL_MAX_FRATIO;\n+\t\t     ratio++) {\n+\t\t\tif ((MADERA_FLL_VCO_CORNER / 2) /\n+\t\t\t    (MADERA_FLL_VCO_MULT * ratio) < fref)\n+\t\t\t\tbreak;\n+\n+\t\t\tif (fref > pseudo_fref_max[ratio - 1])\n+\t\t\t\tbreak;\n+\n+\t\t\tif (fll->fout % (ratio * fref)) {\n+\t\t\t\tcfg->refdiv = refdiv;\n+\t\t\t\tcfg->fratio = ratio - 1;\n+\t\t\t\treturn ratio;\n+\t\t\t}\n+\t\t}\n+\n+\t\tdiv *= 2;\n+\t\tfref /= 2;\n+\t\trefdiv++;\n+\t\tinit_ratio = madera_find_fratio(fll, fref, sync, NULL);\n+\t}\n+\n+\tmadera_fll_warn(fll, \"Falling back to integer mode operation\\n\");\n+\n+\treturn cfg->fratio + 1;\n+}\n+\n+static int madera_find_fll_gain(struct madera_fll *fll,\n+\t\t\t\tstruct madera_fll_cfg *cfg,\n+\t\t\t\tunsigned int fref,\n+\t\t\t\tconst struct madera_fll_gains *gains,\n+\t\t\t\tint n_gains)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < n_gains; i++) {\n+\t\tif (gains[i].min <= fref && fref <= gains[i].max) {\n+\t\t\tcfg->gain = gains[i].gain;\n+\t\t\tcfg->alt_gain = gains[i].alt_gain;\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\tmadera_fll_err(fll, \"Unable to find gain for fref=%uHz\\n\", fref);\n+\n+\treturn -EINVAL;\n+}\n+\n+static int madera_calc_fll(struct madera_fll *fll,\n+\t\t\t   struct madera_fll_cfg *cfg,\n+\t\t\t   unsigned int fref, bool sync)\n+{\n+\tunsigned int gcd_fll;\n+\tconst struct madera_fll_gains *gains;\n+\tint n_gains;\n+\tint ratio, ret;\n+\n+\tmadera_fll_dbg(fll, \"fref=%u Fout=%u fvco=%u\\n\",\n+\t\t\tfref, fll->fout, fll->fout * MADERA_FLL_VCO_MULT);\n+\n+\t/* Find an appropriate FLL_FRATIO and refdiv */\n+\tratio = madera_calc_fratio(fll, cfg, fref, sync);\n+\tif (ratio < 0)\n+\t\treturn ratio;\n+\n+\t/* Apply the division for our remaining calculations */\n+\tfref = fref / (1 << cfg->refdiv);\n+\n+\tcfg->n = fll->fout / (ratio * fref);\n+\n+\tif (fll->fout % (ratio * fref)) {\n+\t\tgcd_fll = gcd(fll->fout, ratio * fref);\n+\t\tmadera_fll_dbg(fll, \"GCD=%u\\n\", gcd_fll);\n+\n+\t\tcfg->theta = (fll->fout - (cfg->n * ratio * fref))\n+\t\t\t/ gcd_fll;\n+\t\tcfg->lambda = (ratio * fref) / gcd_fll;\n+\t} else {\n+\t\tcfg->theta = 0;\n+\t\tcfg->lambda = 0;\n+\t}\n+\n+\t/*\n+\t * Round down to 16bit range with cost of accuracy lost.\n+\t * Denominator must be bigger than numerator so we only\n+\t * take care of it.\n+\t */\n+\twhile (cfg->lambda >= (1 << 16)) {\n+\t\tcfg->theta >>= 1;\n+\t\tcfg->lambda >>= 1;\n+\t}\n+\n+\tswitch (fll->madera->type) {\n+\tcase CS47L35:\n+\t\tswitch (fll->madera->rev) {\n+\t\tcase 0:\n+\t\t\t/* Rev A0 uses the sync gains for both loops */\n+\t\t\tgains = madera_fll_sync_gains;\n+\t\t\tn_gains = ARRAY_SIZE(madera_fll_sync_gains);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tif (sync) {\n+\t\t\t\tgains = madera_fll_sync_gains;\n+\t\t\t\tn_gains = ARRAY_SIZE(madera_fll_sync_gains);\n+\t\t\t} else {\n+\t\t\t\tgains = madera_fll_main_gains;\n+\t\t\t\tn_gains = ARRAY_SIZE(madera_fll_main_gains);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\t/* These use the sync gains for both loops */\n+\t\tgains = madera_fll_sync_gains;\n+\t\tn_gains = ARRAY_SIZE(madera_fll_sync_gains);\n+\t\tbreak;\n+\tdefault:\n+\t\tif (sync) {\n+\t\t\tgains = madera_fll_sync_gains;\n+\t\t\tn_gains = ARRAY_SIZE(madera_fll_sync_gains);\n+\t\t} else {\n+\t\t\tgains = madera_fll_main_gains;\n+\t\t\tn_gains = ARRAY_SIZE(madera_fll_main_gains);\n+\t\t}\n+\t\tbreak;\n+\t}\n+\n+\tret = madera_find_fll_gain(fll, cfg, fref, gains, n_gains);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmadera_fll_dbg(fll, \"N=%d THETA=%d LAMBDA=%d\\n\",\n+\t\t\tcfg->n, cfg->theta, cfg->lambda);\n+\tmadera_fll_dbg(fll, \"FRATIO=0x%x(%d) REFCLK_DIV=0x%x(%d)\\n\",\n+\t\t\tcfg->fratio, ratio, cfg->refdiv, 1 << cfg->refdiv);\n+\tmadera_fll_dbg(fll, \"GAIN=0x%x(%d)\\n\", cfg->gain, 1 << cfg->gain);\n+\n+\treturn 0;\n+\n+}\n+\n+static bool madera_write_fll(struct madera *madera, unsigned int base,\n+\t\t\t     struct madera_fll_cfg *cfg, int source,\n+\t\t\t     bool sync, int gain)\n+{\n+\tbool change, fll_change;\n+\n+\tfll_change = false;\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t base + MADERA_FLL_CONTROL_3_OFFS,\n+\t\t\t\t MADERA_FLL1_THETA_MASK,\n+\t\t\t\t cfg->theta, &change);\n+\tfll_change |= change;\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t base + MADERA_FLL_CONTROL_4_OFFS,\n+\t\t\t\t MADERA_FLL1_LAMBDA_MASK,\n+\t\t\t\t cfg->lambda, &change);\n+\tfll_change |= change;\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t base + MADERA_FLL_CONTROL_5_OFFS,\n+\t\t\t\t MADERA_FLL1_FRATIO_MASK,\n+\t\t\t\t cfg->fratio << MADERA_FLL1_FRATIO_SHIFT,\n+\t\t\t\t &change);\n+\tfll_change |= change;\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t base + MADERA_FLL_CONTROL_6_OFFS,\n+\t\t\t\t MADERA_FLL1_REFCLK_DIV_MASK |\n+\t\t\t\t MADERA_FLL1_REFCLK_SRC_MASK,\n+\t\t\t\t cfg->refdiv << MADERA_FLL1_REFCLK_DIV_SHIFT |\n+\t\t\t\t source << MADERA_FLL1_REFCLK_SRC_SHIFT,\n+\t\t\t\t &change);\n+\tfll_change |= change;\n+\n+\tif (sync) {\n+\t\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t\t base + MADERA_FLL_SYNCHRONISER_7_OFFS,\n+\t\t\t\t\t MADERA_FLL1_GAIN_MASK,\n+\t\t\t\t\t gain << MADERA_FLL1_GAIN_SHIFT,\n+\t\t\t\t\t &change);\n+\t\tfll_change |= change;\n+\t} else {\n+\t\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t\t base + MADERA_FLL_CONTROL_7_OFFS,\n+\t\t\t\t\t MADERA_FLL1_GAIN_MASK,\n+\t\t\t\t\t gain << MADERA_FLL1_GAIN_SHIFT,\n+\t\t\t\t\t &change);\n+\t\tfll_change |= change;\n+\t}\n+\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t base + MADERA_FLL_CONTROL_2_OFFS,\n+\t\t\t\t MADERA_FLL1_CTRL_UPD | MADERA_FLL1_N_MASK,\n+\t\t\t\t MADERA_FLL1_CTRL_UPD | cfg->n, &change);\n+\tfll_change |= change;\n+\n+\treturn fll_change;\n+}\n+\n+static int madera_is_enabled_fll(struct madera_fll *fll, int base)\n+{\n+\tstruct madera *madera = fll->madera;\n+\tunsigned int reg;\n+\tint ret;\n+\n+\tret = regmap_read(madera->regmap,\n+\t\t\t  base + MADERA_FLL_CONTROL_1_OFFS, &reg);\n+\tif (ret != 0) {\n+\t\tmadera_fll_err(fll, \"Failed to read current state: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\treturn reg & MADERA_FLL1_ENA;\n+}\n+\n+static int madera_wait_for_fll(struct madera_fll *fll, bool requested)\n+{\n+\tstruct madera *madera = fll->madera;\n+\tunsigned int val = 0;\n+\tbool status;\n+\tint i;\n+\n+\tmadera_fll_dbg(fll, \"Waiting for FLL...\\n\");\n+\n+\tfor (i = 0; i < 30; i++) {\n+\t\tregmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_2, &val);\n+\t\tstatus = val & (MADERA_FLL1_LOCK_STS1 << (fll->id - 1));\n+\t\tif (status == requested)\n+\t\t\treturn 0;\n+\n+\t\tswitch (i) {\n+\t\tcase 0 ... 5:\n+\t\t\tusleep_range(75, 125);\n+\t\t\tbreak;\n+\t\tcase 11 ... 20:\n+\t\t\tusleep_range(750, 1250);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tmsleep(20);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tmadera_fll_warn(fll, \"Timed out waiting for lock\\n\");\n+\n+\treturn -ETIMEDOUT;\n+}\n+\n+static bool madera_set_fll_phase_integrator(struct madera_fll *fll,\n+\t\t\t\t\t    struct madera_fll_cfg *ref_cfg,\n+\t\t\t\t\t    bool sync)\n+{\n+\tunsigned int val;\n+\tbool reg_change;\n+\n+\tif (!sync && (ref_cfg->theta == 0))\n+\t\tval = (1 << MADERA_FLL1_PHASE_ENA_SHIFT) |\n+\t\t\t(2 << MADERA_FLL1_PHASE_GAIN_SHIFT);\n+\telse\n+\t\tval = 2 << MADERA_FLL1_PHASE_GAIN_SHIFT;\n+\n+\tregmap_update_bits_check(fll->madera->regmap,\n+\t\t\t\t fll->base + MADERA_FLL_EFS_2_OFFS,\n+\t\t\t\t MADERA_FLL1_PHASE_ENA_MASK |\n+\t\t\t\t MADERA_FLL1_PHASE_GAIN_MASK,\n+\t\t\t\t val,\n+\t\t\t\t &reg_change);\n+\n+\treturn reg_change;\n+}\n+\n+static void madera_disable_fll(struct madera_fll *fll)\n+{\n+\tstruct madera *madera = fll->madera;\n+\tunsigned int sync_reg_base;\n+\tbool change;\n+\n+\tswitch (madera->type) {\n+\tcase CS47L35:\n+\t\tsync_reg_base = fll->base + CS47L35_FLL_SYNCHRONISER_OFFS;\n+\t\tbreak;\n+\tdefault:\n+\t\tsync_reg_base = fll->base + MADERA_FLL_SYNCHRONISER_OFFS;\n+\t\tbreak;\n+\t}\n+\n+\tmadera_fll_dbg(fll, \"Disabling FLL\\n\");\n+\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL1_FREERUN, MADERA_FLL1_FREERUN);\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t\t MADERA_FLL1_ENA, 0, &change);\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   sync_reg_base + MADERA_FLL_SYNCHRONISER_1_OFFS,\n+\t\t\t   MADERA_FLL1_SYNC_ENA, 0);\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL1_FREERUN, 0);\n+\n+\tmadera_wait_for_fll(fll, false);\n+\n+\tif (change)\n+\t\tpm_runtime_put_autosuspend(madera->dev);\n+}\n+\n+static int madera_enable_fll(struct madera_fll *fll)\n+{\n+\tstruct madera *madera = fll->madera;\n+\tbool have_sync = false;\n+\tint already_enabled = madera_is_enabled_fll(fll, fll->base);\n+\tint sync_enabled;\n+\tstruct madera_fll_cfg cfg;\n+\tunsigned int sync_reg_base;\n+\tint gain, ret;\n+\tbool fll_change = false;\n+\n+\tif (already_enabled < 0)\n+\t\treturn already_enabled;\t/* error getting current state */\n+\n+\tif ((fll->ref_src < 0) || (fll->ref_freq == 0)) {\n+\t\tmadera_fll_err(fll, \"No REFCLK\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tmadera_fll_dbg(fll, \"Enabling FLL, initially %s\\n\",\n+\t\t\talready_enabled ? \"enabled\" : \"disabled\");\n+\n+\tif ((fll->fout < MADERA_FLL_MIN_FOUT) ||\n+\t    (fll->fout > MADERA_FLL_MAX_FOUT)) {\n+\t\tmadera_fll_err(fll, \"invalid fout %uHz\\n\", fll->fout);\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tswitch (madera->type) {\n+\tcase CS47L35:\n+\t\tsync_reg_base = fll->base + CS47L35_FLL_SYNCHRONISER_OFFS;\n+\t\tbreak;\n+\tdefault:\n+\t\tsync_reg_base = fll->base + MADERA_FLL_SYNCHRONISER_OFFS;\n+\t\tbreak;\n+\t}\n+\n+\tsync_enabled = madera_is_enabled_fll(fll, sync_reg_base);\n+\tif (sync_enabled < 0)\n+\t\treturn sync_enabled;\n+\n+\tif (already_enabled) {\n+\t\t/* Facilitate smooth refclk across the transition */\n+\t\tregmap_update_bits(fll->madera->regmap,\n+\t\t\t\t   fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t\t   MADERA_FLL1_FREERUN,\n+\t\t\t\t   MADERA_FLL1_FREERUN);\n+\t\tudelay(32);\n+\t\tregmap_update_bits(fll->madera->regmap,\n+\t\t\t\t   fll->base + MADERA_FLL_CONTROL_7_OFFS,\n+\t\t\t\t   MADERA_FLL1_GAIN_MASK, 0);\n+\t}\n+\n+\t/* Apply SYNCCLK setting */\n+\tif (fll->sync_src >= 0) {\n+\t\tret = madera_calc_fll(fll, &cfg, fll->sync_freq, true);\n+\t\tif (ret < 0)\n+\t\t\tgoto err;\n+\n+\t\tfll_change |= madera_write_fll(madera, sync_reg_base,\n+\t\t\t\t\t\t&cfg, fll->sync_src,\n+\t\t\t\t\t\ttrue, cfg.gain);\n+\t\thave_sync = true;\n+\t}\n+\n+\tif (already_enabled && !!sync_enabled != have_sync)\n+\t\tmadera_fll_warn(fll, \"Synchroniser changed on active FLL\\n\");\n+\n+\t/* Apply REFCLK setting */\n+\tret = madera_calc_fll(fll, &cfg, fll->ref_freq, false);\n+\tif (ret < 0)\n+\t\tgoto err;\n+\n+\t/* Ref path hardcodes lambda to 65536 when sync is on */\n+\tif (have_sync && cfg.lambda)\n+\t\tcfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;\n+\n+\tswitch (fll->madera->type) {\n+\tcase CS47L35:\n+\t\tswitch (fll->madera->rev) {\n+\t\tcase 0:\n+\t\t\tgain = cfg.gain;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tfll_change |=\n+\t\t\t\tmadera_set_fll_phase_integrator(fll, &cfg,\n+\t\t\t\t\t\t\t\thave_sync);\n+\t\t\tif (!have_sync && (cfg.theta == 0))\n+\t\t\t\tgain = cfg.alt_gain;\n+\t\t\telse\n+\t\t\t\tgain = cfg.gain;\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\tgain = cfg.gain;\n+\t\tbreak;\n+\tdefault:\n+\t\tfll_change |= madera_set_fll_phase_integrator(fll, &cfg,\n+\t\t\t\t\t\t\t      have_sync);\n+\t\tif (!have_sync && (cfg.theta == 0))\n+\t\t\tgain = cfg.alt_gain;\n+\t\telse\n+\t\t\tgain = cfg.gain;\n+\t\tbreak;\n+\t}\n+\n+\tfll_change |= madera_write_fll(madera, fll->base,\n+\t\t\t\t      &cfg, fll->ref_src,\n+\t\t\t\t      false, gain);\n+\n+\t/*\n+\t * Increase the bandwidth if we're not using a low frequency\n+\t * sync source.\n+\t */\n+\tif (have_sync && fll->sync_freq > 100000)\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\tsync_reg_base + MADERA_FLL_SYNCHRONISER_7_OFFS,\n+\t\t\t\tMADERA_FLL1_SYNC_DFSAT_MASK, 0);\n+\telse\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\tsync_reg_base + MADERA_FLL_SYNCHRONISER_7_OFFS,\n+\t\t\t\tMADERA_FLL1_SYNC_DFSAT_MASK,\n+\t\t\t\tMADERA_FLL1_SYNC_DFSAT);\n+\n+\tif (!already_enabled)\n+\t\tpm_runtime_get_sync(madera->dev);\n+\n+\tif (have_sync)\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\tsync_reg_base + MADERA_FLL_SYNCHRONISER_1_OFFS,\n+\t\t\t\tMADERA_FLL1_SYNC_ENA,\n+\t\t\t\tMADERA_FLL1_SYNC_ENA);\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL1_ENA, MADERA_FLL1_ENA);\n+\n+\tif (already_enabled)\n+\t\tregmap_update_bits(madera->regmap,\n+\t\t\t\t   fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t\t   MADERA_FLL1_FREERUN, 0);\n+\n+\tif (fll_change || !already_enabled)\n+\t\tmadera_wait_for_fll(fll, true);\n+\n+\treturn 0;\n+\n+err:\n+\t /* In case of error don't leave the FLL running with an old config */\n+\tmadera_disable_fll(fll);\n+\n+\treturn ret;\n+}\n+\n+static int madera_apply_fll(struct madera_fll *fll)\n+{\n+\tif (fll->fout) {\n+\t\treturn madera_enable_fll(fll);\n+\t} else {\n+\t\tmadera_disable_fll(fll);\n+\t\treturn 0;\n+\t}\n+}\n+\n+int madera_set_fll_syncclk(struct madera_fll *fll, int source,\n+\t\t\t   unsigned int fref, unsigned int fout)\n+{\n+\t/*\n+\t * fout is ignored, since the synchronizer is an optional extra\n+\t * constraint on the Fout generated from REFCLK, so the Fout is\n+\t * set when configuring REFCLK\n+\t */\n+\n+\tif (fll->sync_src == source && fll->sync_freq == fref)\n+\t\treturn 0;\n+\n+\tfll->sync_src = source;\n+\tfll->sync_freq = fref;\n+\n+\treturn madera_apply_fll(fll);\n+}\n+EXPORT_SYMBOL_GPL(madera_set_fll_syncclk);\n+\n+int madera_set_fll_refclk(struct madera_fll *fll, int source,\n+\t\t\t  unsigned int fref, unsigned int fout)\n+{\n+\tint ret;\n+\n+\tif (fll->ref_src == source &&\n+\t    fll->ref_freq == fref && fll->fout == fout)\n+\t\treturn 0;\n+\n+\t/*\n+\t * Changes of fout on an enabled FLL aren't allowed except when\n+\t * setting fout==0 to disable the FLL\n+\t */\n+\tif (fout && (fout != fll->fout)) {\n+\t\tret = madera_is_enabled_fll(fll, fll->base);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tif (ret) {\n+\t\t\tmadera_fll_err(fll, \"Can't change Fout on active FLL\\n\");\n+\t\t\treturn -EBUSY;\n+\t\t}\n+\t}\n+\n+\tfll->ref_src = source;\n+\tfll->ref_freq = fref;\n+\tfll->fout = fout;\n+\n+\treturn madera_apply_fll(fll);\n+}\n+EXPORT_SYMBOL_GPL(madera_set_fll_refclk);\n+\n+int madera_init_fll(struct madera *madera, int id, int base,\n+\t\t    struct madera_fll *fll)\n+{\n+\tfll->id = id;\n+\tfll->base = base;\n+\tfll->madera = madera;\n+\tfll->ref_src = MADERA_FLL_SRC_NONE;\n+\tfll->sync_src = MADERA_FLL_SRC_NONE;\n+\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLL_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL1_FREERUN, 0);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_init_fll);\n+\n+static const struct reg_sequence madera_fll_ao_32K_49M_patch[] = {\n+\t{ MADERA_FLLAO_CONTROL_2,  0x02EE },\n+\t{ MADERA_FLLAO_CONTROL_3,  0x0000 },\n+\t{ MADERA_FLLAO_CONTROL_4,  0x0001 },\n+\t{ MADERA_FLLAO_CONTROL_5,  0x0002 },\n+\t{ MADERA_FLLAO_CONTROL_6,  0x8001 },\n+\t{ MADERA_FLLAO_CONTROL_7,  0x0004 },\n+\t{ MADERA_FLLAO_CONTROL_8,  0x0077 },\n+\t{ MADERA_FLLAO_CONTROL_10, 0x06D8 },\n+\t{ MADERA_FLLAO_CONTROL_11, 0x0085 },\n+\t{ MADERA_FLLAO_CONTROL_2,  0x82EE },\n+};\n+\n+static const struct reg_sequence madera_fll_ao_32K_45M_patch[] = {\n+\t{ MADERA_FLLAO_CONTROL_2,  0x02B1 },\n+\t{ MADERA_FLLAO_CONTROL_3,  0x0001 },\n+\t{ MADERA_FLLAO_CONTROL_4,  0x0010 },\n+\t{ MADERA_FLLAO_CONTROL_5,  0x0002 },\n+\t{ MADERA_FLLAO_CONTROL_6,  0x8001 },\n+\t{ MADERA_FLLAO_CONTROL_7,  0x0004 },\n+\t{ MADERA_FLLAO_CONTROL_8,  0x0077 },\n+\t{ MADERA_FLLAO_CONTROL_10, 0x06D8 },\n+\t{ MADERA_FLLAO_CONTROL_11, 0x0005 },\n+\t{ MADERA_FLLAO_CONTROL_2,  0x82B1 },\n+};\n+\n+struct madera_fllao_patch {\n+\tunsigned int fin;\n+\tunsigned int fout;\n+\tconst struct reg_sequence *patch;\n+\tunsigned int patch_size;\n+};\n+\n+static const struct madera_fllao_patch madera_fllao_settings[] = {\n+\t{\n+\t\t.fin = 32768,\n+\t\t.fout = 49152000,\n+\t\t.patch = madera_fll_ao_32K_49M_patch,\n+\t\t.patch_size = ARRAY_SIZE(madera_fll_ao_32K_49M_patch),\n+\n+\t},\n+\t{\n+\t\t.fin = 32768,\n+\t\t.fout = 45158400,\n+\t\t.patch = madera_fll_ao_32K_45M_patch,\n+\t\t.patch_size = ARRAY_SIZE(madera_fll_ao_32K_45M_patch),\n+\t},\n+};\n+\n+static int madera_enable_fll_ao(struct madera_fll *fll,\n+\t\t\t\tconst struct reg_sequence *patch,\n+\t\t\t\tunsigned int patch_size)\n+{\n+\tstruct madera *madera = fll->madera;\n+\tint already_enabled = madera_is_enabled_fll(fll, fll->base);\n+\tunsigned int val;\n+\tint i;\n+\n+\tif (already_enabled < 0)\n+\t\treturn already_enabled;\n+\n+\tif (!already_enabled)\n+\t\tpm_runtime_get_sync(madera->dev);\n+\n+\tmadera_fll_dbg(fll, \"Enabling FLL_AO, initially %s\\n\",\n+\t\t\talready_enabled ? \"enabled\" : \"disabled\");\n+\n+\t/* FLL_AO_HOLD must be set before configuring any registers */\n+\tregmap_update_bits(fll->madera->regmap,\n+\t\t\t   fll->base + MADERA_FLLAO_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);\n+\n+\tfor (i = 0; i < patch_size; i++) {\n+\t\tval = patch[i].def;\n+\n+\t\t/* modify the patch to apply fll->ref_src as input clock */\n+\t\tif (patch[i].reg == MADERA_FLLAO_CONTROL_6) {\n+\t\t\tval &= ~MADERA_FLL_AO_REFCLK_SRC_MASK;\n+\t\t\tval |= (fll->ref_src << MADERA_FLL_AO_REFCLK_SRC_SHIFT)\n+\t\t\t\t& MADERA_FLL_AO_REFCLK_SRC_MASK;\n+\t\t}\n+\n+\t\tregmap_write(madera->regmap, patch[i].reg, val);\n+\t}\n+\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLLAO_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL_AO_ENA, MADERA_FLL_AO_ENA);\n+\n+\t/* Release the hold so that fll_ao locks to external frequency */\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLLAO_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL_AO_HOLD, 0);\n+\n+\tif (!already_enabled)\n+\t\tmadera_wait_for_fll(fll, true);\n+\n+\treturn 0;\n+}\n+\n+static int madera_disable_fll_ao(struct madera_fll *fll)\n+{\n+\tstruct madera *madera = fll->madera;\n+\tbool change;\n+\n+\tmadera_fll_dbg(fll, \"Disabling FLL_AO\\n\");\n+\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLLAO_CONTROL_1_OFFS,\n+\t\t\t   MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);\n+\tregmap_update_bits_check(madera->regmap,\n+\t\t\t\t fll->base + MADERA_FLLAO_CONTROL_1_OFFS,\n+\t\t\t\t MADERA_FLL_AO_ENA, 0, &change);\n+\n+\tmadera_wait_for_fll(fll, false);\n+\n+\t/*\n+\t * ctrl_up gates the writes to all fll_ao register, setting it to 0\n+\t * here ensures that after a runtime suspend/resume cycle when one\n+\t * enables the fllao then ctrl_up is the last bit that is configured\n+\t * by the fllao enable code rather than the cache sync operation which\n+\t * would have updated it much earlier before writing out all fllao\n+\t * registers\n+\t */\n+\tregmap_update_bits(madera->regmap,\n+\t\t\t   fll->base + MADERA_FLLAO_CONTROL_2_OFFS,\n+\t\t\t   MADERA_FLL_AO_CTRL_UPD_MASK, 0);\n+\n+\tif (change)\n+\t\tpm_runtime_put_autosuspend(madera->dev);\n+\n+\treturn 0;\n+}\n+\n+int madera_set_fll_ao_refclk(struct madera_fll *fll, int source,\n+\t\t\t     unsigned int fin, unsigned int fout)\n+{\n+\tint ret = 0;\n+\tconst struct reg_sequence *patch = NULL;\n+\tint patch_size = 0;\n+\tunsigned int i;\n+\n+\tif (fll->ref_src == source &&\n+\t    fll->ref_freq == fin && fll->fout == fout)\n+\t\treturn 0;\n+\n+\tmadera_fll_dbg(fll, \"Change FLL_AO refclk to fin=%u fout=%u source=%d\\n\",\n+\t\t\tfin, fout, source);\n+\n+\tif (fout && (fll->ref_freq != fin || fll->fout != fout)) {\n+\t\tfor (i = 0; i < ARRAY_SIZE(madera_fllao_settings); i++) {\n+\t\t\tif (madera_fllao_settings[i].fin == fin &&\n+\t\t\t    madera_fllao_settings[i].fout == fout)\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (i == ARRAY_SIZE(madera_fllao_settings)) {\n+\t\t\tmadera_fll_err(fll,\n+\t\t\t\t\t\"No matching configuration for FLL_AO\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tpatch = madera_fllao_settings[i].patch;\n+\t\tpatch_size = madera_fllao_settings[i].patch_size;\n+\t}\n+\n+\tfll->ref_src = source;\n+\tfll->ref_freq = fin;\n+\tfll->fout = fout;\n+\n+\tif (fout)\n+\t\tret = madera_enable_fll_ao(fll, patch, patch_size);\n+\telse\n+\t\tmadera_disable_fll_ao(fll);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_set_fll_ao_refclk);\n+\n+/**\n+ * madera_set_output_mode - Set the mode of the specified output\n+ *\n+ * @codec: Device to configure\n+ * @output: Output number\n+ * @diff: True to set the output to differential mode\n+ *\n+ * Some systems use external analogue switches to connect more\n+ * analogue devices to the CODEC than are supported by the device.  In\n+ * some systems this requires changing the switched output from single\n+ * ended to differential mode dynamically at runtime, an operation\n+ * supported using this function.\n+ *\n+ * Most systems have a single static configuration and should use\n+ * platform data instead.\n+ */\n+int madera_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)\n+{\n+\tunsigned int reg, val;\n+\tint ret;\n+\n+\tif (output < 1 || output > MADERA_MAX_OUTPUT)\n+\t\treturn -EINVAL;\n+\n+\treg = MADERA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;\n+\n+\tif (diff)\n+\t\tval = MADERA_OUT1_MONO;\n+\telse\n+\t\tval = 0;\n+\n+\tret = snd_soc_update_bits(codec, reg, MADERA_OUT1_MONO, val);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\telse\n+\t\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(madera_set_output_mode);\n+\n+static bool madera_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)\n+{\n+\ts16 a = be16_to_cpu(_a);\n+\ts16 b = be16_to_cpu(_b);\n+\n+\tif (!mode) {\n+\t\treturn abs(a) >= 4096;\n+\t} else {\n+\t\tif (abs(b) >= 4096)\n+\t\t\treturn true;\n+\n+\t\treturn (abs((a << 16) / (4096 - b)) >= 4096 << 4);\n+\t}\n+}\n+\n+int madera_eq_coeff_put(struct snd_kcontrol *kcontrol,\n+\t\t\tstruct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\tstruct soc_bytes *params = (void *)kcontrol->private_value;\n+\tunsigned int val;\n+\t__be16 *data;\n+\tint len;\n+\tint ret;\n+\n+\tlen = params->num_regs * regmap_get_val_bytes(madera->regmap);\n+\n+\tdata = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);\n+\tif (!data)\n+\t\treturn -ENOMEM;\n+\n+\tdata[0] &= cpu_to_be16(MADERA_EQ1_B1_MODE);\n+\n+\tif (madera_eq_filter_unstable(!!data[0], data[1], data[2]) ||\n+\t    madera_eq_filter_unstable(true, data[4], data[5]) ||\n+\t    madera_eq_filter_unstable(true, data[8], data[9]) ||\n+\t    madera_eq_filter_unstable(true, data[12], data[13]) ||\n+\t    madera_eq_filter_unstable(false, data[16], data[17])) {\n+\t\tdev_err(madera->dev, \"Rejecting unstable EQ coefficients\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n+\t}\n+\n+\tret = regmap_read(madera->regmap, params->base, &val);\n+\tif (ret != 0)\n+\t\tgoto out;\n+\n+\tval &= ~MADERA_EQ1_B1_MODE;\n+\tdata[0] |= cpu_to_be16(val);\n+\n+\tret = regmap_raw_write(madera->regmap, params->base, data, len);\n+\n+out:\n+\tkfree(data);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_GPL(madera_eq_coeff_put);\n+\n+int madera_lhpf_coeff_put(struct snd_kcontrol *kcontrol,\n+\t\t\t  struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\t__be16 *data = (__be16 *)ucontrol->value.bytes.data;\n+\ts16 val = be16_to_cpu(*data);\n+\n+\tif (abs(val) >= 4096) {\n+\t\tdev_err(madera->dev, \"Rejecting unstable LHPF coefficients\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn snd_soc_bytes_put(kcontrol, ucontrol);\n+}\n+EXPORT_SYMBOL_GPL(madera_lhpf_coeff_put);\n+\n+MODULE_DESCRIPTION(\"ASoC Cirrus Logic Madera codec support\");\n+MODULE_AUTHOR(\"Charles Keepax <ckeepax@opensource.wolfsonmicro.com>\");\n+MODULE_AUTHOR(\"Richard Fitzgerald <rf@opensource.wolfsonmicro.com>\");\n+MODULE_LICENSE(\"GPL v2\");\ndiff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h\nnew file mode 100644\nindex 0000000..abac352\n--- /dev/null\n+++ b/sound/soc/codecs/madera.h\n@@ -0,0 +1,470 @@\n+/*\n+ * madera.h - Cirrus Logic Madera class codecs common support\n+ *\n+ * Copyright 2015-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#ifndef ASOC_MADERA_H\n+#define ASOC_MADERA_H\n+\n+#include <linux/completion.h>\n+#include <sound/soc.h>\n+\n+#include <sound/madera-pdata.h>\n+\n+#include \"wm_adsp.h\"\n+\n+#define MADERA_FLL1_REFCLK\t\t1\n+#define MADERA_FLL2_REFCLK\t\t2\n+#define MADERA_FLL3_REFCLK\t\t3\n+#define MADERA_FLLAO_REFCLK\t\t4\n+#define MADERA_FLL1_SYNCCLK\t\t5\n+#define MADERA_FLL2_SYNCCLK\t\t6\n+#define MADERA_FLL3_SYNCCLK\t\t7\n+#define MADERA_FLLAO_SYNCCLK\t\t8\n+\n+#define MADERA_FLL_SRC_NONE\t\t-1\n+#define MADERA_FLL_SRC_MCLK1\t\t0\n+#define MADERA_FLL_SRC_MCLK2\t\t1\n+#define MADERA_FLL_SRC_SLIMCLK\t\t3\n+#define MADERA_FLL_SRC_FLL1\t\t4\n+#define MADERA_FLL_SRC_FLL2\t\t5\n+#define MADERA_FLL_SRC_AIF1BCLK\t\t8\n+#define MADERA_FLL_SRC_AIF2BCLK\t\t9\n+#define MADERA_FLL_SRC_AIF3BCLK\t\t10\n+#define MADERA_FLL_SRC_AIF4BCLK\t\t11\n+#define MADERA_FLL_SRC_AIF1LRCLK\t12\n+#define MADERA_FLL_SRC_AIF2LRCLK\t13\n+#define MADERA_FLL_SRC_AIF3LRCLK\t14\n+#define MADERA_FLL_SRC_AIF4LRCLK\t15\n+\n+#define MADERA_CLK_SYSCLK_1\t\t1\n+#define MADERA_CLK_ASYNCCLK_1\t\t2\n+#define MADERA_CLK_OPCLK\t\t3\n+#define MADERA_CLK_ASYNC_OPCLK\t\t4\n+#define MADERA_CLK_SYSCLK_2\t\t5\n+#define MADERA_CLK_SYSCLK_3\t\t6\n+#define MADERA_CLK_ASYNCCLK_2\t\t7\n+#define MADERA_CLK_DSPCLK\t\t8\n+\n+#define MADERA_CLK_SRC_MCLK1\t\t0x0\n+#define MADERA_CLK_SRC_MCLK2\t\t0x1\n+#define MADERA_CLK_SRC_FLL1\t\t0x4\n+#define MADERA_CLK_SRC_FLL2\t\t0x5\n+#define MADERA_CLK_SRC_FLL3\t\t0x6\n+#define MADERA_CLK_SRC_FLLAO_HI\t\t0x7\n+#define MADERA_CLK_SRC_FLL1_DIV6\t0x7\n+#define MADERA_CLK_SRC_AIF1BCLK\t\t0x8\n+#define MADERA_CLK_SRC_AIF2BCLK\t\t0x9\n+#define MADERA_CLK_SRC_AIF3BCLK\t\t0xA\n+#define MADERA_CLK_SRC_AIF4BCLK\t\t0xB\n+#define MADERA_CLK_SRC_FLLAO\t\t0xF\n+\n+#define MADERA_MIXER_VOL_MASK\t\t0x00FE\n+#define MADERA_MIXER_VOL_SHIFT\t\t1\n+#define MADERA_MIXER_VOL_WIDTH\t\t7\n+\n+#define MADERA_DOM_GRP_FX\t\t0\n+#define MADERA_DOM_GRP_ASRC1_RATE_1\t1\n+#define MADERA_DOM_GRP_ASRC1_RATE_2\t2\n+#define MADERA_DOM_GRP_ASRC2_RATE_1\t3\n+#define MADERA_DOM_GRP_ASRC2_RATE_2\t4\n+#define MADERA_DOM_GRP_ISRC1_DEC\t5\n+#define MADERA_DOM_GRP_ISRC1_INT\t6\n+#define MADERA_DOM_GRP_ISRC2_DEC\t7\n+#define MADERA_DOM_GRP_ISRC2_INT\t8\n+#define MADERA_DOM_GRP_ISRC3_DEC\t9\n+#define MADERA_DOM_GRP_ISRC3_INT\t10\n+#define MADERA_DOM_GRP_ISRC4_DEC\t11\n+#define MADERA_DOM_GRP_ISRC4_INT\t12\n+#define MADERA_DOM_GRP_OUT\t\t13\n+#define MADERA_DOM_GRP_SPD\t\t14\n+#define MADERA_DOM_GRP_DSP1\t\t15\n+#define MADERA_DOM_GRP_DSP2\t\t16\n+#define MADERA_DOM_GRP_DSP3\t\t17\n+#define MADERA_DOM_GRP_DSP4\t\t18\n+#define MADERA_DOM_GRP_DSP5\t\t19\n+#define MADERA_DOM_GRP_DSP6\t\t20\n+#define MADERA_DOM_GRP_DSP7\t\t21\n+#define MADERA_DOM_GRP_AIF1\t\t22\n+#define MADERA_DOM_GRP_AIF2\t\t23\n+#define MADERA_DOM_GRP_AIF3\t\t24\n+#define MADERA_DOM_GRP_AIF4\t\t25\n+#define MADERA_DOM_GRP_SLIMBUS\t\t26\n+#define MADERA_DOM_GRP_PWM\t\t27\n+#define MADERA_DOM_GRP_DFC\t\t28\n+#define MADERA_N_DOM_GRPS\t\t29\n+\n+#define MADERA_MAX_DAI\t\t\t11\n+#define MADERA_MAX_ADSP\t\t\t7\n+\n+#define MADERA_NUM_MIXER_INPUTS\t\t146\n+\n+struct madera;\n+struct wm_adsp;\n+\n+struct madera_voice_trigger_info {\n+\t/** Which core triggered, 1-based (1 = DSP1, ...) */\n+\tint core_num;\n+};\n+\n+struct madera_dai_priv {\n+\tint clk;\n+\tstruct snd_pcm_hw_constraint_list constraint;\n+};\n+\n+struct madera_priv {\n+\tstruct wm_adsp adsp[MADERA_MAX_ADSP];\n+\tstruct madera *madera;\n+\tstruct device *dev;\n+\tint sysclk;\n+\tint asyncclk;\n+\tint dspclk;\n+\tstruct madera_dai_priv dai[MADERA_MAX_DAI];\n+\n+\tint num_inputs;\n+\n+\tunsigned int in_pending;\n+\n+\tunsigned int out_up_pending;\n+\tunsigned int out_up_delay;\n+\tunsigned int out_down_pending;\n+\tunsigned int out_down_delay;\n+\n+\tunsigned int adsp_rate_cache[MADERA_MAX_ADSP];\n+\n+\tstruct mutex rate_lock;\n+\n+\tint tdm_width[MADERA_MAX_AIF];\n+\tint tdm_slots[MADERA_MAX_AIF];\n+\n+\tint domain_group_ref[MADERA_N_DOM_GRPS];\n+};\n+\n+struct madera_fll_cfg {\n+\tint n;\n+\tunsigned int theta;\n+\tunsigned int lambda;\n+\tint refdiv;\n+\tint fratio;\n+\tint gain;\n+\tint alt_gain;\n+};\n+\n+struct madera_fll {\n+\tstruct madera *madera;\n+\tint id;\n+\tunsigned int base;\n+\n+\tunsigned int fout;\n+\n+\tint sync_src;\n+\tunsigned int sync_freq;\n+\n+\tint ref_src;\n+\tunsigned int ref_freq;\n+\tstruct madera_fll_cfg ref_cfg;\n+};\n+\n+struct madera_enum {\n+\tstruct soc_enum mixer_enum;\n+\tint val;\n+};\n+\n+extern const unsigned int madera_ana_tlv[];\n+extern const unsigned int madera_eq_tlv[];\n+extern const unsigned int madera_digital_tlv[];\n+extern const unsigned int madera_noise_tlv[];\n+extern const unsigned int madera_ng_tlv[];\n+\n+extern const unsigned int madera_mixer_tlv[];\n+extern const char * const madera_mixer_texts[MADERA_NUM_MIXER_INPUTS];\n+extern unsigned int madera_mixer_values[MADERA_NUM_MIXER_INPUTS];\n+\n+#define MADERA_GAINMUX_CONTROLS(name, base) \\\n+\tSOC_SINGLE_RANGE_TLV(name \" Input Volume\", base + 1,\t\t\\\n+\t\t\t     MADERA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,\t\\\n+\t\t\t     madera_mixer_tlv)\n+\n+#define MADERA_MIXER_CONTROLS(name, base) \\\n+\tSOC_SINGLE_RANGE_TLV(name \" Input 1 Volume\", base + 1,\t\t\\\n+\t\t\t     MADERA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,\t\\\n+\t\t\t     madera_mixer_tlv),\t\t\t\\\n+\tSOC_SINGLE_RANGE_TLV(name \" Input 2 Volume\", base + 3,\t\t\\\n+\t\t\t     MADERA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,\t\\\n+\t\t\t     madera_mixer_tlv),\t\t\t\\\n+\tSOC_SINGLE_RANGE_TLV(name \" Input 3 Volume\", base + 5,\t\t\\\n+\t\t\t     MADERA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,\t\\\n+\t\t\t     madera_mixer_tlv),\t\t\t\\\n+\tSOC_SINGLE_RANGE_TLV(name \" Input 4 Volume\", base + 7,\t\t\\\n+\t\t\t     MADERA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,\t\\\n+\t\t\t     madera_mixer_tlv)\n+\n+#define MADERA_MUX_ENUM_DECL(name, reg) \\\n+\tSOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \\\n+\t\tname, reg, 0, 0xff, madera_mixer_texts, madera_mixer_values)\n+\n+#define MADERA_MUX_CTL_DECL(name) \\\n+\tconst struct snd_kcontrol_new name##_mux =\t\\\n+\t\tSOC_DAPM_ENUM(\"Route\", name##_enum)\n+\n+#define MADERA_MUX_ENUMS(name, base_reg) \\\n+\tstatic MADERA_MUX_ENUM_DECL(name##_enum, base_reg);\t\\\n+\tstatic MADERA_MUX_CTL_DECL(name)\n+\n+#define MADERA_MIXER_ENUMS(name, base_reg) \\\n+\tMADERA_MUX_ENUMS(name##_in1, base_reg);     \\\n+\tMADERA_MUX_ENUMS(name##_in2, base_reg + 2); \\\n+\tMADERA_MUX_ENUMS(name##_in3, base_reg + 4); \\\n+\tMADERA_MUX_ENUMS(name##_in4, base_reg + 6)\n+\n+#define MADERA_DSP_AUX_ENUMS(name, base_reg) \\\n+\tMADERA_MUX_ENUMS(name##_aux1, base_reg);\t\\\n+\tMADERA_MUX_ENUMS(name##_aux2, base_reg + 8);\t\\\n+\tMADERA_MUX_ENUMS(name##_aux3, base_reg + 16);\t\\\n+\tMADERA_MUX_ENUMS(name##_aux4, base_reg + 24);\t\\\n+\tMADERA_MUX_ENUMS(name##_aux5, base_reg + 32);\t\\\n+\tMADERA_MUX_ENUMS(name##_aux6, base_reg + 40)\n+\n+#define MADERA_MUX(name, ctrl) \\\n+\tSND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)\n+\n+#define MADERA_MUX_WIDGETS(name, name_str) \\\n+\tMADERA_MUX(name_str \" Input 1\", &name##_mux)\n+\n+#define MADERA_MIXER_WIDGETS(name, name_str)\t\\\n+\tMADERA_MUX(name_str \" Input 1\", &name##_in1_mux), \\\n+\tMADERA_MUX(name_str \" Input 2\", &name##_in2_mux), \\\n+\tMADERA_MUX(name_str \" Input 3\", &name##_in3_mux), \\\n+\tMADERA_MUX(name_str \" Input 4\", &name##_in4_mux), \\\n+\tSND_SOC_DAPM_MIXER(name_str \" Mixer\", SND_SOC_NOPM, 0, 0, NULL, 0)\n+\n+#define MADERA_DSP_WIDGETS(name, name_str)\t\t\t\\\n+\tMADERA_MIXER_WIDGETS(name##L, name_str \"L\"),\t\t\\\n+\tMADERA_MIXER_WIDGETS(name##R, name_str \"R\"),\t\t\\\n+\tMADERA_MUX(name_str \" Aux 1\", &name##_aux1_mux),\t\\\n+\tMADERA_MUX(name_str \" Aux 2\", &name##_aux2_mux),\t\\\n+\tMADERA_MUX(name_str \" Aux 3\", &name##_aux3_mux),\t\\\n+\tMADERA_MUX(name_str \" Aux 4\", &name##_aux4_mux),\t\\\n+\tMADERA_MUX(name_str \" Aux 5\", &name##_aux5_mux),\t\\\n+\tMADERA_MUX(name_str \" Aux 6\", &name##_aux6_mux)\n+\n+#define MADERA_MUX_ROUTES(widget, name) \\\n+\t{ widget, NULL, name \" Input 1\" }, \\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Input 1\")\n+\n+#define MADERA_MIXER_ROUTES(widget, name)\t\t\\\n+\t{ widget, NULL, name \" Mixer\" },\t\t\\\n+\t{ name \" Mixer\", NULL, name \" Input 1\" },\t\\\n+\t{ name \" Mixer\", NULL, name \" Input 2\" },\t\\\n+\t{ name \" Mixer\", NULL, name \" Input 3\" },\t\\\n+\t{ name \" Mixer\", NULL, name \" Input 4\" },\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Input 1\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Input 2\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Input 3\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Input 4\")\n+\n+#define MADERA_DSP_ROUTES(name)\t\t\t\t\\\n+\t{ name, NULL, name \" Preloader\"},\t\t\\\n+\t{ name \" Preloader\", NULL, \"SYSCLK\"},\t\t\\\n+\t{ name \" Preloader\", NULL, \"DSPCLK\"},\t\t\\\n+\t{ name, NULL, name \" Aux 1\" },\t\t\t\\\n+\t{ name, NULL, name \" Aux 2\" },\t\t\t\\\n+\t{ name, NULL, name \" Aux 3\" },\t\t\t\\\n+\t{ name, NULL, name \" Aux 4\" },\t\t\t\\\n+\t{ name, NULL, name \" Aux 5\" },\t\t\t\\\n+\t{ name, NULL, name \" Aux 6\" },\t\t\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Aux 1\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Aux 2\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Aux 3\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Aux 4\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Aux 5\"),\t\\\n+\tMADERA_MIXER_INPUT_ROUTES(name \" Aux 6\"),\t\\\n+\tMADERA_MIXER_ROUTES(name, name \"L\"),\t\t\\\n+\tMADERA_MIXER_ROUTES(name, name \"R\")\n+\n+#define MADERA_SAMPLE_RATE_CONTROL(name, domain) \\\n+\tSOC_ENUM(name, madera_sample_rate[(domain) - 2])\n+\n+#define MADERA_RATE_ENUM(xname, xenum) \\\n+{\t.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\\\n+\t.info = snd_soc_info_enum_double, \\\n+\t.get = snd_soc_get_enum_double, .put = madera_rate_put, \\\n+\t.private_value = (unsigned long)&xenum }\n+\n+#define MADERA_EQ_CONTROL(xname, xbase)\t\t\t\t\\\n+{\t.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\t\\\n+\t.info = snd_soc_bytes_info, .get = snd_soc_bytes_get,\t\\\n+\t.put = madera_eq_coeff_put, .private_value =\t\t\\\n+\t((unsigned long)&(struct soc_bytes) { .base = xbase,\t\\\n+\t .num_regs = 20, .mask = ~MADERA_EQ1_B1_MODE }) }\n+\n+#define MADERA_LHPF_CONTROL(xname, xbase)\t\t\t\\\n+{\t.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\t\\\n+\t.info = snd_soc_bytes_info, .get = snd_soc_bytes_get,\t\\\n+\t.put = madera_lhpf_coeff_put, .private_value =\t\t\\\n+\t((unsigned long)&(struct soc_bytes) { .base = xbase,\t\\\n+\t .num_regs = 1 }) }\n+\n+#define MADERA_RATES SNDRV_PCM_RATE_KNOT\n+\n+#define MADERA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \\\n+\t\t\tSNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)\n+\n+#define MADERA_OSR_ENUM_SIZE\t\t5\n+#define MADERA_SYNC_RATE_ENUM_SIZE\t3\n+#define MADERA_ASYNC_RATE_ENUM_SIZE\t2\n+#define MADERA_RATE_ENUM_SIZE \\\n+\t\t(MADERA_SYNC_RATE_ENUM_SIZE + MADERA_ASYNC_RATE_ENUM_SIZE)\n+#define MADERA_SAMPLE_RATE_ENUM_SIZE\t16\n+#define MADERA_DFC_TYPE_ENUM_SIZE\t5\n+#define MADERA_DFC_WIDTH_ENUM_SIZE\t5\n+\n+extern const struct snd_soc_dai_ops madera_dai_ops;\n+extern const struct snd_soc_dai_ops madera_simple_dai_ops;\n+\n+extern const struct snd_kcontrol_new madera_inmux[];\n+\n+extern const char * const madera_rate_text[MADERA_RATE_ENUM_SIZE];\n+extern const unsigned int madera_rate_val[MADERA_RATE_ENUM_SIZE];\n+extern const char * const madera_sample_rate_text[MADERA_SAMPLE_RATE_ENUM_SIZE];\n+extern const unsigned int madera_sample_rate_val[MADERA_SAMPLE_RATE_ENUM_SIZE];\n+extern const char * const madera_dfc_width_text[MADERA_DFC_WIDTH_ENUM_SIZE];\n+extern const unsigned int madera_dfc_width_val[MADERA_DFC_WIDTH_ENUM_SIZE];\n+extern const char * const madera_dfc_type_text[MADERA_DFC_TYPE_ENUM_SIZE];\n+extern const unsigned int madera_dfc_type_val[MADERA_DFC_TYPE_ENUM_SIZE];\n+\n+extern const struct soc_enum madera_sample_rate[];\n+extern const struct soc_enum madera_isrc_fsl[];\n+extern const struct soc_enum madera_isrc_fsh[];\n+extern const struct soc_enum madera_asrc1_rate[];\n+extern const struct soc_enum madera_asrc2_rate[];\n+extern const struct soc_enum madera_dfc_width[];\n+extern const struct soc_enum madera_dfc_type[];\n+extern const struct soc_enum madera_spdif_rate;\n+\n+extern const struct soc_enum madera_in_vi_ramp;\n+extern const struct soc_enum madera_in_vd_ramp;\n+\n+extern const struct soc_enum madera_out_vi_ramp;\n+extern const struct soc_enum madera_out_vd_ramp;\n+\n+extern const struct soc_enum madera_lhpf1_mode;\n+extern const struct soc_enum madera_lhpf2_mode;\n+extern const struct soc_enum madera_lhpf3_mode;\n+extern const struct soc_enum madera_lhpf4_mode;\n+\n+extern const struct soc_enum madera_ng_hold;\n+extern const struct soc_enum madera_in_hpf_cut_enum;\n+extern const struct soc_enum madera_in_dmic_osr[];\n+\n+extern const struct soc_enum madera_output_anc_src[];\n+extern const struct soc_enum madera_anc_input_src[];\n+extern const struct soc_enum madera_anc_ng_enum;\n+\n+extern const struct snd_kcontrol_new madera_dsp_trigger_output_mux[];\n+extern const struct snd_kcontrol_new madera_drc_activity_output_mux[];\n+\n+extern const struct snd_kcontrol_new madera_adsp_rate_controls[];\n+\n+const char *madera_sample_rate_val_to_name(unsigned int rate_val);\n+\n+int madera_dfc_put(struct snd_kcontrol *kcontrol,\n+\t\t   struct snd_ctl_elem_value *ucontrol);\n+\n+int madera_lp_mode_put(struct snd_kcontrol *kcontrol,\n+\t\t       struct snd_ctl_elem_value *ucontrol);\n+\n+int madera_out1_demux_put(struct snd_kcontrol *kcontrol,\n+\t\t\t  struct snd_ctl_elem_value *ucontrol);\n+\n+int madera_dre_put(struct snd_kcontrol *kcontrol,\n+\t\t   struct snd_ctl_elem_value *ucontrol);\n+\n+int madera_rate_put(struct snd_kcontrol *kcontrol,\n+\t\t    struct snd_ctl_elem_value *ucontrol);\n+\n+int madera_eq_coeff_put(struct snd_kcontrol *kcontrol,\n+\t\t\tstruct snd_ctl_elem_value *ucontrol);\n+int madera_lhpf_coeff_put(struct snd_kcontrol *kcontrol,\n+\t\t\t  struct snd_ctl_elem_value *ucontrol);\n+\n+int madera_sysclk_ev(struct snd_soc_dapm_widget *w,\n+\t\t     struct snd_kcontrol *kcontrol, int event);\n+int madera_spk_ev(struct snd_soc_dapm_widget *w,\n+\t\t  struct snd_kcontrol *kcontrol, int event);\n+int madera_in_ev(struct snd_soc_dapm_widget *w,\n+\t\t struct snd_kcontrol *kcontrol, int event);\n+int madera_out_ev(struct snd_soc_dapm_widget *w,\n+\t\t  struct snd_kcontrol *kcontrol, int event);\n+int madera_hp_ev(struct snd_soc_dapm_widget *w,\n+\t\t struct snd_kcontrol *kcontrol, int event);\n+int madera_anc_ev(struct snd_soc_dapm_widget *w,\n+\t\t  struct snd_kcontrol *kcontrol, int event);\n+int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,\n+\t\t\t struct snd_kcontrol *kcontrol,\n+\t\t\t int event);\n+\n+int madera_adsp_rate_info(struct snd_kcontrol *kcontrol,\n+\t\t\t  struct snd_ctl_elem_info *uinfo);\n+int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,\n+\t\t\t struct snd_ctl_elem_value *ucontrol);\n+int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,\n+\t\t\t struct snd_ctl_elem_value *ucontrol);\n+int madera_set_adsp_clk(struct madera_priv *priv, int dsp_num,\n+\t\t\tunsigned int freq);\n+\n+int madera_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source,\n+\t\t      unsigned int freq, int dir);\n+int madera_get_legacy_dspclk_setting(struct madera *madera, unsigned int freq);\n+void madera_spin_sysclk(struct madera_priv *priv);\n+\n+int madera_init_fll(struct madera *madera, int id, int base,\n+\t\t    struct madera_fll *fll);\n+int madera_set_fll_refclk(struct madera_fll *fll, int source,\n+\t\t\t  unsigned int Fref, unsigned int Fout);\n+int madera_set_fll_syncclk(struct madera_fll *fll, int source,\n+\t\t\t   unsigned int Fref, unsigned int Fout);\n+int madera_set_fll_ao_refclk(struct madera_fll *fll, int source,\n+\t\t\t     unsigned int fin, unsigned int fout);\n+\n+int madera_core_init(struct madera_priv *priv);\n+int madera_core_destroy(struct madera_priv *priv);\n+int madera_init_overheat(struct madera_priv *priv);\n+int madera_free_overheat(struct madera_priv *priv);\n+int madera_init_inputs(struct snd_soc_codec *codec,\n+\t\t       const char * const *dmic_inputs,\n+\t\t       int n_dmic_inputs,\n+\t\t       const char * const *dmic_refs,\n+\t\t       int n_dmic_refs);\n+int madera_init_outputs(struct snd_soc_codec *codec, int n_mono_routes);\n+int madera_init_bus_error_irq(struct madera_priv *priv, int dsp_num,\n+\t\t\t      irq_handler_t handler);\n+void madera_destroy_bus_error_irq(struct madera_priv *priv, int dsp_num);\n+\n+int madera_init_dai(struct madera_priv *priv, int dai);\n+\n+int madera_set_output_mode(struct snd_soc_codec *codec, int output, bool diff);\n+\n+/* Following functions are for use by machine drivers */\n+static inline int madera_register_notifier(struct snd_soc_codec *codec,\n+\t\t\t\t\t   struct notifier_block *nb)\n+{\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\n+\treturn blocking_notifier_chain_register(&madera->notifier, nb);\n+}\n+\n+static inline int madera_unregister_notifier(struct snd_soc_codec *codec,\n+\t\t\t\t\t     struct notifier_block *nb)\n+{\n+\tstruct madera *madera = dev_get_drvdata(codec->dev->parent);\n+\n+\treturn blocking_notifier_chain_unregister(&madera->notifier, nb);\n+}\n+\n+#endif\n",
    "prefixes": [
        "v5",
        "14/17"
    ]
}