* [PATCH mmc/next] mmc: sh_mmcif: Document r8a73a4, r8a7778 and sh73a0 DT bindings
From: Simon Horman @ 2016-11-25 7:56 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Magnus Damm,
linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Simon Horman
Simply document new compatibility strings as the driver is already
activated using a fallback compatibility string.
These compat strings are in keeping with those for all other
Renesas ARM based SoCs with sh_mmcif enabled in mainline.
Signed-off-by: Simon Horman <horms+renesas-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org>
---
Reposted with r8a7778 instead of r8a7779 in subject
I have also posted patches to use these new compat strings
to bring the DT files of the SoCs in question in-line with those
for other Renesas ARM based SoCs with sh_mmcif enabled in mainline.
---
Documentation/devicetree/bindings/mmc/renesas,mmcif.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
index ff611fa66871..e4ba92aa035e 100644
--- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
+++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
@@ -8,11 +8,14 @@ Required properties:
- compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
fallback. Examples with <soctype> are:
+ - "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
+ - "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
- "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
- "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
+ - "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs
- clocks: reference to the functional clock
--
2.7.0.rc3.207.g0ac5344
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v2 0/3] arm64: dts: r8a7796: Add CAN/CAN FD support
From: Simon Horman @ 2016-11-25 7:48 UTC (permalink / raw)
To: Chris Paterson
Cc: Marc Kleine-Budde, Rob Herring, Mark Rutland, Geert Uytterhoeven,
Ramesh Shanmugasundaram, linux-arm-kernel, devicetree,
linux-renesas-soc
In-Reply-To: <1480004021-4037-1-git-send-email-chris.paterson2@renesas.com>
On Thu, Nov 24, 2016 at 04:13:38PM +0000, Chris Paterson wrote:
> This series adds CAN and CAN FD support to the r8a7796.
>
> Changes since v1:
> - Split device tree changes from bindings documentation.
> - Rebased on renesas-devel-20161123v2-v4.9-rc6.
>
>
> Chris Paterson (3):
> arm64: dts: r8a7796: Add CAN external clock support
> arm64: dts: r8a7796: Add CAN support
> arm64: dts: r8a7796: Add CAN FD support
Thanks Chris,
I have queued these up for v4.11 in the devel branch of the renesas tree.
^ permalink raw reply
* Re: [PATCH v2 0/2] can: Add r8a7796 support to CAN/CAN FD
From: Marc Kleine-Budde @ 2016-11-25 7:19 UTC (permalink / raw)
To: Chris Paterson
Cc: Wolfgang Grandegger, Rob Herring, Mark Rutland,
Geert Uytterhoeven, Simon Horman, Ramesh Shanmugasundaram,
linux-can, netdev, devicetree, linux-renesas-soc
In-Reply-To: <1480003917-3953-1-git-send-email-chris.paterson2@renesas.com>
[-- Attachment #1.1: Type: text/plain, Size: 774 bytes --]
On 11/24/2016 05:11 PM, Chris Paterson wrote:
> This series adds support for r8a7796 to rcar_can and rcar_canfd.
>
> Original series: [PATCH 0/3] arm64: dts: r8a7796: Add CAN/CAN FD support.
>
> Changes since v1:
> - Split bindings documentation changes from device tree changes.
> - Rebased on renesas-devel-20161123v2-v4.9-rc6.
>
>
> Chris Paterson (2):
> can: rcar_can: Add r8a7796 support
> can: rcar_canfd: Add r8a7796 support
Both added to can-next.
Thanks,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v6 3/5] ARM: dts: sun8i-h3: add HDMI video nodes
From: Jean-François Moine @ 2016-11-25 6:57 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Dave Airlie, Maxime Ripard, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
In-Reply-To: <6896101480051640-ddF1QkQ5CrZxpj1cXAZ9Bg@public.gmane.org>
On Fri, 25 Nov 2016 13:27:20 +0800
Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org> wrote:
> > + assigned-clocks = <&ccu CLK_PLL_DE>,
>
> Cannot get the patch built on 4.9-rc, as CLK_PLL_DE is not an exported clock.
Hi,
Sorry, I forgot it. The symbol goes to
include/dt-bindings/clock/sun8i-h3-ccu.h
as:
#define CLK_PLL_DE 13
--
Ken ar c'hentañ | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* [PATCH 2/2] Documetationi: mmc: add cap-mmc-cmd23 proprerty's decription
From: Jaehoon Chung @ 2016-11-25 6:52 UTC (permalink / raw)
To: linux-mmc-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
adrian.hunter-ral2JQCrhuEAvxtiuMwx3w, Jaehoon Chung
In-Reply-To: <20161125065215.10833-1-jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This patch adds description for cap-mmc-cmd23.
There are two typse of multiple block read/write transaction.
One is Open-ended, other is Pre-defined block count(CMD23).
CMD23 is optional command. So user can choose this type.
Signed-off-by: Jaehoon Chung <jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 8a37782..29f60f6 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -52,6 +52,7 @@ Optional properties:
- no-sdio: controller is limited to send sdio cmd during initialization
- no-sd: controller is limited to send sd cmd during initialization
- no-mmc: controller is limited to send mmc cmd during initialization
+- cap-mmc-cmd23: CMD23(pre-defined block count) is supported
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted"
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 1/2] mmc: core: add DT binding for CMD23
From: Jaehoon Chung @ 2016-11-25 6:52 UTC (permalink / raw)
To: linux-mmc-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
adrian.hunter-ral2JQCrhuEAvxtiuMwx3w, Jaehoon Chung
Provide the option to configure one type of multiple block read/wrte
transatction (CMD23 - it's optional.)
Signed-off-by: Jaehoon Chung <jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
drivers/mmc/core/host.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 98f25ff..9bdc369 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -321,6 +321,8 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_NO_SD;
if (of_property_read_bool(np, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
+ if (of_property_read_bool(np, "cap-mmc-cmd23"))
+ host->caps |= MMC_CAP_CMD23;
host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) {
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* RE: [PATCH V3 2/4] mfd: pv88080: MFD core support
From: Eric Hyeung Dong Jeong @ 2016-11-25 6:03 UTC (permalink / raw)
To: Lee Jones, Eric Hyeung Dong Jeong
Cc: LINUX-KERNEL, Alexandre Courbot, DEVICETREE, LINUX-GPIO,
Liam Girdwood, Linus Walleij, Mark Brown, Mark Rutland,
Rob Herring, Support Opensource
In-Reply-To: <20161121130919.GB3917@dell>
On Monday, November 21, 2016 10:09 PM, Lee Jones Wrote:
>
> On Fri, 18 Nov 2016, Eric Jeong wrote:
>
> >
> > From: Eric Jeong <eric.jeong.opensource@diasemi.com>
> >
> > This patch adds supports for PV88080 MFD core device.
> >
> > It provides communication through the I2C interface.
> > It contains the following components:
> > - Regulators
> > - Configurable GPIOs
> >
> > Kconfig and Makefile are updated to reflect support for PV88080 PMIC.
> >
> > Signed-off-by: Eric Jeong <eric.jeong.opensource@diasemi.com>
> >
> > ---
> > This patch applies against linux-next and next-20161117
> >
> > Hi,
> >
> > This patch adds MFD core driver for PV88080 PMIC.
> > This is done as part of the existing PV88080 regulator driver by
> > expending the driver for GPIO function support.
> >
> > Change since PATCH V2
> > - Make one file insted of usging core and i2c file
> > - Use devm_ function to be managed resource automatically
> > - Separated mfd_cell and regmap_irq_chip declaration for clarification.
> > - Updated Kconfig to use OF and assign yes to I2C
> >
> > Change since PATCH V1
> > - Patch separated from PATCH V1
> >
> > Regards,
> > Eric Jeong, Dialog Semiconductor Ltd.
> >
> >
> > drivers/mfd/Kconfig | 12 ++
> > drivers/mfd/Makefile | 1 +
> > drivers/mfd/pv88080.c | 331 +++++++++++++++++++++++++++++++++++++++++++
> > include/linux/mfd/pv88080.h | 222 +++++++++++++++++++++++++++++
> > 4 files changed, 566 insertions(+)
> > create mode 100644 drivers/mfd/pv88080.c create mode 100644
> > include/linux/mfd/pv88080.h
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index
> > 06dc9b0..75abf2d 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -792,6 +792,18 @@ config MFD_PM8921_CORE
> > Say M here if you want to include support for PM8921 chip as a module.
> > This will build a module called "pm8921-core".
> >
> > +config MFD_PV88080
> > + tristate "Powerventure Semiconductor PV88080 PMIC Support"
> > + select MFD_CORE
> > + select REGMAP_I2C
> > + select REGMAP_IRQ
> > + depends on I2C=y && OF
> > + help
> > + Say yes here for support for the Powerventure Semiconductor PV88080 PMIC.
> > + This includes the I2C driver and core APIs.
> > + Additional drivers must be enabled in order to use the functionality
> > + of the device.
> > +
> > config MFD_QCOM_RPM
> > tristate "Qualcomm Resource Power Manager (RPM)"
> > depends on ARCH_QCOM && OF
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index
> > db39377..e9e16c6 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -173,6 +173,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
> > obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
> > obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
> > obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
> > +obj-$(CONFIG_MFD_PV88080) += pv88080.o
> > obj-$(CONFIG_MFD_QCOM_RPM) += qcom_rpm.o
> > obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
> > obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
> > diff --git a/drivers/mfd/pv88080.c b/drivers/mfd/pv88080.c new file
> > mode 100644 index 0000000..518b44f
> > --- /dev/null
> > +++ b/drivers/mfd/pv88080.c
> > @@ -0,0 +1,331 @@
> > +/*
> > + * pv88080-i2c.c - I2C access driver for PV88080
>
> Remove the filename.
>
> They have a habit of becoming out of date (like now).
OK, I will do that.
>
> > + * Copyright (C) 2016 Powerventure Semiconductor Ltd.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version 2
> > + * of the License, or (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/i2c.h>
> > +#include <linux/module.h>
> > +#include <linux/regmap.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/module.h>
>
> Alphabetical.
OK, I see.
>
> > +#include <linux/mfd/pv88080.h>
>
> This doesn't need to be separated from the rest.
OK.
>
> > +#define PV88080_REG_EVENT_A_OFFSET 0
> > +#define PV88080_REG_EVENT_B_OFFSET 1
> > +#define PV88080_REG_EVENT_C_OFFSET 2
>
> Spaces after 'define'.
OK I will do that.
>
> > +static const struct resource regulators_aa_resources[] = {
> > + {
> > + .name = "VDD_TEMP_FAULT",
> > + .start = PV88080_AA_IRQ_VDD_FLT,
> > + .end = PV88080_AA_IRQ_OVER_TEMP,
> > + .flags = IORESOURCE_IRQ,
> > + },
> > +};
> > +
> > +static const struct resource regulators_ba_resources[] = {
> > + {
> > + .name = "VDD_TEMP_FAULT",
> > + .start = PV88080_BA_IRQ_VDD_FLT,
> > + .end = PV88080_BA_IRQ_OVER_TEMP,
> > + .flags = IORESOURCE_IRQ,
> > + },
> > +};
>
> Use the DEFINE_RES_* macros.
I will use the macros.
>
> > +static const struct mfd_cell pv88080_aa_cells[] = {
> > + {
> > + .name = "pv88080-regulator",
> > + .num_resources = ARRAY_SIZE(regulators_aa_resources),
> > + .resources = regulators_aa_resources,
> > + .of_compatible = "pvs,pv88080-regulator",
> > + },
> > + {
> > + .name = "pv88080-gpio",
> > + .of_compatible = "pvs,pv88080-gpio",
> > + },
> > +};
> > +
> > +static const struct mfd_cell pv88080_ba_cells[] = {
> > + {
> > + .name = "pv88080-regulator",
> > + .num_resources = ARRAY_SIZE(regulators_ba_resources),
> > + .resources = regulators_ba_resources,
> > + .of_compatible = "pvs,pv88080-regulator",
> > + },
> > + {
> > + .name = "pv88080-gpio",
> > + .of_compatible = "pvs,pv88080-gpio",
> > + },
> > +};
> > +
> > +static const struct regmap_irq pv88080_aa_irqs[] = {
> > + /* PV88080 event A register for AA/AB silicon */
> > + [PV88080_AA_IRQ_VDD_FLT] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_VDD_FLT,
> > + },
> > + [PV88080_AA_IRQ_OVER_TEMP] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_OVER_TEMP,
> > + },
> > + [PV88080_AA_IRQ_SEQ_RDY] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_SEQ_RDY,
> > + },
> > + /* PV88080 event B register for AA/AB silicon */
> > + [PV88080_AA_IRQ_HVBUCK_OV] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_HVBUCK_OV,
> > + },
> > + [PV88080_AA_IRQ_HVBUCK_UV] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_HVBUCK_UV,
> > + },
> > + [PV88080_AA_IRQ_HVBUCK_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_HVBUCK_SCP,
> > + },
> > + [PV88080_AA_IRQ_BUCK1_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_BUCK1_SCP,
> > + },
> > + [PV88080_AA_IRQ_BUCK2_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_BUCK2_SCP,
> > + },
> > + [PV88080_AA_IRQ_BUCK3_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_BUCK3_SCP,
> > + },
> > + /* PV88080 event C register for AA/AB silicon */
> > + [PV88080_AA_IRQ_GPIO_FLAG0] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_GPIO_FLAG0,
> > + },
> > + [PV88080_AA_IRQ_GPIO_FLAG1] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_GPIO_FLAG1,
> > + },
> > +};
> > +
> > +static const struct regmap_irq pv88080_ba_irqs[] = {
> > + /* PV88080 event A register for BA/BB silicon */
> > + [PV88080_BA_IRQ_VDD_FLT] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_VDD_FLT,
> > + },
> > + [PV88080_BA_IRQ_OVER_TEMP] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_OVER_TEMP,
> > + },
> > + [PV88080_BA_IRQ_SEQ_RDY] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_SEQ_RDY,
> > + },
> > + [PV88080_BA_IRQ_EXT_OT] = {
> > + .reg_offset = PV88080_REG_EVENT_A_OFFSET,
> > + .mask = PV88080_M_EXT_OT,
> > + },
> > + /* PV88080 event B register for BA/BB silicon */
> > + [PV88080_BA_IRQ_HVBUCK_OV] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_HVBUCK_OV,
> > + },
> > + [PV88080_BA_IRQ_HVBUCK_UV] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_HVBUCK_UV,
> > + },
> > + [PV88080_BA_IRQ_HVBUCK_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_HVBUCK_SCP,
> > + },
> > + [PV88080_BA_IRQ_BUCK1_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_BUCK1_SCP,
> > + },
> > + [PV88080_BA_IRQ_BUCK2_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_BUCK2_SCP,
> > + },
> > + [PV88080_BA_IRQ_BUCK3_SCP] = {
> > + .reg_offset = PV88080_REG_EVENT_B_OFFSET,
> > + .mask = PV88080_M_BUCK3_SCP,
> > + },
> > + /* PV88080 event C register for BA/BB silicon */
> > + [PV88080_BA_IRQ_GPIO_FLAG0] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_GPIO_FLAG0,
> > + },
> > + [PV88080_BA_IRQ_GPIO_FLAG1] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_GPIO_FLAG1,
> > + },
> > + [PV88080_BA_IRQ_BUCK1_DROP_TIMEOUT] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_BUCK1_DROP_TIMEOUT,
> > + },
> > + [PV88080_BA_IRQ_BUCK2_DROP_TIMEOUT] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_BUCK2_DROP_TIMEOUT,
> > + },
> > + [PB88080_BA_IRQ_BUCK3_DROP_TIMEOUT] = {
> > + .reg_offset = PV88080_REG_EVENT_C_OFFSET,
> > + .mask = PV88080_M_BUCk3_DROP_TIMEOUT,
> > + },
> > +};
> > +
> > +static const struct regmap_irq_chip pv88080_aa_irq_chip = {
> > + .name = "pv88080-irq",
> > + .irqs = pv88080_aa_irqs,
> > + .num_irqs = ARRAY_SIZE(pv88080_aa_irqs),
> > + .num_regs = 3,
> > + .status_base = PV88080_REG_EVENT_A,
> > + .mask_base = PV88080_REG_MASK_A,
> > + .ack_base = PV88080_REG_EVENT_A,
> > + .init_ack_masked = true,
> > +};
> > +
> > +static const struct regmap_irq_chip pv88080_ba_irq_chip = {
> > + .name = "pv88080-irq",
> > + .irqs = pv88080_ba_irqs,
> > + .num_irqs = ARRAY_SIZE(pv88080_ba_irqs),
> > + .num_regs = 3,
> > + .status_base = PV88080_REG_EVENT_A,
> > + .mask_base = PV88080_REG_MASK_A,
> > + .ack_base = PV88080_REG_EVENT_A,
> > + .init_ack_masked = true,
> > +};
> > +
> > +static const struct regmap_config pv88080_regmap_config = {
> > + .reg_bits = 8,
> > + .val_bits = 8,
> > +};
> > +
> > +static const struct of_device_id pv88080_of_match_table[] = {
> > + { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA },
> > + { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA },
> > + { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA },
> > + { },
> > +};
> > +MODULE_DEVICE_TABLE(of, pv88080_of_match_table);
> > +
> > +static int pv88080_probe(struct i2c_client *client,
> > + const struct i2c_device_id *ids)
> > +{
> > + struct pv88080 *chip;
> > + const struct of_device_id *match;
> > + const struct regmap_irq_chip *pv88080_irq_chips;
> > + const struct mfd_cell *pv88080_mfd_cells;
> > + int ret, n_devs;
> > +
> > + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > + if (!chip)
> > + return -ENOMEM;
> > +
> > + if (client->dev.of_node) {
> > + match = of_match_node(pv88080_of_match_table,
> > + client->dev.of_node);
> > + if (!match) {
> > + dev_err(&client->dev, "Failed to get of_match_node\n");
> > + return -EINVAL;
>
> -ENODEV
OK, Thank you.
>
> > + }
> > + chip->type = (unsigned long)match->data;
> > + } else {
> > + chip->type = ids->driver_data;
> > + }
> > +
> > + i2c_set_clientdata(client, chip);
> > +
> > + chip->irq = client->irq;
> > + chip->dev = &client->dev;
> > +
> > + chip->regmap = devm_regmap_init_i2c(client, &pv88080_regmap_config);
> > + if (IS_ERR(chip->regmap)) {
> > + dev_err(chip->dev, "Failed to initialize register map\n");
> > + return PTR_ERR(chip->regmap);
> > + }
> > +
> > + ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF);
> > + if (ret < 0) {
> > + dev_err(chip->dev, "Failed to mask A reg: %d\n", ret);
> > + return ret;
> > + }
> > + ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF);
> > + if (ret < 0) {
> > + dev_err(chip->dev, "Failed to mask B reg: %d\n", ret);
> > + return ret;
> > + }
> > + ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF);
> > + if (ret < 0) {
> > + dev_err(chip->dev, "Failed to mask C reg: %d\n", ret);
> > + return ret;
> > + }
>
> What do these calls do?
You are right. I will remove those calls.
>
> > + switch (chip->type) {
> > + case TYPE_PV88080_AA:
> > + pv88080_irq_chips = &pv88080_aa_irq_chip;
> > + pv88080_mfd_cells = pv88080_aa_cells;
> > + n_devs = ARRAY_SIZE(pv88080_aa_cells);
> > + break;
> > + case TYPE_PV88080_BA:
> > + pv88080_irq_chips = &pv88080_ba_irq_chip;
> > + pv88080_mfd_cells = pv88080_ba_cells;
> > + n_devs = ARRAY_SIZE(pv88080_ba_cells);
> > + break;
> > + }
> > +
> > + ret = devm_regmap_add_irq_chip(chip->dev, chip->regmap,
> > + chip->irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> > + 0, pv88080_irq_chips, &chip->irq_data);
> > + if (ret) {
> > + dev_err(chip->dev, "Failed to add IRQ %d: %d\n",
> > + chip->irq, ret);
> > + return ret;
> > + }
> > +
> > + ret = devm_mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE,
> > + pv88080_mfd_cells, n_devs,
> > + NULL, 0, NULL);
> > + if (ret) {
> > + dev_err(chip->dev, "Failed to add MFD devices\n");
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct i2c_device_id pv88080_id_table[] = {
> > + { "pv88080", TYPE_PV88080_AA },
> > + { "pv88080-aa", TYPE_PV88080_AA },
> > + { "pv88080-ba", TYPE_PV88080_BA },
> > + { },
> > +};
> > +MODULE_DEVICE_TABLE(i2c, pv88080_id_table);
> > +
> > +static struct i2c_driver pv88080_driver = {
> > + .driver = {
> > + .name = "pv88080",
> > + .of_match_table = of_match_ptr(pv88080_of_match_table),
> > + },
> > + .probe = pv88080_probe,
> > + .id_table = pv88080_id_table,
> > +};
> > +module_i2c_driver(pv88080_driver);
> > +
> > +MODULE_AUTHOR("Eric Jeong <eric.jeong.opensource@diasemi.com>");
> > +MODULE_DESCRIPTION("MFD Driver for Powerventure PV88080");
> > +MODULE_LICENSE("GPL");
> > +
> > diff --git a/include/linux/mfd/pv88080.h b/include/linux/mfd/pv88080.h
> > new file mode 100644 index 0000000..76d6656
> > --- /dev/null
> > +++ b/include/linux/mfd/pv88080.h
> > @@ -0,0 +1,222 @@
> > +/*
> > + * pv88080.h - Declarations for PV88080.
>
> Remove filename.
OK. I will.
>
> > + * Copyright (C) 2016 Powerventure Semiconductor Ltd.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version 2
> > + * of the License, or (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#ifndef __PV88080_H__
> > +#define __PV88080_H__
> > +
> > +#include <linux/regulator/machine.h>
> > +#include <linux/device.h>
> > +#include <linux/regmap.h>
> > +
> > +/* System Control and Event Registers */
> > +#define PV88080_REG_STATUS_A 0x01
> > +#define PV88080_REG_EVENT_A 0x04
> > +#define PV88080_REG_MASK_A 0x09
> > +#define PV88080_REG_MASK_B 0x0A
> > +#define PV88080_REG_MASK_C 0x0B
> > +
> > +/* GPIO Registers - rev. AA */
> > +#define PV88080AA_REG_GPIO_INPUT 0x18
> > +#define PV88080AA_REG_GPIO_OUTPUT 0x19
> > +#define PV88080AA_REG_GPIO_GPIO0 0x1A
> > +
> > +/* Regulator Registers - rev. AA */
> > +#define PV88080AA_REG_HVBUCK_CONF1 0x2D
> > +#define PV88080AA_REG_HVBUCK_CONF2 0x2E
> > +#define PV88080AA_REG_BUCK1_CONF0 0x27
> > +#define PV88080AA_REG_BUCK1_CONF1 0x28
> > +#define PV88080AA_REG_BUCK1_CONF2 0x59
> > +#define PV88080AA_REG_BUCK1_CONF5 0x5C
> > +#define PV88080AA_REG_BUCK2_CONF0 0x29
> > +#define PV88080AA_REG_BUCK2_CONF1 0x2A
> > +#define PV88080AA_REG_BUCK2_CONF2 0x61
> > +#define PV88080AA_REG_BUCK2_CONF5 0x64
> > +#define PV88080AA_REG_BUCK3_CONF0 0x2B
> > +#define PV88080AA_REG_BUCK3_CONF1 0x2C
> > +#define PV88080AA_REG_BUCK3_CONF2 0x69
> > +#define PV88080AA_REG_BUCK3_CONF5 0x6C
> > +
> > +/* GPIO Registers - rev. BA */
> > +#define PV88080BA_REG_GPIO_INPUT 0x17
> > +#define PV88080BA_REG_GPIO_OUTPUT 0x18
> > +#define PV88080BA_REG_GPIO_GPIO0 0x19
> > +
> > +/* Regulator Registers - rev. BA */
> > +#define PV88080BA_REG_HVBUCK_CONF1 0x33
> > +#define PV88080BA_REG_HVBUCK_CONF2 0x34
> > +#define PV88080BA_REG_BUCK1_CONF0 0x2A
> > +#define PV88080BA_REG_BUCK1_CONF1 0x2C
> > +#define PV88080BA_REG_BUCK1_CONF2 0x5A
> > +#define PV88080BA_REG_BUCK1_CONF5 0x5D
> > +#define PV88080BA_REG_BUCK2_CONF0 0x2D
> > +#define PV88080BA_REG_BUCK2_CONF1 0x2F
> > +#define PV88080BA_REG_BUCK2_CONF2 0x63
> > +#define PV88080BA_REG_BUCK2_CONF5 0x66
> > +#define PV88080BA_REG_BUCK3_CONF0 0x30
> > +#define PV88080BA_REG_BUCK3_CONF1 0x32
> > +#define PV88080BA_REG_BUCK3_CONF2 0x6C
> > +#define PV88080BA_REG_BUCK3_CONF5 0x6F
> > +
> > +/* PV88080_REG_EVENT_A (addr=0x04) */
> > +#define PV88080_E_VDD_FLT 0x01
> > +#define PV88080_E_OVER_TEMP 0x02
> > +#define PV88080_E_SEQ_RDY 0x04
> > +#define PV88080_E_EXT_OT 0x08
> > +
> > +/* PV88080_REG_MASK_A (addr=0x09) */
> > +#define PV88080_M_VDD_FLT 0x01
> > +#define PV88080_M_OVER_TEMP 0x02
> > +#define PV88080_M_SEQ_RDY 0x04
> > +#define PV88080_M_EXT_OT 0x08
> > +
> > +/* PV88080_REG_EVENT_B (addr=0x05) */
> > +#define PV88080_E_HVBUCK_OV 0x01
> > +#define PV88080_E_HVBUCK_UV 0x02
> > +#define PV88080_E_HVBUCK_SCP 0x04
> > +#define PV88080_E_BUCK1_SCP 0x08
> > +#define PV88080_E_BUCK2_SCP 0x10
> > +#define PV88080_E_BUCK3_SCP 0x20
> > +
> > +/* PV88080_REG_MASK_B (addr=0x0A) */
> > +#define PV88080_M_HVBUCK_OV 0x01
> > +#define PV88080_M_HVBUCK_UV 0x02
> > +#define PV88080_M_HVBUCK_SCP 0x04
> > +#define PV88080_M_BUCK1_SCP 0x08
> > +#define PV88080_M_BUCK2_SCP 0x10
> > +#define PV88080_M_BUCK3_SCP 0x20
> > +
> > +/* PV88080_REG_EVENT_C (addr=0x06) */
> > +#define PV88080_E_GPIO_FLAG0 0x01
> > +#define PV88080_E_GPIO_FLAG1 0x02
> > +#define PV88080_E_BUCK1_DROP_TIMEOUT 0x08
> > +#define PV88080_E_BUCK2_DROP_TIMEOUT 0x10
> > +#define PV88080_E_BUCk3_DROP_TIMEOUT 0x20
> > +
> > +/* PV88080_REG_MASK_C (addr=0x0B) */
> > +#define PV88080_M_GPIO_FLAG0 0x01
> > +#define PV88080_M_GPIO_FLAG1 0x02
> > +#define PV88080_M_BUCK1_DROP_TIMEOUT 0x08
> > +#define PV88080_M_BUCK2_DROP_TIMEOUT 0x10
> > +#define PV88080_M_BUCk3_DROP_TIMEOUT 0x20
> > +
> > +/* PV88080xx_REG_GPIO_GPIO0 (addr=0x1A|0x19) */
> > +#define PV88080_GPIO_DIRECTION_MASK 0x01
> > +#define PV88080_GPIO_SINGLE_ENDED_MASK 0x02
> > +
> > +/* PV88080_REG_BUCK1_CONF0 (addr=0x27|0x2A) */
> > +#define PV88080_BUCK1_EN 0x80
> > +#define PV88080_VBUCK1_MASK 0x7F
> > +
> > +/* PV88080_REG_BUCK2_CONF0 (addr=0x29|0x2D) */
> > +#define PV88080_BUCK2_EN 0x80
> > +#define PV88080_VBUCK2_MASK 0x7F
> > +
> > +/* PV88080_REG_BUCK3_CONF0 (addr=0x2B|0x30) */
> > +#define PV88080_BUCK3_EN 0x80
> > +#define PV88080_VBUCK3_MASK 0x7F
> > +
> > +/* PV88080_REG_BUCK1_CONF1 (addr=0x28|0x2C) */
> > +#define PV88080_BUCK1_ILIM_SHIFT 2
> > +#define PV88080_BUCK1_ILIM_MASK 0x0C
> > +#define PV88080_BUCK1_MODE_MASK 0x03
> > +
> > +/* PV88080_REG_BUCK2_CONF1 (addr=0x2A|0x2F) */
> > +#define PV88080_BUCK2_ILIM_SHIFT 2
> > +#define PV88080_BUCK2_ILIM_MASK 0x0C
> > +#define PV88080_BUCK2_MODE_MASK 0x03
> > +
> > +/* PV88080_REG_BUCK3_CONF1 (addr=0x2C|0x32) */
> > +#define PV88080_BUCK3_ILIM_SHIFT 2
> > +#define PV88080_BUCK3_ILIM_MASK 0x0C
> > +#define PV88080_BUCK3_MODE_MASK 0x03
> > +
> > +#define PV88080_BUCK_MODE_SLEEP 0x00
> > +#define PV88080_BUCK_MODE_AUTO 0x01
> > +#define PV88080_BUCK_MODE_SYNC 0x02
> > +
> > +/* PV88080_REG_HVBUCK_CONF1 (addr=0x2D|0x33) */
> > +#define PV88080_VHVBUCK_MASK 0xFF
> > +
> > +/* PV88080_REG_HVBUCK_CONF1 (addr=0x2E|0x34) */
> > +#define PV88080_HVBUCK_EN 0x01
> > +
> > +/* PV88080_REG_BUCK2_CONF2 (addr=0x61|0x63) */
> > +/* PV88080_REG_BUCK3_CONF2 (addr=0x69|0x6C) */
> > +#define PV88080_BUCK_VDAC_RANGE_SHIFT 7
> > +#define PV88080_BUCK_VDAC_RANGE_MASK 0x01
> > +
> > +#define PV88080_BUCK_VDAC_RANGE_1 0x00
> > +#define PV88080_BUCK_VDAC_RANGE_2 0x01
> > +
> > +/* PV88080_REG_BUCK2_CONF5 (addr=0x64|0x66) */
> > +/* PV88080_REG_BUCK3_CONF5 (addr=0x6C|0x6F) */
> > +#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0
> > +#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
> > +
> > +#define PV88080_BUCK_VRANGE_GAIN_1 0x00
> > +#define PV88080_BUCK_VRANGE_GAIN_2 0x01
> > +
> > +#define PV88080_MAX_REGULATORS 4
> > +
> > +enum pv88080_types {
> > + TYPE_PV88080_AA,
> > + TYPE_PV88080_BA,
> > +};
> > +
> > +/* Interrupts */
> > +enum pv88080_aa_irqs {
> > + PV88080_AA_IRQ_VDD_FLT,
> > + PV88080_AA_IRQ_OVER_TEMP,
> > + PV88080_AA_IRQ_SEQ_RDY,
> > + PV88080_AA_IRQ_HVBUCK_OV,
> > + PV88080_AA_IRQ_HVBUCK_UV,
> > + PV88080_AA_IRQ_HVBUCK_SCP,
> > + PV88080_AA_IRQ_BUCK1_SCP,
> > + PV88080_AA_IRQ_BUCK2_SCP,
> > + PV88080_AA_IRQ_BUCK3_SCP,
> > + PV88080_AA_IRQ_GPIO_FLAG0,
> > + PV88080_AA_IRQ_GPIO_FLAG1,
> > +};
> > +
> > +enum pv88080_ba_irqs {
> > + PV88080_BA_IRQ_VDD_FLT,
> > + PV88080_BA_IRQ_OVER_TEMP,
> > + PV88080_BA_IRQ_SEQ_RDY,
> > + PV88080_BA_IRQ_EXT_OT,
> > + PV88080_BA_IRQ_HVBUCK_OV,
> > + PV88080_BA_IRQ_HVBUCK_UV,
> > + PV88080_BA_IRQ_HVBUCK_SCP,
> > + PV88080_BA_IRQ_BUCK1_SCP,
> > + PV88080_BA_IRQ_BUCK2_SCP,
> > + PV88080_BA_IRQ_BUCK3_SCP,
> > + PV88080_BA_IRQ_GPIO_FLAG0,
> > + PV88080_BA_IRQ_GPIO_FLAG1,
> > + PV88080_BA_IRQ_BUCK1_DROP_TIMEOUT,
> > + PV88080_BA_IRQ_BUCK2_DROP_TIMEOUT,
> > + PB88080_BA_IRQ_BUCK3_DROP_TIMEOUT,
> > +};
> > +
> > +struct pv88080 {
> > + struct device *dev;
> > + struct regmap *regmap;
> > + unsigned long type;
>
> Does this really need to be in here?
The *type* member is used for separating silicon type.
And, regulator and gpio driver also use the member to check the type
for proper configuration without additional code.
That is the reason that the member is added in the structure.
>
> > + /* IRQ Data */
> > + int irq;
> > + struct regmap_irq_chip_data *irq_data; };
> > +
> > +#endif /* __PV88080_H__ */
> > +
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for
> ARM SoCs Follow Linaro: Facebook | Twitter | Blog
I have added some comments. Thank you.
Regards
Eric
^ permalink raw reply
* Re: [PATCH 02/10] ASoC: sunxi: Add support for A23/A33/H3 codec's analog path controls
From: Icenowy Zheng @ 2016-11-25 5:51 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Mark Rutland, devicetree@vger.kernel.org,
alsa-devel@alsa-project.org, Liam Girdwood, Rob Herring,
linux-kernel@vger.kernel.org, Mark Brown, Maxime Ripard,
Mylene Josserand, Lee Jones, linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAGb2v66Zb9-UdimKDn5tq9UPRY7wBZNNCCn-52bf=evP914sPg@mail.gmail.com>
25.11.2016, 13:46, "Chen-Yu Tsai" <wens@csie.org>:
> On Fri, Nov 25, 2016 at 1:43 PM, Icenowy Zheng <icenowy@aosc.xyz> wrote:
>> 12.11.2016, 14:57, "Chen-Yu Tsai" <wens@csie.org>:
>>> The internal codec on A23/A33/H3 is split into 2 parts. The
>>> analog path controls are routed through an embedded custom register
>>> bus accessed through the PRCM block.
>>>
>>> The SoCs share a common set of inputs, outputs, and audio paths.
>>> The following table lists the differences.
>>>
>>> ----------------------------------------
>>> | Feature \ SoC | A23 | A33 | H3 |
>>> ----------------------------------------
>>> | Headphone | v | v | |
>>> ----------------------------------------
>>> | Line Out | | | v |
>>> ----------------------------------------
>>> | Phone In/Out | v | v | |
>>> ----------------------------------------
>>>
>>> Add an ASoC component driver for it. This should be tied to the codec
>>> audio card as an auxiliary device. This patch adds the commont paths
>>> and controls, and variant specific headphone out and line out.
>>>
>>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>> ---
>>> sound/soc/sunxi/Kconfig | 8 +
>>> sound/soc/sunxi/Makefile | 1 +
>>> sound/soc/sunxi/sun8i-codec-analog.c | 665 +++++++++++++++++++++++++++++++++++
>>> 3 files changed, 674 insertions(+)
>>> create mode 100644 sound/soc/sunxi/sun8i-codec-analog.c
>>>
>>> diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
>>> index dd2368297fd3..6c344e16aca4 100644
>>> --- a/sound/soc/sunxi/Kconfig
>>> +++ b/sound/soc/sunxi/Kconfig
>>> @@ -9,6 +9,14 @@ config SND_SUN4I_CODEC
>>> Select Y or M to add support for the Codec embedded in the Allwinner
>>> A10 and affiliated SoCs.
>>>
>>> +config SND_SUN8I_CODEC_ANALOG
>>> + tristate "Allwinner sun8i Codec Analog Controls Support"
>>> + depends on MACH_SUN8I || COMPILE_TEST
>>
>> sun50i-a64 has a similar (or the same?) codec to A33.
>
> I think the register offsets/fields were moved around again.
> Why does Allwinner always do that... :/
Yes, moved around :-(
Or maybe I should say "there's more registers on A64".
>
> ChenYu
>
>>> + select REGMAP
>>> + help
>>> + Say Y or M if you want to add support for the analog controls for
>>> + the codec embedded in newer Allwinner SoCs.
>>> +
>>> config SND_SUN4I_I2S
>>> tristate "Allwinner A10 I2S Support"
>>> select SND_SOC_GENERIC_DMAENGINE_PCM
>>> diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
>>> index 604c7b842837..241c0df9ca0c 100644
>>> --- a/sound/soc/sunxi/Makefile
>>> +++ b/sound/soc/sunxi/Makefile
>>> @@ -1,3 +1,4 @@
>>> obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
>>> obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
>>> obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
>>> +obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
>>> diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
>>> new file mode 100644
>>> index 000000000000..222bbd440b1e
>>> --- /dev/null
>>> +++ b/sound/soc/sunxi/sun8i-codec-analog.c
>>> @@ -0,0 +1,665 @@
>>> +/*
>>> + * This driver supports the analog controls for the internal codec
>>> + * found in Allwinner's A31s, A23, A33 and H3 SoCs.
>>> + *
>>> + * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + * GNU General Public License for more details.
>>> + */
>>> +
>>> +#include <linux/io.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/regmap.h>
>>> +
>>> +#include <sound/soc.h>
>>> +#include <sound/soc-dapm.h>
>>> +#include <sound/tlv.h>
>>> +
>>> +/* Codec analog control register offsets and bit fields */
>>> +#define SUN8I_ADDA_HP_VOLC 0x00
>>> +#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7
>>> +#define SUN8I_ADDA_HP_VOLC_HP_VOL 0
>>> +#define SUN8I_ADDA_LOMIXSC 0x01
>>> +#define SUN8I_ADDA_LOMIXSC_MIC1 6
>>> +#define SUN8I_ADDA_LOMIXSC_MIC2 5
>>> +#define SUN8I_ADDA_LOMIXSC_PHONE 4
>>> +#define SUN8I_ADDA_LOMIXSC_PHONEN 3
>>> +#define SUN8I_ADDA_LOMIXSC_LINEINL 2
>>> +#define SUN8I_ADDA_LOMIXSC_DACL 1
>>> +#define SUN8I_ADDA_LOMIXSC_DACR 0
>>> +#define SUN8I_ADDA_ROMIXSC 0x02
>>> +#define SUN8I_ADDA_ROMIXSC_MIC1 6
>>> +#define SUN8I_ADDA_ROMIXSC_MIC2 5
>>> +#define SUN8I_ADDA_ROMIXSC_PHONE 4
>>> +#define SUN8I_ADDA_ROMIXSC_PHONEP 3
>>> +#define SUN8I_ADDA_ROMIXSC_LINEINR 2
>>> +#define SUN8I_ADDA_ROMIXSC_DACR 1
>>> +#define SUN8I_ADDA_ROMIXSC_DACL 0
>>> +#define SUN8I_ADDA_DAC_PA_SRC 0x03
>>> +#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7
>>> +#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6
>>> +#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5
>>> +#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4
>>> +#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3
>>> +#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2
>>> +#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1
>>> +#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0
>>> +#define SUN8I_ADDA_PHONEIN_GCTRL 0x04
>>> +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4
>>> +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0
>>> +#define SUN8I_ADDA_LINEIN_GCTRL 0x05
>>> +#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4
>>> +#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0
>>> +#define SUN8I_ADDA_MICIN_GCTRL 0x06
>>> +#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4
>>> +#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL 0x07
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1
>>> +#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL 0x08
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1
>>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0
>>> +#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09
>>> +#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3
>>> +#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0
>>> +#define SUN8I_ADDA_MIC2G_CTRL 0x0a
>>> +#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7
>>> +#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4
>>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3
>>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2
>>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1
>>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0
>>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b
>>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7
>>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6
>>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5
>>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3
>>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0
>>> +#define SUN8I_ADDA_LADCMIXSC 0x0c
>>> +#define SUN8I_ADDA_LADCMIXSC_MIC1 6
>>> +#define SUN8I_ADDA_LADCMIXSC_MIC2 5
>>> +#define SUN8I_ADDA_LADCMIXSC_PHONE 4
>>> +#define SUN8I_ADDA_LADCMIXSC_PHONEN 3
>>> +#define SUN8I_ADDA_LADCMIXSC_LINEINL 2
>>> +#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1
>>> +#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0
>>> +#define SUN8I_ADDA_RADCMIXSC 0x0d
>>> +#define SUN8I_ADDA_RADCMIXSC_MIC1 6
>>> +#define SUN8I_ADDA_RADCMIXSC_MIC2 5
>>> +#define SUN8I_ADDA_RADCMIXSC_PHONE 4
>>> +#define SUN8I_ADDA_RADCMIXSC_PHONEP 3
>>> +#define SUN8I_ADDA_RADCMIXSC_LINEINR 2
>>> +#define SUN8I_ADDA_RADCMIXSC_OMIXR 1
>>> +#define SUN8I_ADDA_RADCMIXSC_OMIXL 0
>>> +#define SUN8I_ADDA_RES 0x0e
>>> +#define SUN8I_ADDA_RES_MMICBIAS_SEL 4
>>> +#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0
>>> +#define SUN8I_ADDA_ADC_AP_EN 0x0f
>>> +#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7
>>> +#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
>>> +#define SUN8I_ADDA_ADC_AP_EN_ADCG 0
>>> +
>>> +/* Analog control register access bits */
>>> +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
>>> +#define ADDA_PR_RESET BIT(28)
>>> +#define ADDA_PR_WRITE BIT(24)
>>> +#define ADDA_PR_ADDR_SHIFT 16
>>> +#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
>>> +#define ADDA_PR_DATA_IN_SHIFT 8
>>> +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
>>> +#define ADDA_PR_DATA_OUT_SHIFT 0
>>> +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
>>> +
>>> +/* regmap access bits */
>>> +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
>>> +{
>>> + void __iomem *base = (void __iomem *)context;
>>> + u32 tmp;
>>> +
>>> + /* De-assert reset */
>>> + writel(readl(base) | ADDA_PR_RESET, base);
>>> +
>>> + /* Clear write bit */
>>> + writel(readl(base) & ~ADDA_PR_WRITE, base);
>>> +
>>> + /* Set register address */
>>> + tmp = readl(base);
>>> + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
>>> + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
>>> + writel(tmp, base);
>>> +
>>> + /* Read back value */
>>> + *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
>>> +{
>>> + void __iomem *base = (void __iomem *)context;
>>> + u32 tmp;
>>> +
>>> + /* De-assert reset */
>>> + writel(readl(base) | ADDA_PR_RESET, base);
>>> +
>>> + /* Set register address */
>>> + tmp = readl(base);
>>> + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
>>> + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
>>> + writel(tmp, base);
>>> +
>>> + /* Set data to write */
>>> + tmp = readl(base);
>>> + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
>>> + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
>>> + writel(tmp, base);
>>> +
>>> + /* Set write bit to signal a write */
>>> + writel(readl(base) | ADDA_PR_WRITE, base);
>>> +
>>> + /* Clear write bit */
>>> + writel(readl(base) & ~ADDA_PR_WRITE, base);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static const struct regmap_config adda_pr_regmap_cfg = {
>>> + .name = "adda-pr",
>>> + .reg_bits = 5,
>>> + .reg_stride = 1,
>>> + .val_bits = 8,
>>> + .reg_read = adda_reg_read,
>>> + .reg_write = adda_reg_write,
>>> + .fast_io = true,
>>> + .max_register = 24,
>>> +};
>>> +
>>> +/* mixer controls */
>>> +static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
>>> + SOC_DAPM_DOUBLE_R("DAC Playback Switch",
>>> + SUN8I_ADDA_LOMIXSC,
>>> + SUN8I_ADDA_ROMIXSC,
>>> + SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
>>> + SUN8I_ADDA_LOMIXSC,
>>> + SUN8I_ADDA_ROMIXSC,
>>> + SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Line In Playback Switch",
>>> + SUN8I_ADDA_LOMIXSC,
>>> + SUN8I_ADDA_ROMIXSC,
>>> + SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
>>> + SUN8I_ADDA_LOMIXSC,
>>> + SUN8I_ADDA_ROMIXSC,
>>> + SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
>>> + SUN8I_ADDA_LOMIXSC,
>>> + SUN8I_ADDA_ROMIXSC,
>>> + SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
>>> +};
>>> +
>>> +/* ADC mixer controls */
>>> +static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
>>> + SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
>>> + SUN8I_ADDA_LADCMIXSC,
>>> + SUN8I_ADDA_RADCMIXSC,
>>> + SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
>>> + SUN8I_ADDA_LADCMIXSC,
>>> + SUN8I_ADDA_RADCMIXSC,
>>> + SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Line In Capture Switch",
>>> + SUN8I_ADDA_LADCMIXSC,
>>> + SUN8I_ADDA_RADCMIXSC,
>>> + SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
>>> + SUN8I_ADDA_LADCMIXSC,
>>> + SUN8I_ADDA_RADCMIXSC,
>>> + SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
>>> + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
>>> + SUN8I_ADDA_LADCMIXSC,
>>> + SUN8I_ADDA_RADCMIXSC,
>>> + SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
>>> +};
>>> +
>>> +/* volume / mute controls */
>>> +static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
>>> + -450, 150, 0);
>>> +static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale,
>>> + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
>>> + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
>>> +);
>>> +
>>> +static const struct snd_kcontrol_new sun8i_codec_common_controls[] = {
>>> + /* Mixer pre-gains */
>>> + SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL,
>>> + SUN8I_ADDA_LINEIN_GCTRL_LINEING,
>>> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>>> + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL,
>>> + SUN8I_ADDA_MICIN_GCTRL_MIC1G,
>>> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>>> + SOC_SINGLE_TLV("Mic2 Playback Volume",
>>> + SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G,
>>> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>>> +
>>> + /* Microphone Amp boost gains */
>>> + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0,
>>> + sun8i_codec_mic_gain_scale),
>>> + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL,
>>> + SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0,
>>> + sun8i_codec_mic_gain_scale),
>>> +
>>> + /* ADC */
>>> + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN,
>>> + SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0,
>>> + sun8i_codec_out_mixer_pregain_scale),
>>> +};
>>> +
>>> +static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
>>> + /* ADC */
>>> + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
>>> + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
>>> + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
>>> + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
>>> +
>>> + /* DAC */
>>> + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
>>> + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
>>> + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
>>> + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
>>> + /*
>>> + * Due to this component and the codec belonging to separate DAPM
>>> + * contexts, we need to manually link the above widgets to their
>>> + * stream widgets at the card level.
>>> + */
>>> +
>>> + /* Line In */
>>> + SND_SOC_DAPM_INPUT("LINEIN"),
>>> +
>>> + /* Microphone inputs */
>>> + SND_SOC_DAPM_INPUT("MIC1"),
>>> + SND_SOC_DAPM_INPUT("MIC2"),
>>> +
>>> + /* Microphone Bias */
>>> + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
>>> + 0, NULL, 0),
>>> +
>>> + /* Mic input path */
>>> + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
>>> + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
>>> + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
>>> +
>>> + /* Mixers */
>>> + SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
>>> + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
>>> + sun8i_codec_mixer_controls,
>>> + ARRAY_SIZE(sun8i_codec_mixer_controls)),
>>> + SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
>>> + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
>>> + sun8i_codec_mixer_controls,
>>> + ARRAY_SIZE(sun8i_codec_mixer_controls)),
>>> + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
>>> + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
>>> + sun8i_codec_adc_mixer_controls,
>>> + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
>>> + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
>>> + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
>>> + sun8i_codec_adc_mixer_controls,
>>> + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
>>> +};
>>> +
>>> +static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
>>> + /* Microphone Routes */
>>> + { "Mic1 Amplifier", NULL, "MIC1"},
>>> + { "Mic2 Amplifier", NULL, "MIC2"},
>>> +
>>> + /* Left Mixer Routes */
>>> + { "Left Mixer", "DAC Playback Switch", "Left DAC" },
>>> + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
>>> + { "Left Mixer", "Line In Playback Switch", "LINEIN" },
>>> + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
>>> + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
>>> +
>>> + /* Right Mixer Routes */
>>> + { "Right Mixer", "DAC Playback Switch", "Right DAC" },
>>> + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
>>> + { "Right Mixer", "Line In Playback Switch", "LINEIN" },
>>> + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
>>> + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
>>> +
>>> + /* Left ADC Mixer Routes */
>>> + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
>>> + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
>>> + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
>>> + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
>>> + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
>>> +
>>> + /* Right ADC Mixer Routes */
>>> + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
>>> + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
>>> + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
>>> + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
>>> + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
>>> +
>>> + /* ADC Routes */
>>> + { "Left ADC", NULL, "Left ADC Mixer" },
>>> + { "Right ADC", NULL, "Right ADC Mixer" },
>>> +};
>>> +
>>> +/* headphone specific controls, widgets, and routes */
>>> +static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
>>> +static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
>>> + SOC_SINGLE_TLV("Headphone Playback Volume",
>>> + SUN8I_ADDA_HP_VOLC,
>>> + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
>>> + sun8i_codec_hp_vol_scale),
>>> + SOC_DOUBLE("Headphone Playback Switch",
>>> + SUN8I_ADDA_DAC_PA_SRC,
>>> + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
>>> + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
>>> +};
>>> +
>>> +static const char * const sun8i_codec_hp_src_enum_text[] = {
>>> + "DAC", "Mixer",
>>> +};
>>> +
>>> +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum,
>>> + SUN8I_ADDA_DAC_PA_SRC,
>>> + SUN8I_ADDA_DAC_PA_SRC_LHPIS,
>>> + SUN8I_ADDA_DAC_PA_SRC_RHPIS,
>>> + sun8i_codec_hp_src_enum_text);
>>> +
>>> +static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
>>> + SOC_DAPM_ENUM("Headphone Source Playback Route",
>>> + sun8i_codec_hp_src_enum),
>>> +};
>>> +
>>> +static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
>>> + SND_SOC_DAPM_MUX("Headphone Source Playback Route",
>>> + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
>>> + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
>>> + SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0),
>>> + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
>>> + SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
>>> + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
>>> + SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0),
>>> + SND_SOC_DAPM_OUTPUT("HP"),
>>> +};
>>> +
>>> +static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
>>> + { "Headphone Source Playback Route", "DAC", "Left DAC" },
>>> + { "Headphone Source Playback Route", "DAC", "Right DAC" },
>>> + { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
>>> + { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
>>> + { "Headphone Amp", NULL, "Headphone Source Playback Route" },
>>> + { "HPCOM", NULL, "HPCOM Protection" },
>>> + { "HP", NULL, "Headphone Amp" },
>>> +};
>>> +
>>> +static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
>>> +{
>>> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>>> + struct device *dev = cmpnt->dev;
>>> + int ret;
>>> +
>>> + ret = snd_soc_add_component_controls(cmpnt,
>>> + sun8i_codec_headphone_controls,
>>> + ARRAY_SIZE(sun8i_codec_headphone_controls));
>>> + if (ret) {
>>> + dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
>>> + ARRAY_SIZE(sun8i_codec_headphone_widgets));
>>> + if (ret) {
>>> + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes,
>>> + ARRAY_SIZE(sun8i_codec_headphone_routes));
>>> + if (ret) {
>>> + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/* hmic specific widget */
>>> +static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
>>> + SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN,
>>> + 0, NULL, 0),
>>> +};
>>> +
>>> +static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt)
>>> +{
>>> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>>> + struct device *dev = cmpnt->dev;
>>> + int ret;
>>> +
>>> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets,
>>> + ARRAY_SIZE(sun8i_codec_hmic_widgets));
>>> + if (ret)
>>> + dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret);
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +/* line out specific controls, widgets and routes */
>>> +static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
>>> + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
>>> + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
>>> +);
>>> +static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
>>> + SOC_SINGLE_TLV("Line Out Playback Volume",
>>> + SUN8I_ADDA_PHONE_GAIN_CTRL,
>>> + SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0,
>>> + sun8i_codec_lineout_vol_scale),
>>> + SOC_DOUBLE("Line Out Playback Switch",
>>> + SUN8I_ADDA_MIC2G_CTRL,
>>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN,
>>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
>>> +};
>>> +
>>> +static const char * const sun8i_codec_lineout_src_enum_text[] = {
>>> + "Stereo", "Mono Differential",
>>> +};
>>> +
>>> +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
>>> + SUN8I_ADDA_MIC2G_CTRL,
>>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC,
>>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
>>> + sun8i_codec_lineout_src_enum_text);
>>> +
>>> +static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
>>> + SOC_DAPM_ENUM("Line Out Source Playback Route",
>>> + sun8i_codec_lineout_src_enum),
>>> +};
>>> +
>>> +static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
>>> + SND_SOC_DAPM_MUX("Line Out Source Playback Route",
>>> + SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
>>> + /* It is unclear if this is a buffer or gate, model it as a supply */
>>> + SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL,
>>> + SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0),
>>> + SND_SOC_DAPM_OUTPUT("LINEOUT"),
>>> +};
>>> +
>>> +static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
>>> + { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
>>> + { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
>>> + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
>>> + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
>>> + { "LINEOUT", NULL, "Line Out Source Playback Route" },
>>> + { "LINEOUT", NULL, "Line Out Enable", },
>>> +};
>>> +
>>> +static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
>>> +{
>>> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>>> + struct device *dev = cmpnt->dev;
>>> + int ret;
>>> +
>>> + ret = snd_soc_add_component_controls(cmpnt,
>>> + sun8i_codec_lineout_controls,
>>> + ARRAY_SIZE(sun8i_codec_lineout_controls));
>>> + if (ret) {
>>> + dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets,
>>> + ARRAY_SIZE(sun8i_codec_lineout_widgets));
>>> + if (ret) {
>>> + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes,
>>> + ARRAY_SIZE(sun8i_codec_lineout_routes));
>>> + if (ret) {
>>> + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +struct sun8i_codec_analog_quirks {
>>> + bool has_headphone;
>>> + bool has_hmic;
>>> + bool has_lineout;
>>> +};
>>> +
>>> +static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
>>> + .has_headphone = true,
>>> + .has_hmic = true,
>>> +};
>>> +
>>> +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
>>> + .has_lineout = true,
>>> +};
>>> +
>>> +static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
>>> +{
>>> + struct device *dev = cmpnt->dev;
>>> + const struct sun8i_codec_analog_quirks *quirks;
>>> + int ret;
>>> +
>>> + /*
>>> + * This would never return NULL unless someone directly registers a
>>> + * platform device matching this driver's name, without specifying a
>>> + * device tree node.
>>> + */
>>> + quirks = of_device_get_match_data(dev);
>>> +
>>> + /* Add controls, widgets, and routes for individual features */
>>> +
>>> + if (quirks->has_headphone) {
>>> + ret = sun8i_codec_add_headphone(cmpnt);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> + if (quirks->has_hmic) {
>>> + sun8i_codec_add_hmic(cmpnt);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> + if (quirks->has_lineout) {
>>> + ret = sun8i_codec_add_lineout(cmpnt);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
>>> + .controls = sun8i_codec_common_controls,
>>> + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls),
>>> + .dapm_widgets = sun8i_codec_common_widgets,
>>> + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets),
>>> + .dapm_routes = sun8i_codec_common_routes,
>>> + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes),
>>> + .probe = sun8i_codec_analog_cmpnt_probe,
>>> +};
>>> +
>>> +static const struct of_device_id sun8i_codec_analog_of_match[] = {
>>> + {
>>> + .compatible = "allwinner,sun8i-a23-codec-analog",
>>> + .data = &sun8i_a23_quirks,
>>> + },
>>> + {
>>> + .compatible = "allwinner,sun8i-h3-codec-analog",
>>> + .data = &sun8i_h3_quirks,
>>> + },
>>> + {}
>>> +};
>>> +MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
>>> +
>>> +static int sun8i_codec_analog_probe(struct platform_device *pdev)
>>> +{
>>> + struct resource *res;
>>> + struct regmap *regmap;
>>> + void __iomem *base;
>>> +
>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> + base = devm_ioremap_resource(&pdev->dev, res);
>>> + if (IS_ERR(base)) {
>>> + dev_err(&pdev->dev, "Failed to map the registers\n");
>>> + return PTR_ERR(base);
>>> + }
>>> +
>>> + regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg);
>>> + if (IS_ERR(regmap)) {
>>> + dev_err(&pdev->dev, "Failed to create regmap\n");
>>> + return PTR_ERR(regmap);
>>> + }
>>> +
>>> + return devm_snd_soc_register_component(&pdev->dev,
>>> + &sun8i_codec_analog_cmpnt_drv,
>>> + NULL, 0);
>>> +}
>>> +
>>> +static struct platform_driver sun8i_codec_analog_driver = {
>>> + .driver = {
>>> + .name = "sun8i-codec-analog",
>>> + .of_match_table = sun8i_codec_analog_of_match,
>>> + },
>>> + .probe = sun8i_codec_analog_probe,
>>> +};
>>> +module_platform_driver(sun8i_codec_analog_driver);
>>> +
>>> +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver");
>>> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
>>> +MODULE_LICENSE("GPL");
>>> +MODULE_ALIAS("platform:sun8i-codec-analog");
>>> --
>>> 2.10.2
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 02/10] ASoC: sunxi: Add support for A23/A33/H3 codec's analog path controls
From: Chen-Yu Tsai @ 2016-11-25 5:45 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Mark Rutland, devicetree@vger.kernel.org,
alsa-devel@alsa-project.org, Mark Brown, Liam Girdwood,
linux-kernel@vger.kernel.org, Chen-Yu Tsai, Rob Herring,
Maxime Ripard, Mylene Josserand, Lee Jones,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <901011480052591@web1j.yandex.ru>
On Fri, Nov 25, 2016 at 1:43 PM, Icenowy Zheng <icenowy@aosc.xyz> wrote:
>
>
> 12.11.2016, 14:57, "Chen-Yu Tsai" <wens@csie.org>:
>> The internal codec on A23/A33/H3 is split into 2 parts. The
>> analog path controls are routed through an embedded custom register
>> bus accessed through the PRCM block.
>>
>> The SoCs share a common set of inputs, outputs, and audio paths.
>> The following table lists the differences.
>>
>> ----------------------------------------
>> | Feature \ SoC | A23 | A33 | H3 |
>> ----------------------------------------
>> | Headphone | v | v | |
>> ----------------------------------------
>> | Line Out | | | v |
>> ----------------------------------------
>> | Phone In/Out | v | v | |
>> ----------------------------------------
>>
>> Add an ASoC component driver for it. This should be tied to the codec
>> audio card as an auxiliary device. This patch adds the commont paths
>> and controls, and variant specific headphone out and line out.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> sound/soc/sunxi/Kconfig | 8 +
>> sound/soc/sunxi/Makefile | 1 +
>> sound/soc/sunxi/sun8i-codec-analog.c | 665 +++++++++++++++++++++++++++++++++++
>> 3 files changed, 674 insertions(+)
>> create mode 100644 sound/soc/sunxi/sun8i-codec-analog.c
>>
>> diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
>> index dd2368297fd3..6c344e16aca4 100644
>> --- a/sound/soc/sunxi/Kconfig
>> +++ b/sound/soc/sunxi/Kconfig
>> @@ -9,6 +9,14 @@ config SND_SUN4I_CODEC
>> Select Y or M to add support for the Codec embedded in the Allwinner
>> A10 and affiliated SoCs.
>>
>> +config SND_SUN8I_CODEC_ANALOG
>> + tristate "Allwinner sun8i Codec Analog Controls Support"
>> + depends on MACH_SUN8I || COMPILE_TEST
>
> sun50i-a64 has a similar (or the same?) codec to A33.
>
I think the register offsets/fields were moved around again.
Why does Allwinner always do that... :/
ChenYu
>> + select REGMAP
>> + help
>> + Say Y or M if you want to add support for the analog controls for
>> + the codec embedded in newer Allwinner SoCs.
>> +
>> config SND_SUN4I_I2S
>> tristate "Allwinner A10 I2S Support"
>> select SND_SOC_GENERIC_DMAENGINE_PCM
>> diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
>> index 604c7b842837..241c0df9ca0c 100644
>> --- a/sound/soc/sunxi/Makefile
>> +++ b/sound/soc/sunxi/Makefile
>> @@ -1,3 +1,4 @@
>> obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
>> obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
>> obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
>> +obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
>> diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
>> new file mode 100644
>> index 000000000000..222bbd440b1e
>> --- /dev/null
>> +++ b/sound/soc/sunxi/sun8i-codec-analog.c
>> @@ -0,0 +1,665 @@
>> +/*
>> + * This driver supports the analog controls for the internal codec
>> + * found in Allwinner's A31s, A23, A33 and H3 SoCs.
>> + *
>> + * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +
>> +#include <sound/soc.h>
>> +#include <sound/soc-dapm.h>
>> +#include <sound/tlv.h>
>> +
>> +/* Codec analog control register offsets and bit fields */
>> +#define SUN8I_ADDA_HP_VOLC 0x00
>> +#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7
>> +#define SUN8I_ADDA_HP_VOLC_HP_VOL 0
>> +#define SUN8I_ADDA_LOMIXSC 0x01
>> +#define SUN8I_ADDA_LOMIXSC_MIC1 6
>> +#define SUN8I_ADDA_LOMIXSC_MIC2 5
>> +#define SUN8I_ADDA_LOMIXSC_PHONE 4
>> +#define SUN8I_ADDA_LOMIXSC_PHONEN 3
>> +#define SUN8I_ADDA_LOMIXSC_LINEINL 2
>> +#define SUN8I_ADDA_LOMIXSC_DACL 1
>> +#define SUN8I_ADDA_LOMIXSC_DACR 0
>> +#define SUN8I_ADDA_ROMIXSC 0x02
>> +#define SUN8I_ADDA_ROMIXSC_MIC1 6
>> +#define SUN8I_ADDA_ROMIXSC_MIC2 5
>> +#define SUN8I_ADDA_ROMIXSC_PHONE 4
>> +#define SUN8I_ADDA_ROMIXSC_PHONEP 3
>> +#define SUN8I_ADDA_ROMIXSC_LINEINR 2
>> +#define SUN8I_ADDA_ROMIXSC_DACR 1
>> +#define SUN8I_ADDA_ROMIXSC_DACL 0
>> +#define SUN8I_ADDA_DAC_PA_SRC 0x03
>> +#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7
>> +#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6
>> +#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5
>> +#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4
>> +#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3
>> +#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2
>> +#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1
>> +#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0
>> +#define SUN8I_ADDA_PHONEIN_GCTRL 0x04
>> +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4
>> +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0
>> +#define SUN8I_ADDA_LINEIN_GCTRL 0x05
>> +#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4
>> +#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0
>> +#define SUN8I_ADDA_MICIN_GCTRL 0x06
>> +#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4
>> +#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0
>> +#define SUN8I_ADDA_PAEN_HP_CTRL 0x07
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1
>> +#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0
>> +#define SUN8I_ADDA_PHONEOUT_CTRL 0x08
>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5
>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4
>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3
>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2
>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1
>> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0
>> +#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09
>> +#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3
>> +#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0
>> +#define SUN8I_ADDA_MIC2G_CTRL 0x0a
>> +#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7
>> +#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4
>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3
>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2
>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1
>> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0
>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b
>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7
>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6
>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5
>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3
>> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0
>> +#define SUN8I_ADDA_LADCMIXSC 0x0c
>> +#define SUN8I_ADDA_LADCMIXSC_MIC1 6
>> +#define SUN8I_ADDA_LADCMIXSC_MIC2 5
>> +#define SUN8I_ADDA_LADCMIXSC_PHONE 4
>> +#define SUN8I_ADDA_LADCMIXSC_PHONEN 3
>> +#define SUN8I_ADDA_LADCMIXSC_LINEINL 2
>> +#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1
>> +#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0
>> +#define SUN8I_ADDA_RADCMIXSC 0x0d
>> +#define SUN8I_ADDA_RADCMIXSC_MIC1 6
>> +#define SUN8I_ADDA_RADCMIXSC_MIC2 5
>> +#define SUN8I_ADDA_RADCMIXSC_PHONE 4
>> +#define SUN8I_ADDA_RADCMIXSC_PHONEP 3
>> +#define SUN8I_ADDA_RADCMIXSC_LINEINR 2
>> +#define SUN8I_ADDA_RADCMIXSC_OMIXR 1
>> +#define SUN8I_ADDA_RADCMIXSC_OMIXL 0
>> +#define SUN8I_ADDA_RES 0x0e
>> +#define SUN8I_ADDA_RES_MMICBIAS_SEL 4
>> +#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0
>> +#define SUN8I_ADDA_ADC_AP_EN 0x0f
>> +#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7
>> +#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
>> +#define SUN8I_ADDA_ADC_AP_EN_ADCG 0
>> +
>> +/* Analog control register access bits */
>> +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
>> +#define ADDA_PR_RESET BIT(28)
>> +#define ADDA_PR_WRITE BIT(24)
>> +#define ADDA_PR_ADDR_SHIFT 16
>> +#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
>> +#define ADDA_PR_DATA_IN_SHIFT 8
>> +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
>> +#define ADDA_PR_DATA_OUT_SHIFT 0
>> +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
>> +
>> +/* regmap access bits */
>> +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
>> +{
>> + void __iomem *base = (void __iomem *)context;
>> + u32 tmp;
>> +
>> + /* De-assert reset */
>> + writel(readl(base) | ADDA_PR_RESET, base);
>> +
>> + /* Clear write bit */
>> + writel(readl(base) & ~ADDA_PR_WRITE, base);
>> +
>> + /* Set register address */
>> + tmp = readl(base);
>> + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
>> + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
>> + writel(tmp, base);
>> +
>> + /* Read back value */
>> + *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
>> +
>> + return 0;
>> +}
>> +
>> +static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
>> +{
>> + void __iomem *base = (void __iomem *)context;
>> + u32 tmp;
>> +
>> + /* De-assert reset */
>> + writel(readl(base) | ADDA_PR_RESET, base);
>> +
>> + /* Set register address */
>> + tmp = readl(base);
>> + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
>> + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
>> + writel(tmp, base);
>> +
>> + /* Set data to write */
>> + tmp = readl(base);
>> + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
>> + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
>> + writel(tmp, base);
>> +
>> + /* Set write bit to signal a write */
>> + writel(readl(base) | ADDA_PR_WRITE, base);
>> +
>> + /* Clear write bit */
>> + writel(readl(base) & ~ADDA_PR_WRITE, base);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct regmap_config adda_pr_regmap_cfg = {
>> + .name = "adda-pr",
>> + .reg_bits = 5,
>> + .reg_stride = 1,
>> + .val_bits = 8,
>> + .reg_read = adda_reg_read,
>> + .reg_write = adda_reg_write,
>> + .fast_io = true,
>> + .max_register = 24,
>> +};
>> +
>> +/* mixer controls */
>> +static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
>> + SOC_DAPM_DOUBLE_R("DAC Playback Switch",
>> + SUN8I_ADDA_LOMIXSC,
>> + SUN8I_ADDA_ROMIXSC,
>> + SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
>> + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
>> + SUN8I_ADDA_LOMIXSC,
>> + SUN8I_ADDA_ROMIXSC,
>> + SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Line In Playback Switch",
>> + SUN8I_ADDA_LOMIXSC,
>> + SUN8I_ADDA_ROMIXSC,
>> + SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
>> + SUN8I_ADDA_LOMIXSC,
>> + SUN8I_ADDA_ROMIXSC,
>> + SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
>> + SUN8I_ADDA_LOMIXSC,
>> + SUN8I_ADDA_ROMIXSC,
>> + SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
>> +};
>> +
>> +/* ADC mixer controls */
>> +static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
>> + SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
>> + SUN8I_ADDA_LADCMIXSC,
>> + SUN8I_ADDA_RADCMIXSC,
>> + SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
>> + SUN8I_ADDA_LADCMIXSC,
>> + SUN8I_ADDA_RADCMIXSC,
>> + SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Line In Capture Switch",
>> + SUN8I_ADDA_LADCMIXSC,
>> + SUN8I_ADDA_RADCMIXSC,
>> + SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
>> + SUN8I_ADDA_LADCMIXSC,
>> + SUN8I_ADDA_RADCMIXSC,
>> + SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
>> + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
>> + SUN8I_ADDA_LADCMIXSC,
>> + SUN8I_ADDA_RADCMIXSC,
>> + SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
>> +};
>> +
>> +/* volume / mute controls */
>> +static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
>> + -450, 150, 0);
>> +static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale,
>> + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
>> + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
>> +);
>> +
>> +static const struct snd_kcontrol_new sun8i_codec_common_controls[] = {
>> + /* Mixer pre-gains */
>> + SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL,
>> + SUN8I_ADDA_LINEIN_GCTRL_LINEING,
>> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>> + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL,
>> + SUN8I_ADDA_MICIN_GCTRL_MIC1G,
>> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>> + SOC_SINGLE_TLV("Mic2 Playback Volume",
>> + SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G,
>> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>> +
>> + /* Microphone Amp boost gains */
>> + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0,
>> + sun8i_codec_mic_gain_scale),
>> + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL,
>> + SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0,
>> + sun8i_codec_mic_gain_scale),
>> +
>> + /* ADC */
>> + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN,
>> + SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0,
>> + sun8i_codec_out_mixer_pregain_scale),
>> +};
>> +
>> +static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
>> + /* ADC */
>> + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
>> + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
>> + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
>> + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
>> +
>> + /* DAC */
>> + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
>> + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
>> + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
>> + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
>> + /*
>> + * Due to this component and the codec belonging to separate DAPM
>> + * contexts, we need to manually link the above widgets to their
>> + * stream widgets at the card level.
>> + */
>> +
>> + /* Line In */
>> + SND_SOC_DAPM_INPUT("LINEIN"),
>> +
>> + /* Microphone inputs */
>> + SND_SOC_DAPM_INPUT("MIC1"),
>> + SND_SOC_DAPM_INPUT("MIC2"),
>> +
>> + /* Microphone Bias */
>> + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
>> + 0, NULL, 0),
>> +
>> + /* Mic input path */
>> + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
>> + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
>> + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
>> +
>> + /* Mixers */
>> + SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
>> + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
>> + sun8i_codec_mixer_controls,
>> + ARRAY_SIZE(sun8i_codec_mixer_controls)),
>> + SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
>> + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
>> + sun8i_codec_mixer_controls,
>> + ARRAY_SIZE(sun8i_codec_mixer_controls)),
>> + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
>> + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
>> + sun8i_codec_adc_mixer_controls,
>> + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
>> + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
>> + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
>> + sun8i_codec_adc_mixer_controls,
>> + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
>> +};
>> +
>> +static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
>> + /* Microphone Routes */
>> + { "Mic1 Amplifier", NULL, "MIC1"},
>> + { "Mic2 Amplifier", NULL, "MIC2"},
>> +
>> + /* Left Mixer Routes */
>> + { "Left Mixer", "DAC Playback Switch", "Left DAC" },
>> + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
>> + { "Left Mixer", "Line In Playback Switch", "LINEIN" },
>> + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
>> + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
>> +
>> + /* Right Mixer Routes */
>> + { "Right Mixer", "DAC Playback Switch", "Right DAC" },
>> + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
>> + { "Right Mixer", "Line In Playback Switch", "LINEIN" },
>> + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
>> + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
>> +
>> + /* Left ADC Mixer Routes */
>> + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
>> + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
>> + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
>> + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
>> + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
>> +
>> + /* Right ADC Mixer Routes */
>> + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
>> + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
>> + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
>> + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
>> + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
>> +
>> + /* ADC Routes */
>> + { "Left ADC", NULL, "Left ADC Mixer" },
>> + { "Right ADC", NULL, "Right ADC Mixer" },
>> +};
>> +
>> +/* headphone specific controls, widgets, and routes */
>> +static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
>> +static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
>> + SOC_SINGLE_TLV("Headphone Playback Volume",
>> + SUN8I_ADDA_HP_VOLC,
>> + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
>> + sun8i_codec_hp_vol_scale),
>> + SOC_DOUBLE("Headphone Playback Switch",
>> + SUN8I_ADDA_DAC_PA_SRC,
>> + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
>> + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
>> +};
>> +
>> +static const char * const sun8i_codec_hp_src_enum_text[] = {
>> + "DAC", "Mixer",
>> +};
>> +
>> +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum,
>> + SUN8I_ADDA_DAC_PA_SRC,
>> + SUN8I_ADDA_DAC_PA_SRC_LHPIS,
>> + SUN8I_ADDA_DAC_PA_SRC_RHPIS,
>> + sun8i_codec_hp_src_enum_text);
>> +
>> +static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
>> + SOC_DAPM_ENUM("Headphone Source Playback Route",
>> + sun8i_codec_hp_src_enum),
>> +};
>> +
>> +static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
>> + SND_SOC_DAPM_MUX("Headphone Source Playback Route",
>> + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
>> + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
>> + SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0),
>> + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
>> + SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
>> + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
>> + SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0),
>> + SND_SOC_DAPM_OUTPUT("HP"),
>> +};
>> +
>> +static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
>> + { "Headphone Source Playback Route", "DAC", "Left DAC" },
>> + { "Headphone Source Playback Route", "DAC", "Right DAC" },
>> + { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
>> + { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
>> + { "Headphone Amp", NULL, "Headphone Source Playback Route" },
>> + { "HPCOM", NULL, "HPCOM Protection" },
>> + { "HP", NULL, "Headphone Amp" },
>> +};
>> +
>> +static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
>> +{
>> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>> + struct device *dev = cmpnt->dev;
>> + int ret;
>> +
>> + ret = snd_soc_add_component_controls(cmpnt,
>> + sun8i_codec_headphone_controls,
>> + ARRAY_SIZE(sun8i_codec_headphone_controls));
>> + if (ret) {
>> + dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
>> + ARRAY_SIZE(sun8i_codec_headphone_widgets));
>> + if (ret) {
>> + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes,
>> + ARRAY_SIZE(sun8i_codec_headphone_routes));
>> + if (ret) {
>> + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/* hmic specific widget */
>> +static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
>> + SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN,
>> + 0, NULL, 0),
>> +};
>> +
>> +static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt)
>> +{
>> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>> + struct device *dev = cmpnt->dev;
>> + int ret;
>> +
>> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets,
>> + ARRAY_SIZE(sun8i_codec_hmic_widgets));
>> + if (ret)
>> + dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret);
>> +
>> + return ret;
>> +}
>> +
>> +/* line out specific controls, widgets and routes */
>> +static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
>> + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
>> + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
>> +);
>> +static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
>> + SOC_SINGLE_TLV("Line Out Playback Volume",
>> + SUN8I_ADDA_PHONE_GAIN_CTRL,
>> + SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0,
>> + sun8i_codec_lineout_vol_scale),
>> + SOC_DOUBLE("Line Out Playback Switch",
>> + SUN8I_ADDA_MIC2G_CTRL,
>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN,
>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
>> +};
>> +
>> +static const char * const sun8i_codec_lineout_src_enum_text[] = {
>> + "Stereo", "Mono Differential",
>> +};
>> +
>> +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
>> + SUN8I_ADDA_MIC2G_CTRL,
>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC,
>> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
>> + sun8i_codec_lineout_src_enum_text);
>> +
>> +static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
>> + SOC_DAPM_ENUM("Line Out Source Playback Route",
>> + sun8i_codec_lineout_src_enum),
>> +};
>> +
>> +static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
>> + SND_SOC_DAPM_MUX("Line Out Source Playback Route",
>> + SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
>> + /* It is unclear if this is a buffer or gate, model it as a supply */
>> + SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL,
>> + SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0),
>> + SND_SOC_DAPM_OUTPUT("LINEOUT"),
>> +};
>> +
>> +static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
>> + { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
>> + { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
>> + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
>> + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
>> + { "LINEOUT", NULL, "Line Out Source Playback Route" },
>> + { "LINEOUT", NULL, "Line Out Enable", },
>> +};
>> +
>> +static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
>> +{
>> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>> + struct device *dev = cmpnt->dev;
>> + int ret;
>> +
>> + ret = snd_soc_add_component_controls(cmpnt,
>> + sun8i_codec_lineout_controls,
>> + ARRAY_SIZE(sun8i_codec_lineout_controls));
>> + if (ret) {
>> + dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets,
>> + ARRAY_SIZE(sun8i_codec_lineout_widgets));
>> + if (ret) {
>> + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes,
>> + ARRAY_SIZE(sun8i_codec_lineout_routes));
>> + if (ret) {
>> + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +struct sun8i_codec_analog_quirks {
>> + bool has_headphone;
>> + bool has_hmic;
>> + bool has_lineout;
>> +};
>> +
>> +static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
>> + .has_headphone = true,
>> + .has_hmic = true,
>> +};
>> +
>> +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
>> + .has_lineout = true,
>> +};
>> +
>> +static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
>> +{
>> + struct device *dev = cmpnt->dev;
>> + const struct sun8i_codec_analog_quirks *quirks;
>> + int ret;
>> +
>> + /*
>> + * This would never return NULL unless someone directly registers a
>> + * platform device matching this driver's name, without specifying a
>> + * device tree node.
>> + */
>> + quirks = of_device_get_match_data(dev);
>> +
>> + /* Add controls, widgets, and routes for individual features */
>> +
>> + if (quirks->has_headphone) {
>> + ret = sun8i_codec_add_headphone(cmpnt);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + if (quirks->has_hmic) {
>> + sun8i_codec_add_hmic(cmpnt);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + if (quirks->has_lineout) {
>> + ret = sun8i_codec_add_lineout(cmpnt);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
>> + .controls = sun8i_codec_common_controls,
>> + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls),
>> + .dapm_widgets = sun8i_codec_common_widgets,
>> + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets),
>> + .dapm_routes = sun8i_codec_common_routes,
>> + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes),
>> + .probe = sun8i_codec_analog_cmpnt_probe,
>> +};
>> +
>> +static const struct of_device_id sun8i_codec_analog_of_match[] = {
>> + {
>> + .compatible = "allwinner,sun8i-a23-codec-analog",
>> + .data = &sun8i_a23_quirks,
>> + },
>> + {
>> + .compatible = "allwinner,sun8i-h3-codec-analog",
>> + .data = &sun8i_h3_quirks,
>> + },
>> + {}
>> +};
>> +MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
>> +
>> +static int sun8i_codec_analog_probe(struct platform_device *pdev)
>> +{
>> + struct resource *res;
>> + struct regmap *regmap;
>> + void __iomem *base;
>> +
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + base = devm_ioremap_resource(&pdev->dev, res);
>> + if (IS_ERR(base)) {
>> + dev_err(&pdev->dev, "Failed to map the registers\n");
>> + return PTR_ERR(base);
>> + }
>> +
>> + regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg);
>> + if (IS_ERR(regmap)) {
>> + dev_err(&pdev->dev, "Failed to create regmap\n");
>> + return PTR_ERR(regmap);
>> + }
>> +
>> + return devm_snd_soc_register_component(&pdev->dev,
>> + &sun8i_codec_analog_cmpnt_drv,
>> + NULL, 0);
>> +}
>> +
>> +static struct platform_driver sun8i_codec_analog_driver = {
>> + .driver = {
>> + .name = "sun8i-codec-analog",
>> + .of_match_table = sun8i_codec_analog_of_match,
>> + },
>> + .probe = sun8i_codec_analog_probe,
>> +};
>> +module_platform_driver(sun8i_codec_analog_driver);
>> +
>> +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver");
>> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:sun8i-codec-analog");
>> --
>> 2.10.2
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 02/10] ASoC: sunxi: Add support for A23/A33/H3 codec's analog path controls
From: Icenowy Zheng @ 2016-11-25 5:43 UTC (permalink / raw)
To: Chen-Yu Tsai, Liam Girdwood, Mark Brown, Maxime Ripard, Lee Jones,
Rob Herring, Mark Rutland
Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
Mylene Josserand, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20161112064648.26779-3-wens@csie.org>
12.11.2016, 14:57, "Chen-Yu Tsai" <wens@csie.org>:
> The internal codec on A23/A33/H3 is split into 2 parts. The
> analog path controls are routed through an embedded custom register
> bus accessed through the PRCM block.
>
> The SoCs share a common set of inputs, outputs, and audio paths.
> The following table lists the differences.
>
> ----------------------------------------
> | Feature \ SoC | A23 | A33 | H3 |
> ----------------------------------------
> | Headphone | v | v | |
> ----------------------------------------
> | Line Out | | | v |
> ----------------------------------------
> | Phone In/Out | v | v | |
> ----------------------------------------
>
> Add an ASoC component driver for it. This should be tied to the codec
> audio card as an auxiliary device. This patch adds the commont paths
> and controls, and variant specific headphone out and line out.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> sound/soc/sunxi/Kconfig | 8 +
> sound/soc/sunxi/Makefile | 1 +
> sound/soc/sunxi/sun8i-codec-analog.c | 665 +++++++++++++++++++++++++++++++++++
> 3 files changed, 674 insertions(+)
> create mode 100644 sound/soc/sunxi/sun8i-codec-analog.c
>
> diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
> index dd2368297fd3..6c344e16aca4 100644
> --- a/sound/soc/sunxi/Kconfig
> +++ b/sound/soc/sunxi/Kconfig
> @@ -9,6 +9,14 @@ config SND_SUN4I_CODEC
> Select Y or M to add support for the Codec embedded in the Allwinner
> A10 and affiliated SoCs.
>
> +config SND_SUN8I_CODEC_ANALOG
> + tristate "Allwinner sun8i Codec Analog Controls Support"
> + depends on MACH_SUN8I || COMPILE_TEST
sun50i-a64 has a similar (or the same?) codec to A33.
> + select REGMAP
> + help
> + Say Y or M if you want to add support for the analog controls for
> + the codec embedded in newer Allwinner SoCs.
> +
> config SND_SUN4I_I2S
> tristate "Allwinner A10 I2S Support"
> select SND_SOC_GENERIC_DMAENGINE_PCM
> diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
> index 604c7b842837..241c0df9ca0c 100644
> --- a/sound/soc/sunxi/Makefile
> +++ b/sound/soc/sunxi/Makefile
> @@ -1,3 +1,4 @@
> obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
> obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
> obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
> +obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
> diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
> new file mode 100644
> index 000000000000..222bbd440b1e
> --- /dev/null
> +++ b/sound/soc/sunxi/sun8i-codec-analog.c
> @@ -0,0 +1,665 @@
> +/*
> + * This driver supports the analog controls for the internal codec
> + * found in Allwinner's A31s, A23, A33 and H3 SoCs.
> + *
> + * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#include <sound/soc.h>
> +#include <sound/soc-dapm.h>
> +#include <sound/tlv.h>
> +
> +/* Codec analog control register offsets and bit fields */
> +#define SUN8I_ADDA_HP_VOLC 0x00
> +#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7
> +#define SUN8I_ADDA_HP_VOLC_HP_VOL 0
> +#define SUN8I_ADDA_LOMIXSC 0x01
> +#define SUN8I_ADDA_LOMIXSC_MIC1 6
> +#define SUN8I_ADDA_LOMIXSC_MIC2 5
> +#define SUN8I_ADDA_LOMIXSC_PHONE 4
> +#define SUN8I_ADDA_LOMIXSC_PHONEN 3
> +#define SUN8I_ADDA_LOMIXSC_LINEINL 2
> +#define SUN8I_ADDA_LOMIXSC_DACL 1
> +#define SUN8I_ADDA_LOMIXSC_DACR 0
> +#define SUN8I_ADDA_ROMIXSC 0x02
> +#define SUN8I_ADDA_ROMIXSC_MIC1 6
> +#define SUN8I_ADDA_ROMIXSC_MIC2 5
> +#define SUN8I_ADDA_ROMIXSC_PHONE 4
> +#define SUN8I_ADDA_ROMIXSC_PHONEP 3
> +#define SUN8I_ADDA_ROMIXSC_LINEINR 2
> +#define SUN8I_ADDA_ROMIXSC_DACR 1
> +#define SUN8I_ADDA_ROMIXSC_DACL 0
> +#define SUN8I_ADDA_DAC_PA_SRC 0x03
> +#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7
> +#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6
> +#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5
> +#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4
> +#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3
> +#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2
> +#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1
> +#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0
> +#define SUN8I_ADDA_PHONEIN_GCTRL 0x04
> +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4
> +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0
> +#define SUN8I_ADDA_LINEIN_GCTRL 0x05
> +#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4
> +#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0
> +#define SUN8I_ADDA_MICIN_GCTRL 0x06
> +#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4
> +#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0
> +#define SUN8I_ADDA_PAEN_HP_CTRL 0x07
> +#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7
> +#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */
> +#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5
> +#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4
> +#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2
> +#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1
> +#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0
> +#define SUN8I_ADDA_PHONEOUT_CTRL 0x08
> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5
> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4
> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3
> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2
> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1
> +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0
> +#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09
> +#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3
> +#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0
> +#define SUN8I_ADDA_MIC2G_CTRL 0x0a
> +#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7
> +#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4
> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3
> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2
> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1
> +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0
> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b
> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7
> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6
> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5
> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3
> +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0
> +#define SUN8I_ADDA_LADCMIXSC 0x0c
> +#define SUN8I_ADDA_LADCMIXSC_MIC1 6
> +#define SUN8I_ADDA_LADCMIXSC_MIC2 5
> +#define SUN8I_ADDA_LADCMIXSC_PHONE 4
> +#define SUN8I_ADDA_LADCMIXSC_PHONEN 3
> +#define SUN8I_ADDA_LADCMIXSC_LINEINL 2
> +#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1
> +#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0
> +#define SUN8I_ADDA_RADCMIXSC 0x0d
> +#define SUN8I_ADDA_RADCMIXSC_MIC1 6
> +#define SUN8I_ADDA_RADCMIXSC_MIC2 5
> +#define SUN8I_ADDA_RADCMIXSC_PHONE 4
> +#define SUN8I_ADDA_RADCMIXSC_PHONEP 3
> +#define SUN8I_ADDA_RADCMIXSC_LINEINR 2
> +#define SUN8I_ADDA_RADCMIXSC_OMIXR 1
> +#define SUN8I_ADDA_RADCMIXSC_OMIXL 0
> +#define SUN8I_ADDA_RES 0x0e
> +#define SUN8I_ADDA_RES_MMICBIAS_SEL 4
> +#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0
> +#define SUN8I_ADDA_ADC_AP_EN 0x0f
> +#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7
> +#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
> +#define SUN8I_ADDA_ADC_AP_EN_ADCG 0
> +
> +/* Analog control register access bits */
> +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
> +#define ADDA_PR_RESET BIT(28)
> +#define ADDA_PR_WRITE BIT(24)
> +#define ADDA_PR_ADDR_SHIFT 16
> +#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
> +#define ADDA_PR_DATA_IN_SHIFT 8
> +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
> +#define ADDA_PR_DATA_OUT_SHIFT 0
> +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
> +
> +/* regmap access bits */
> +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
> +{
> + void __iomem *base = (void __iomem *)context;
> + u32 tmp;
> +
> + /* De-assert reset */
> + writel(readl(base) | ADDA_PR_RESET, base);
> +
> + /* Clear write bit */
> + writel(readl(base) & ~ADDA_PR_WRITE, base);
> +
> + /* Set register address */
> + tmp = readl(base);
> + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
> + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
> + writel(tmp, base);
> +
> + /* Read back value */
> + *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
> +
> + return 0;
> +}
> +
> +static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
> +{
> + void __iomem *base = (void __iomem *)context;
> + u32 tmp;
> +
> + /* De-assert reset */
> + writel(readl(base) | ADDA_PR_RESET, base);
> +
> + /* Set register address */
> + tmp = readl(base);
> + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
> + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
> + writel(tmp, base);
> +
> + /* Set data to write */
> + tmp = readl(base);
> + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
> + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
> + writel(tmp, base);
> +
> + /* Set write bit to signal a write */
> + writel(readl(base) | ADDA_PR_WRITE, base);
> +
> + /* Clear write bit */
> + writel(readl(base) & ~ADDA_PR_WRITE, base);
> +
> + return 0;
> +}
> +
> +static const struct regmap_config adda_pr_regmap_cfg = {
> + .name = "adda-pr",
> + .reg_bits = 5,
> + .reg_stride = 1,
> + .val_bits = 8,
> + .reg_read = adda_reg_read,
> + .reg_write = adda_reg_write,
> + .fast_io = true,
> + .max_register = 24,
> +};
> +
> +/* mixer controls */
> +static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
> + SOC_DAPM_DOUBLE_R("DAC Playback Switch",
> + SUN8I_ADDA_LOMIXSC,
> + SUN8I_ADDA_ROMIXSC,
> + SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
> + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
> + SUN8I_ADDA_LOMIXSC,
> + SUN8I_ADDA_ROMIXSC,
> + SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
> + SOC_DAPM_DOUBLE_R("Line In Playback Switch",
> + SUN8I_ADDA_LOMIXSC,
> + SUN8I_ADDA_ROMIXSC,
> + SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0),
> + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
> + SUN8I_ADDA_LOMIXSC,
> + SUN8I_ADDA_ROMIXSC,
> + SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
> + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
> + SUN8I_ADDA_LOMIXSC,
> + SUN8I_ADDA_ROMIXSC,
> + SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
> +};
> +
> +/* ADC mixer controls */
> +static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
> + SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
> + SUN8I_ADDA_LADCMIXSC,
> + SUN8I_ADDA_RADCMIXSC,
> + SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
> + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
> + SUN8I_ADDA_LADCMIXSC,
> + SUN8I_ADDA_RADCMIXSC,
> + SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
> + SOC_DAPM_DOUBLE_R("Line In Capture Switch",
> + SUN8I_ADDA_LADCMIXSC,
> + SUN8I_ADDA_RADCMIXSC,
> + SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0),
> + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
> + SUN8I_ADDA_LADCMIXSC,
> + SUN8I_ADDA_RADCMIXSC,
> + SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
> + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
> + SUN8I_ADDA_LADCMIXSC,
> + SUN8I_ADDA_RADCMIXSC,
> + SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
> +};
> +
> +/* volume / mute controls */
> +static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
> + -450, 150, 0);
> +static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale,
> + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
> + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
> +);
> +
> +static const struct snd_kcontrol_new sun8i_codec_common_controls[] = {
> + /* Mixer pre-gains */
> + SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL,
> + SUN8I_ADDA_LINEIN_GCTRL_LINEING,
> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
> + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL,
> + SUN8I_ADDA_MICIN_GCTRL_MIC1G,
> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
> + SOC_SINGLE_TLV("Mic2 Playback Volume",
> + SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G,
> + 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
> +
> + /* Microphone Amp boost gains */
> + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0,
> + sun8i_codec_mic_gain_scale),
> + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL,
> + SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0,
> + sun8i_codec_mic_gain_scale),
> +
> + /* ADC */
> + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN,
> + SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0,
> + sun8i_codec_out_mixer_pregain_scale),
> +};
> +
> +static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
> + /* ADC */
> + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
> + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
> + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
> + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
> +
> + /* DAC */
> + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
> + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
> + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
> + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
> + /*
> + * Due to this component and the codec belonging to separate DAPM
> + * contexts, we need to manually link the above widgets to their
> + * stream widgets at the card level.
> + */
> +
> + /* Line In */
> + SND_SOC_DAPM_INPUT("LINEIN"),
> +
> + /* Microphone inputs */
> + SND_SOC_DAPM_INPUT("MIC1"),
> + SND_SOC_DAPM_INPUT("MIC2"),
> +
> + /* Microphone Bias */
> + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
> + 0, NULL, 0),
> +
> + /* Mic input path */
> + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
> + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
> + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
> +
> + /* Mixers */
> + SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
> + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
> + sun8i_codec_mixer_controls,
> + ARRAY_SIZE(sun8i_codec_mixer_controls)),
> + SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
> + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
> + sun8i_codec_mixer_controls,
> + ARRAY_SIZE(sun8i_codec_mixer_controls)),
> + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
> + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
> + sun8i_codec_adc_mixer_controls,
> + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
> + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
> + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
> + sun8i_codec_adc_mixer_controls,
> + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
> +};
> +
> +static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
> + /* Microphone Routes */
> + { "Mic1 Amplifier", NULL, "MIC1"},
> + { "Mic2 Amplifier", NULL, "MIC2"},
> +
> + /* Left Mixer Routes */
> + { "Left Mixer", "DAC Playback Switch", "Left DAC" },
> + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
> + { "Left Mixer", "Line In Playback Switch", "LINEIN" },
> + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
> + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
> +
> + /* Right Mixer Routes */
> + { "Right Mixer", "DAC Playback Switch", "Right DAC" },
> + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
> + { "Right Mixer", "Line In Playback Switch", "LINEIN" },
> + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
> + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
> +
> + /* Left ADC Mixer Routes */
> + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
> + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
> + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
> + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
> + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
> +
> + /* Right ADC Mixer Routes */
> + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
> + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
> + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
> + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
> + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
> +
> + /* ADC Routes */
> + { "Left ADC", NULL, "Left ADC Mixer" },
> + { "Right ADC", NULL, "Right ADC Mixer" },
> +};
> +
> +/* headphone specific controls, widgets, and routes */
> +static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
> +static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
> + SOC_SINGLE_TLV("Headphone Playback Volume",
> + SUN8I_ADDA_HP_VOLC,
> + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
> + sun8i_codec_hp_vol_scale),
> + SOC_DOUBLE("Headphone Playback Switch",
> + SUN8I_ADDA_DAC_PA_SRC,
> + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
> + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
> +};
> +
> +static const char * const sun8i_codec_hp_src_enum_text[] = {
> + "DAC", "Mixer",
> +};
> +
> +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum,
> + SUN8I_ADDA_DAC_PA_SRC,
> + SUN8I_ADDA_DAC_PA_SRC_LHPIS,
> + SUN8I_ADDA_DAC_PA_SRC_RHPIS,
> + sun8i_codec_hp_src_enum_text);
> +
> +static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
> + SOC_DAPM_ENUM("Headphone Source Playback Route",
> + sun8i_codec_hp_src_enum),
> +};
> +
> +static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
> + SND_SOC_DAPM_MUX("Headphone Source Playback Route",
> + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
> + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
> + SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0),
> + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
> + SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
> + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
> + SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0),
> + SND_SOC_DAPM_OUTPUT("HP"),
> +};
> +
> +static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
> + { "Headphone Source Playback Route", "DAC", "Left DAC" },
> + { "Headphone Source Playback Route", "DAC", "Right DAC" },
> + { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
> + { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
> + { "Headphone Amp", NULL, "Headphone Source Playback Route" },
> + { "HPCOM", NULL, "HPCOM Protection" },
> + { "HP", NULL, "Headphone Amp" },
> +};
> +
> +static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
> +{
> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
> + struct device *dev = cmpnt->dev;
> + int ret;
> +
> + ret = snd_soc_add_component_controls(cmpnt,
> + sun8i_codec_headphone_controls,
> + ARRAY_SIZE(sun8i_codec_headphone_controls));
> + if (ret) {
> + dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
> + return ret;
> + }
> +
> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
> + ARRAY_SIZE(sun8i_codec_headphone_widgets));
> + if (ret) {
> + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
> + return ret;
> + }
> +
> + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes,
> + ARRAY_SIZE(sun8i_codec_headphone_routes));
> + if (ret) {
> + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/* hmic specific widget */
> +static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
> + SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
> + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN,
> + 0, NULL, 0),
> +};
> +
> +static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt)
> +{
> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
> + struct device *dev = cmpnt->dev;
> + int ret;
> +
> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets,
> + ARRAY_SIZE(sun8i_codec_hmic_widgets));
> + if (ret)
> + dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret);
> +
> + return ret;
> +}
> +
> +/* line out specific controls, widgets and routes */
> +static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
> + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
> + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
> +);
> +static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
> + SOC_SINGLE_TLV("Line Out Playback Volume",
> + SUN8I_ADDA_PHONE_GAIN_CTRL,
> + SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0,
> + sun8i_codec_lineout_vol_scale),
> + SOC_DOUBLE("Line Out Playback Switch",
> + SUN8I_ADDA_MIC2G_CTRL,
> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN,
> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
> +};
> +
> +static const char * const sun8i_codec_lineout_src_enum_text[] = {
> + "Stereo", "Mono Differential",
> +};
> +
> +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
> + SUN8I_ADDA_MIC2G_CTRL,
> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC,
> + SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
> + sun8i_codec_lineout_src_enum_text);
> +
> +static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
> + SOC_DAPM_ENUM("Line Out Source Playback Route",
> + sun8i_codec_lineout_src_enum),
> +};
> +
> +static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
> + SND_SOC_DAPM_MUX("Line Out Source Playback Route",
> + SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
> + /* It is unclear if this is a buffer or gate, model it as a supply */
> + SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL,
> + SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0),
> + SND_SOC_DAPM_OUTPUT("LINEOUT"),
> +};
> +
> +static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
> + { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
> + { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
> + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
> + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
> + { "LINEOUT", NULL, "Line Out Source Playback Route" },
> + { "LINEOUT", NULL, "Line Out Enable", },
> +};
> +
> +static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
> +{
> + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
> + struct device *dev = cmpnt->dev;
> + int ret;
> +
> + ret = snd_soc_add_component_controls(cmpnt,
> + sun8i_codec_lineout_controls,
> + ARRAY_SIZE(sun8i_codec_lineout_controls));
> + if (ret) {
> + dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
> + return ret;
> + }
> +
> + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets,
> + ARRAY_SIZE(sun8i_codec_lineout_widgets));
> + if (ret) {
> + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
> + return ret;
> + }
> +
> + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes,
> + ARRAY_SIZE(sun8i_codec_lineout_routes));
> + if (ret) {
> + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +struct sun8i_codec_analog_quirks {
> + bool has_headphone;
> + bool has_hmic;
> + bool has_lineout;
> +};
> +
> +static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
> + .has_headphone = true,
> + .has_hmic = true,
> +};
> +
> +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
> + .has_lineout = true,
> +};
> +
> +static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
> +{
> + struct device *dev = cmpnt->dev;
> + const struct sun8i_codec_analog_quirks *quirks;
> + int ret;
> +
> + /*
> + * This would never return NULL unless someone directly registers a
> + * platform device matching this driver's name, without specifying a
> + * device tree node.
> + */
> + quirks = of_device_get_match_data(dev);
> +
> + /* Add controls, widgets, and routes for individual features */
> +
> + if (quirks->has_headphone) {
> + ret = sun8i_codec_add_headphone(cmpnt);
> + if (ret)
> + return ret;
> + }
> +
> + if (quirks->has_hmic) {
> + sun8i_codec_add_hmic(cmpnt);
> + if (ret)
> + return ret;
> + }
> +
> + if (quirks->has_lineout) {
> + ret = sun8i_codec_add_lineout(cmpnt);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
> + .controls = sun8i_codec_common_controls,
> + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls),
> + .dapm_widgets = sun8i_codec_common_widgets,
> + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets),
> + .dapm_routes = sun8i_codec_common_routes,
> + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes),
> + .probe = sun8i_codec_analog_cmpnt_probe,
> +};
> +
> +static const struct of_device_id sun8i_codec_analog_of_match[] = {
> + {
> + .compatible = "allwinner,sun8i-a23-codec-analog",
> + .data = &sun8i_a23_quirks,
> + },
> + {
> + .compatible = "allwinner,sun8i-h3-codec-analog",
> + .data = &sun8i_h3_quirks,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
> +
> +static int sun8i_codec_analog_probe(struct platform_device *pdev)
> +{
> + struct resource *res;
> + struct regmap *regmap;
> + void __iomem *base;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(base)) {
> + dev_err(&pdev->dev, "Failed to map the registers\n");
> + return PTR_ERR(base);
> + }
> +
> + regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg);
> + if (IS_ERR(regmap)) {
> + dev_err(&pdev->dev, "Failed to create regmap\n");
> + return PTR_ERR(regmap);
> + }
> +
> + return devm_snd_soc_register_component(&pdev->dev,
> + &sun8i_codec_analog_cmpnt_drv,
> + NULL, 0);
> +}
> +
> +static struct platform_driver sun8i_codec_analog_driver = {
> + .driver = {
> + .name = "sun8i-codec-analog",
> + .of_match_table = sun8i_codec_analog_of_match,
> + },
> + .probe = sun8i_codec_analog_probe,
> +};
> +module_platform_driver(sun8i_codec_analog_driver);
> +
> +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver");
> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:sun8i-codec-analog");
> --
> 2.10.2
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v6 3/5] ARM: dts: sun8i-h3: add HDMI video nodes
From: Icenowy Zheng @ 2016-11-25 5:27 UTC (permalink / raw)
To: moinejf-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org, Dave Airlie,
Maxime Ripard, Rob Herring
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
In-Reply-To: <cdf50b8433e2d9a053e35f8788bfcd5d41504312.1479641523.git.moinejf-GANU6spQydw@public.gmane.org>
20.11.2016, 20:07, "Jean-Francois Moine" <moinejf@free.fr>:
> Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
> ---
> arch/arm/boot/dts/sun8i-h3.dtsi | 51 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 51 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
> index 416b825..7c6b1d5 100644
> --- a/arch/arm/boot/dts/sun8i-h3.dtsi
> +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
> @@ -140,6 +140,16 @@
> #size-cells = <1>;
> ranges;
>
> + de: de-controller@01000000 {
> + compatible = "allwinner,sun8i-h3-display-engine";
> + reg = <0x01000000 0x400000>;
> + clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>;
> + clock-names = "bus", "clock";
> + resets = <&ccu RST_BUS_DE>;
> + ports = <&lcd0_p>;
> + status = "disabled";
> + };
> +
> dma: dma-controller@01c02000 {
> compatible = "allwinner,sun8i-h3-dma";
> reg = <0x01c02000 0x1000>;
> @@ -149,6 +159,23 @@
> #dma-cells = <1>;
> };
>
> + lcd0: lcd-controller@01c0c000 {
> + compatible = "allwinner,sun8i-a83t-tcon";
> + reg = <0x01c0c000 0x400>;
> + clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
> + clock-names = "bus", "clock";
> + resets = <&ccu RST_BUS_TCON0>;
> + interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
> + status = "disabled";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + lcd0_p: port {
> + lcd0_hdmi: endpoint {
> + remote-endpoint = <&hdmi_lcd0>;
> + };
> + };
> + };
> +
> mmc0: mmc@01c0f000 {
> compatible = "allwinner,sun7i-a20-mmc";
> reg = <0x01c0f000 0x1000>;
> @@ -314,6 +341,11 @@
> clock-names = "hosc", "losc";
> #clock-cells = <1>;
> #reset-cells = <1>;
> +
> + assigned-clocks = <&ccu CLK_PLL_DE>,
Cannot get the patch built on 4.9-rc, as CLK_PLL_DE is not an exported clock.
Only CLK_DE is exported.
> + <&ccu CLK_DE>;
> + assigned-clock-rates = <864000000>,
> + <432000000>;
> };
>
> pio: pinctrl@01c20800 {
> @@ -564,6 +596,25 @@
> interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
> };
>
> + hdmi: hdmi@01ee0000 {
> + compatible = "allwinner,sun8i-h3-hdmi";
> + reg = <0x01ee0000 0x20000>;
> + clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI>,
> + <&ccu CLK_HDMI_DDC>;
> + clock-names = "bus", "clock", "ddc-clock";
> + resets = <&ccu RST_BUS_HDMI0>, <&ccu RST_BUS_HDMI1>;
> + reset-names = "hdmi0", "hdmi1";
> + status = "disabled";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + port@0 { /* video */
> + reg = <0>;
> + hdmi_lcd0: endpoint {
> + remote-endpoint = <&lcd0_hdmi>;
> + };
> + };
> + };
> +
> rtc: rtc@01f00000 {
> compatible = "allwinner,sun6i-a31-rtc";
> reg = <0x01f00000 0x54>;
> --
> 2.10.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH V8 2/6] thermal: bcm2835: add thermal driver for bcm2835 soc
From: Eduardo Valentin @ 2016-11-25 5:20 UTC (permalink / raw)
To: Martin Sperl
Cc: Zhang Rui, Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Lee Jones, Eric Anholt, Russell King, Florian Fainelli,
Catalin Marinas, Will Deacon, linux-pm-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <28F93ABE-8210-4389-AE77-4D5E830E669B-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
Hello,
On Tue, Nov 22, 2016 at 03:28:04PM +0100, Martin Sperl wrote:
> Hi Eduardo!
>
> On 19.11.2016 05:22, Eduardo Valentin wrote:
> > Hello Martin,
<cut>
>
> I was asked to implement the "initialize" case just in case FW ever
> stopped setting up the device itself, so that is why this code is
> included.
OK. Looks like we (like, we in the Linux side) do not understand the
conditions that firmware fails to initialize the thermal device, but we
still want to force an initialization, hoping to get the device in a sane
state, even if we do not know if the firmware is correctly booted or
not. And that is done silently, with no notification to user. I see.
>
> >
> > Who has the ownership of this device?
>
> Joined ownership I suppose...
>
with no synchronization mechanism?
> >
> >> The above mentioned “configuration if not running” reflect the values that
> >> the FW is currently setting. We should not change those values as long as the
> >> Firmware is also reading the temperature on its own.
> >
> > hmm.. that looks like racy to me. Again, How do you synchronize accesses to
> > this device? What if you configure the device and right after the
> > firmware updates the configs? How do you make sure the configs you are
> > writing here are the same used by the firmware? What if the firmware
> > version changes? What versions of the firmware does this driver support?
> >
> > Would it make sense to simply always initialize the device? Do you have
> > a way to tell the firmware that it should not use the device?
> >
> > Or, if you want to keep the device driver simply being a dummy reader,
> > would it make sense to simply avoid writing configurations to the
> > device, and simply retry to check if the firmware gets the device
> > initialized?
>
> Again: the device registers are only ever written if the device is not started
> already. Otherwise the driver only reads for the ADC register, so there
> is no real race here.
>
and no race?
To me, there is a race when you write to the config of this device,
given that there is no sync between the two. We do not know if the
firmware would be still attempting to initialize the device or not, do
we?
> >
> >>
> >>>
> >>>> So do you need another version of the patchset that uses that new API?
> >>>
> >>> I think the API usage is change that can be done together with
> >>> clarification for the above questions too: on hardware state,
> >>> firmware loading, maybe a master driver dependency, and the ADC
> >>> conversion sequence, which are not well clear to me on this driver. As long as
> >>> this is clarified and documented in the code (can be simple comments so
> >>> it is clear to whoever reads in the future), then I would be OK with
> >>> this driver.
> >>
> >> So how do you want this to get “documented” in the driver?
> >> The setup and Firmware is a generic feature of the SOC, so if we would put
> >> some clarifications in this driver, then we would need to put it in every
> >> bcm283X driver (which seems unreasonable).
> >>
> >
> > I think a simple comment explaining the firmware dependency and the
> > expected pre-conditions to get this driver working in a sane state would
> > do it.
> >
> > A better device initialization would also be appreciated. Based on my
> > limited understanding of this platform, and your explanations, this
> > device seams to have a serious race condition with firmware while
> > accessing this device.
>
> Again: the firmware runs before the ARM is started and for all practical
> purposes the firmware is (as of now) configuring the thermal device.
>
Oh, OK, we know the firmware wont touch the thermal device, right?
Then, If that is the case, what is still not clear is in which conditions
the firmware would leave the thermal device uninitialized.
This driver seams to be only concerned of critical temperature. The
concern I see with this code, and the explanations I heard, is a side
effect of seeing spurious thermal shutdown, or even worse, getting the
device booted hot and never shutting down, due to (possible) race
between the two systems.
Besides, if the firmware would not touch the thermal device when ARM is
running, why not always writing to the device a configuration that you
know is your sane starting point? Just do not rely on what was
previously set. How do you know it is a sane configuration? Have you
done sensor calibration exercise to confirm temperature reads are
correct?
> As for the use of thermal_zone_get_offset/slope: looking into the code
> it looks like this actually blows up the code, as we now would need to
> allocate thermal_zone_params and preset it with the “correct” values.
>
> So more code to maintain and more memory consumed.
> The only advantage I would see is that it would allow to set offset and
> slope directly in the device tree.
>
Any specific reason not to use of-thermal, then?
> Thanks,
> Martin
BR,
Eduardo Valentin
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2] ALSA SoC MAX98927 driver - Revision
From: Ryan Lee @ 2016-11-25 5:02 UTC (permalink / raw)
To: yesanishhere-Re5JQEeQqe8AvxtiuMwx3w,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k, arnd-r2nGTMty4D4,
michael-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/,
oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
jacob-EZCvousvhKUZux3j3Bed6dkegs52MxvZ,
Damien.Horsley-1AXoQHu6uovQT0dZR+AlfA,
bardliao-Rasf1IRRPZFBDgjK7y7TUQ,
kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
petr-Qh/3xLP0EvwAvxtiuMwx3w, lars-Qo5EllUWu/uELgA04lAiVw,
nh6z-fFIq/eER6g8, ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Ryan Lee
In-Reply-To: <1479877026-5172-1-git-send-email-RyanS.Lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
Signed-off-by: Ryan Lee <RyanS.Lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
---
.../devicetree/bindings/sound/max98927.txt | 33 +-
sound/soc/codecs/max98927.c | 839 +++++------
sound/soc/codecs/max98927.h | 1463 ++++----------------
3 files changed, 692 insertions(+), 1643 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/max98927.txt b/Documentation/devicetree/bindings/sound/max98927.txt
index ddcd332..d610879 100755
--- a/Documentation/devicetree/bindings/sound/max98927.txt
+++ b/Documentation/devicetree/bindings/sound/max98927.txt
@@ -6,19 +6,25 @@ Required properties:
- compatible : "maxim,max98927"
- - vmon-slot-no : slot number used to send voltage information
+ - maxim,vmon-slot-no : slot number used to send voltage information
or in inteleave mode this will be used as
interleave slot.
-
- - imon-slot-no : slot number used to send current information
-
- - interleave-mode : When using two MAX98927 in a system it is
- possible to create ADC data that that will
- overflow the frame size. Digital Audio Interleave
- mode provides a means to output VMON and IMON data
- from two devices on a single DOUT line when running
- smaller frames sizes such as 32 BCLKS per LRCLK or
- 48 BCLKS per LRCLK.
+ This property can be set to values from 0 to 15 for slot 0 to 15.
+ Default value is 0.
+
+ - maxim,imon-slot-no : slot number used to send current information
+ This property can be set to values from 0 to 15 for slot 0 to 15.
+ Default value is 0.
+
+ - maxim,interleave-mode : When using two MAX98927 in a system it is
+ possible to create ADC data that that will
+ overflow the frame size. Digital Audio Interleave
+ mode provides a means to output VMON and IMON data
+ from two devices on a single DOUT line when running
+ smaller frames sizes such as 32 BCLKS per LRCLK or
+ 48 BCLKS per LRCLK.
+ This property can be set to values from 0 to 1 for off and on.
+ Default value is 0.
- reg : the I2C address of the device for I2C
@@ -26,7 +32,8 @@ Example:
codec: max98927@3a {
compatible = "maxim,max98927";
- vmon-slot-no = <1>;
- imon-slot-no = <0>;
+ maxim,vmon-slot-no = <0>;
+ maxim,imon-slot-no = <1>;
+ maxim,interleave-mode = <0>;
reg = <0x3a>;
};
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index d85c84f..9c16fe8 100755
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -1,7 +1,7 @@
/*
* max98927.c -- MAX98927 ALSA Soc Audio driver
*
- * Copyright 2013-15 Maxim Integrated Products
+ * Copyright 2013-16 Maxim Integrated Products
* Author: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
*
* This program is free software; you can redistribute it and/or modify it
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -24,54 +23,122 @@
#include <sound/tlv.h>
#include "max98927.h"
-static struct reg_default max98927_reg_map[] = {
- {0x0014, 0x78},
- {0x0015, 0xFF},
- {0x0043, 0x04},
- {0x0017, 0x55},
- /* For mono driver we are just enabling one channel*/
- {MAX98927_PCM_Rx_Enables_A, 0x03},
- {MAX98927_PCM_Tx_HiZ_Control_A, 0xfc},
- {MAX98927_PCM_Tx_HiZ_Control_B, 0xff},
- {MAX98927_PCM_Tx_Channel_Sources_A, 0x01},
- {MAX98927_PCM_Tx_Channel_Sources_B, 0x01},
- {MAX98927_Measurement_DSP_Config, 0xf7},
- {0x0025, 0x80},
- {0x0026, 0x01},
- {0x0035, 0x40},
- {0x0036, 0x40},
- {0x0037, 0x02},
- {0x0039, 0x01},
- {0x003c, 0x44},
- {0x003d, 0x04},
- {0x0040, 0x10},
- {0x0042, 0x3f},
- {0x0044, 0x00},
- {0x0045, 0x24},
- {0x007f, 0x06},
- {0x0087, 0x1c},
- {0x0089, 0x03},
- {0x009f, 0x01},
+static struct reg_default max98927_reg[] = {
+ {MAX98927_R0001_INT_RAW1, 0x00},
+ {MAX98927_R0002_INT_RAW2, 0x00},
+ {MAX98927_R0003_INT_RAW3, 0x00},
+ {MAX98927_R0004_INT_STATE1, 0x00},
+ {MAX98927_R0005_INT_STATE2, 0x00},
+ {MAX98927_R0006_INT_STATE3, 0x00},
+ {MAX98927_R0007_INT_FLAG1, 0x00},
+ {MAX98927_R0008_INT_FLAG2, 0x00},
+ {MAX98927_R0009_INT_FLAG3, 0x00},
+ {MAX98927_R000A_INT_EN1, 0x00},
+ {MAX98927_R000B_INT_EN2, 0x00},
+ {MAX98927_R000C_INT_EN3, 0x00},
+ {MAX98927_R000D_INT_FLAG_CLR1, 0x00},
+ {MAX98927_R000E_INT_FLAG_CLR2, 0x00},
+ {MAX98927_R000F_INT_FLAG_CLR3, 0x00},
+ {MAX98927_R0010_IRQ_CTRL, 0x00},
+ {MAX98927_R0011_CLK_MON, 0x00},
+ {MAX98927_R0012_WDOG_CTRL, 0x00},
+ {MAX98927_R0013_WDOG_RST, 0x00},
+ {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x00},
+ {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x00},
+ {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x00},
+ {MAX98927_R0017_PIN_CFG, 0x55},
+ {MAX98927_R0018_PCM_RX_EN_A, 0x00},
+ {MAX98927_R0019_PCM_RX_EN_B, 0x00},
+ {MAX98927_R001A_PCM_TX_EN_A, 0x00},
+ {MAX98927_R001B_PCM_TX_EN_B, 0x00},
+ {MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0x00},
+ {MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0x00},
+ {MAX98927_R001E_PCM_TX_CH_SRC_A, 0x00},
+ {MAX98927_R001F_PCM_TX_CH_SRC_B, 0x00},
+ {MAX98927_R0020_PCM_MODE_CFG, 0x40},
+ {MAX98927_R0021_PCM_MASTER_MODE, 0x00},
+ {MAX98927_R0022_PCM_CLK_SETUP, 0x22},
+ {MAX98927_R0023_PCM_SR_SETUP1, 0x00},
+ {MAX98927_R0024_PCM_SR_SETUP2, 0x00},
+ {MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, 0x00},
+ {MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, 0x00},
+ {MAX98927_R0027_ICC_RX_EN_A, 0x00},
+ {MAX98927_R0028_ICC_RX_EN_B, 0x00},
+ {MAX98927_R002B_ICC_TX_EN_A, 0x00},
+ {MAX98927_R002C_ICC_TX_EN_B, 0x00},
+ {MAX98927_R002E_ICC_HIZ_MANUAL_MODE, 0x00},
+ {MAX98927_R002F_ICC_TX_HIZ_EN_A, 0x00},
+ {MAX98927_R0030_ICC_TX_HIZ_EN_B, 0x00},
+ {MAX98927_R0031_ICC_LNK_EN, 0x00},
+ {MAX98927_R0032_PDM_TX_EN, 0x00},
+ {MAX98927_R0033_PDM_TX_HIZ_CTRL, 0x00},
+ {MAX98927_R0034_PDM_TX_CTRL, 0x00},
+ {MAX98927_R0035_PDM_RX_CTRL, 0x00},
+ {MAX98927_R0036_AMP_VOL_CTRL, 0x00},
+ {MAX98927_R0037_AMP_DSP_CFG, 0x02},
+ {MAX98927_R0038_TONE_GEN_DC_CFG, 0x00},
+ {MAX98927_R0039_DRE_CTRL, 0x01},
+ {MAX98927_R003A_AMP_EN, 0x00},
+ {MAX98927_R003B_SPK_SRC_SEL, 0x00},
+ {MAX98927_R003C_SPK_GAIN, 0x00},
+ {MAX98927_R003D_SSM_CFG, 0x01},
+ {MAX98927_R003E_MEAS_EN, 0x00},
+ {MAX98927_R003F_MEAS_DSP_CFG, 0x04},
+ {MAX98927_R0040_BOOST_CTRL0, 0x00},
+ {MAX98927_R0041_BOOST_CTRL3, 0x00},
+ {MAX98927_R0042_BOOST_CTRL1, 0x00},
+ {MAX98927_R0043_MEAS_ADC_CFG, 0x00},
+ {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00},
+ {MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x00},
+ {MAX98927_R0046_ADC_CH0_DIVIDE, 0x00},
+ {MAX98927_R0047_ADC_CH1_DIVIDE, 0x00},
+ {MAX98927_R0048_ADC_CH2_DIVIDE, 0x00},
+ {MAX98927_R0049_ADC_CH0_FILT_CFG, 0x00},
+ {MAX98927_R004A_ADC_CH1_FILT_CFG, 0x00},
+ {MAX98927_R004B_ADC_CH2_FILT_CFG, 0x00},
+ {MAX98927_R004C_MEAS_ADC_CH0_READ, 0x00},
+ {MAX98927_R004D_MEAS_ADC_CH1_READ, 0x00},
+ {MAX98927_R004E_MEAS_ADC_CH2_READ, 0x00},
+ {MAX98927_R0051_BROWNOUT_STATUS, 0x00},
+ {MAX98927_R0052_BROWNOUT_EN, 0x00},
+ {MAX98927_R0053_BROWNOUT_INFINITE_HOLD, 0x00},
+ {MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR, 0x00},
+ {MAX98927_R0055_BROWNOUT_LVL_HOLD, 0x00},
+ {MAX98927_R005A_BROWNOUT_LVL1_THRESH, 0x00},
+ {MAX98927_R005B_BROWNOUT_LVL2_THRESH, 0x00},
+ {MAX98927_R005C_BROWNOUT_LVL3_THRESH, 0x00},
+ {MAX98927_R005D_BROWNOUT_LVL4_THRESH, 0x00},
+ {MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS, 0x00},
+ {MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL, 0x00},
+ {MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL, 0x00},
+ {MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE, 0x00},
+ {MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT, 0x00},
+ {MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1, 0x00},
+ {MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2, 0x00},
+ {MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3, 0x00},
+ {MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT, 0x00},
+ {MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1, 0x00},
+ {MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2, 0x00},
+ {MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3, 0x00},
+ {MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT, 0x00},
+ {MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1, 0x00},
+ {MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2, 0x00},
+ {MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3, 0x00},
+ {MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT, 0x00},
+ {MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, 0x00},
+ {MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2, 0x00},
+ {MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3, 0x00},
+ {MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, 0x00},
+ {MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY, 0x00},
+ {MAX98927_R0084_ENV_TRACK_REL_RATE, 0x00},
+ {MAX98927_R0085_ENV_TRACK_HOLD_RATE, 0x00},
+ {MAX98927_R0086_ENV_TRACK_CTRL, 0x00},
+ {MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, 0x00},
+ {MAX98927_R00FF_GLOBAL_SHDN, 0x00},
+ {MAX98927_R0100_SOFT_RESET, 0x00},
+ {MAX98927_R01FF_REV_ID, 0x40},
};
-void max98927_wrapper_write(struct max98927_priv *max98927,
- unsigned int reg, unsigned int val)
-{
- if (max98927->regmap)
- regmap_write(max98927->regmap, reg, val);
- if (max98927->sub_regmap)
- regmap_write(max98927->sub_regmap, reg, val);
-}
-
-void max98927_wrap_update_bits(struct max98927_priv *max98927,
- unsigned int reg, unsigned int mask, unsigned int val)
-{
- if (max98927->regmap)
- regmap_update_bits(max98927->regmap, reg, mask, val);
- if (max98927->sub_regmap)
- regmap_update_bits(max98927->sub_regmap, reg, mask, val);
-}
-
static int max98927_reg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol, unsigned int reg,
unsigned int mask, unsigned int shift)
@@ -81,8 +148,7 @@ static int max98927_reg_get(struct snd_kcontrol *kcontrol,
int data;
regmap_read(max98927->regmap, reg, &data);
- ucontrol->value.integer.value[0] =
- (data & mask) >> shift;
+ ucontrol->value.integer.value[0] = (data & mask) >> shift;
return 0;
}
@@ -94,83 +160,81 @@ static int max98927_reg_put(struct snd_kcontrol *kcontrol,
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
- max98927_wrap_update_bits(max98927, reg, mask, sel << shift);
+ regmap_update_bits(max98927->regmap, reg, mask, sel << shift);
dev_dbg(codec->dev, "%s: register 0x%02X, value 0x%02X\n",
- __func__, reg, sel);
+ __func__, reg, sel);
return 0;
}
static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
+ unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+ unsigned int mode = 0;
unsigned int invert = 0;
dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_SLAVE);
+ mode = MAX98927_PCM_MASTER_MODE_SLAVE;
break;
case SND_SOC_DAIFMT_CBM_CFM:
max98927->master = true;
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_MASTER);
+ mode = MAX98927_PCM_MASTER_MODE_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFM:
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_HYBRID);
+ mode = MAX98927_PCM_MASTER_MODE_HYBRID;
default:
dev_err(codec->dev, "DAI clock mode unsupported");
return -EINVAL;
}
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MASK,
+ mode);
+
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_NF:
- invert = MAX98927_PCM_Mode_Config_PCM_BCLKEDGE;
+ invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
break;
default:
dev_err(codec->dev, "DAI invert mode unsupported");
return -EINVAL;
}
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
+ invert);
+
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
max98927->iface |= SND_SOC_DAIFMT_I2S;
- max98927_wrap_update_bits(max98927,
- MAX98927_PCM_Mode_Config,
- max98927->iface, max98927->iface);
+
break;
case SND_SOC_DAIFMT_LEFT_J:
max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
- max98927_wrap_update_bits(max98927,
- MAX98927_PCM_Mode_Config,
- max98927->iface, max98927->iface);
break;
default:
return -EINVAL;
}
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ max98927->iface, max98927->iface);
+
/* pcm channel configuration */
- if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
- max98927_wrapper_write(max98927,
- MAX98927_PCM_Rx_Enables_A,
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH0_EN|
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH1_EN);
- max98927_wrapper_write(max98927,
- MAX98927_PCM_Tx_Enables_A,
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH0_EN|
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH1_EN);
- }
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Mode_Config,
- MAX98927_PCM_Mode_Config_PCM_BCLKEDGE, invert);
+ if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J))
+ regmap_write(max98927->regmap,
+ MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN|
+ MAX98927_PCM_RX_CH1_EN);
+
return 0;
}
@@ -182,12 +246,13 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai,
};
static int max98927_set_clock(struct max98927_priv *max98927,
- struct snd_pcm_hw_params *params)
+ struct snd_pcm_hw_params *params)
{
+ struct snd_soc_codec *codec = max98927->codec;
/* BCLK/LRCLK ratio calculation */
int blr_clk_ratio = params_channels(params) * max98927->ch_size;
- int reg = MAX98927_PCM_Clock_setup;
- int mask = MAX98927_PCM_Clock_setup_PCM_BSEL_Mask;
+ int reg = MAX98927_R0022_PCM_CLK_SETUP;
+ int mask = MAX98927_PCM_CLK_SETUP_BSEL_MASK;
int value;
if (max98927->master) {
@@ -198,13 +263,13 @@ static int max98927_set_clock(struct max98927_priv *max98927,
break;
}
if (i == ARRAY_SIZE(rate_table)) {
- pr_err("%s couldn't get the MCLK to match codec\n",
- __func__);
+ dev_err(codec->dev, "failed to find proper clock rate.\n");
return -EINVAL;
}
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode,
- MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_Mask,
- i << MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_SHIFT);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+ i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
}
switch (blr_clk_ratio) {
@@ -220,100 +285,93 @@ static int max98927_set_clock(struct max98927_priv *max98927,
default:
return -EINVAL;
}
- max98927_wrap_update_bits(max98927,
- reg, mask, value);
+ regmap_update_bits(max98927->regmap, reg, mask, value);
return 0;
}
static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
- int sampling_rate = 0;
+ unsigned int sampling_rate = 0;
+ unsigned int chan_sz = 0;
/* pcm mode configuration */
switch (snd_pcm_format_width(params_format(params))) {
case 16:
- max98927_wrap_update_bits(max98927,
- MAX98927_PCM_Mode_Config,
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_16,
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_16);
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
max98927->ch_size = 16;
break;
case 24:
- max98927_wrap_update_bits(max98927,
- MAX98927_PCM_Mode_Config,
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_24,
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_24);
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
max98927->ch_size = 24;
break;
case 32:
- max98927_wrap_update_bits(max98927,
- MAX98927_PCM_Mode_Config,
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_32,
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_32);
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
max98927->ch_size = 32;
break;
default:
- pr_err("%s: format unsupported %d",
- __func__, params_format(params));
+ dev_err(codec->dev, "format unsupported %d",
+ params_format(params));
goto err;
}
- dev_dbg(codec->dev, "%s: format supported %d",
- __func__, params_format(params));
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ chan_sz, chan_sz);
+
+ dev_dbg(codec->dev, "format supported %d",
+ params_format(params));
/* sampling rate configuration */
switch (params_rate(params)) {
case 8000:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_8000;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_8000;
break;
case 11025:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_11025;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_11025;
break;
case 12000:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_12000;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_12000;
break;
case 16000:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_16000;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_16000;
break;
case 22050:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_22050;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_22050;
break;
case 24000:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_24000;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_24000;
break;
case 32000:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_32000;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_32000;
break;
case 44100:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_44100;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_44100;
break;
case 48000:
- sampling_rate |=
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_48000;
+ sampling_rate |= MAX98927_PCM_SR_SET1_SR_48000;
break;
default:
- pr_err("%s rate %d not supported\n",
- __func__, params_rate(params));
+ dev_err(codec->dev, "rate %d not supported\n",
+ params_rate(params));
goto err;
}
/* set DAI_SR to correct LRCLK frequency */
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_1,
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_Mask, sampling_rate);
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_2,
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_Mask, sampling_rate<<4);
- max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_2,
- MAX98927_PCM_Sample_rate_setup_2_IVADC_SR_Mask, sampling_rate);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0023_PCM_SR_SETUP1,
+ MAX98927_PCM_SR_SET1_SR_MASK,
+ sampling_rate);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_SR_MASK,
+ sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate);
return max98927_set_clock(max98927, params);
err:
return -EINVAL;
@@ -325,7 +383,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
- int clk_id, unsigned int freq, int dir)
+ int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = dai->codec;
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
@@ -340,78 +398,37 @@ static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
.hw_params = max98927_dai_hw_params,
};
-static void max98927_handle_pdata(struct snd_soc_codec *codec)
-{
- struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
- struct max98927_reg_default *regInfo;
- int cfg_size = 0;
- int x;
-
- if (max98927->regcfg != NULL)
- cfg_size = max98927->regcfg_sz / sizeof(uint32_t);
-
- if (cfg_size <= 0) {
- dev_dbg(codec->dev,
- "Register configuration is not required.\n");
- return;
- }
-
- /* direct configuration from device tree */
- for (x = 0; x < cfg_size; x += 3) {
- regInfo = (struct max98927_reg_default *)&max98927->regcfg[x];
- dev_info(codec->dev, "CH:%d, reg:0x%02x, value:0x%02x\n",
- be32_to_cpu(regInfo->ch),
- be32_to_cpu(regInfo->reg),
- be32_to_cpu(regInfo->def));
- if (be32_to_cpu(regInfo->ch) == PRI_MAX98927
- && max98927->regmap)
- regmap_write(max98927->regmap,
- be32_to_cpu(regInfo->reg),
- be32_to_cpu(regInfo->def));
- else if (be32_to_cpu(regInfo->ch) == SEC_MAX98927
- && max98927->sub_regmap)
- regmap_write(max98927->sub_regmap,
- be32_to_cpu(regInfo->reg),
- be32_to_cpu(regInfo->def));
- }
-}
-
static int max98927_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- max98927_wrap_update_bits(max98927,
- MAX98927_AMP_enables, 1, 1);
- /* enable the v and i for vi feedback */
- max98927_wrap_update_bits(max98927,
- MAX98927_Measurement_enables,
- MAX98927_Measurement_enables_IVADC_V_EN,
- MAX98927_Measurement_enables_IVADC_V_EN);
- max98927_wrap_update_bits(max98927,
- MAX98927_Measurement_enables,
- MAX98927_Measurement_enables_IVADC_I_EN,
- MAX98927_Measurement_enables_IVADC_I_EN);
- max98927_wrap_update_bits(max98927,
- MAX98927_Global_Enable, 1, 1);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 1);
+ /* enable VMON and IMON */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003E_MEAS_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- max98927_wrap_update_bits(max98927,
- MAX98927_Global_Enable, 1, 0);
- max98927_wrap_update_bits(max98927,
- MAX98927_AMP_enables, 1, 0);
- /* disable the v and i for vi feedback */
- max98927_wrap_update_bits(max98927,
- MAX98927_Measurement_enables,
- MAX98927_Measurement_enables_IVADC_V_EN,
- 0);
- max98927_wrap_update_bits(max98927,
- MAX98927_Measurement_enables,
- MAX98927_Measurement_enables_IVADC_I_EN,
- 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 0);
+ /* disable VMON and IMON */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003E_MEAS_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
break;
default:
return 0;
@@ -421,7 +438,7 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_AMP_enables,
+ SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
0, 0, max98927_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("BE_OUT"),
@@ -431,7 +448,7 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0);
static int max98927_spk_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
@@ -443,22 +460,23 @@ static int max98927_spk_gain_get(struct snd_kcontrol *kcontrol,
}
static int max98927_spk_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
- if (sel < ((1 << MAX98927_Speaker_Gain_Width) - 1)) {
- max98927_wrap_update_bits(max98927, MAX98927_Speaker_Gain,
- MAX98927_Speaker_Gain_SPK_PCM_GAIN_Mask, sel);
+ if (sel < ((1 << MAX98927_SPK_GAIN_WIDTH) - 1)) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003C_SPK_GAIN,
+ MAX98927_SPK_PCM_GAIN_MASK, sel);
max98927->spk_gain = sel;
}
return 0;
}
static int max98927_digital_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
@@ -470,15 +488,16 @@ static int max98927_digital_gain_get(struct snd_kcontrol *kcontrol,
}
static int max98927_digital_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
if (sel < ((1 << MAX98927_AMP_VOL_WIDTH) - 1)) {
- max98927_wrap_update_bits(max98927, MAX98927_AMP_volume_control,
- MAX98927_AMP_volume_control_AMP_VOL_Mask, sel);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0036_AMP_VOL_CTRL,
+ MAX98927_AMP_VOL_MASK, sel);
max98927->digital_gain = sel;
}
return 0;
@@ -487,113 +506,126 @@ static int max98927_digital_gain_put(struct snd_kcontrol *kcontrol,
static int max98927_boost_voltage_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_get(kcontrol, ucontrol, MAX98927_Boost_Control_0,
- MAX98927_Boost_Control_0_BST_VOUT_Mask, 0);
+ return max98927_reg_get(kcontrol, ucontrol,
+ MAX98927_R0040_BOOST_CTRL0,
+ MAX98927_BOOST_CTRL0_VOUT_MASK, 0);
}
static int max98927_boost_voltage_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_put(kcontrol, ucontrol, MAX98927_Boost_Control_0,
- MAX98927_Boost_Control_0_BST_VOUT_Mask, 0);
+ return max98927_reg_put(kcontrol, ucontrol,
+ MAX98927_R0040_BOOST_CTRL0,
+ MAX98927_BOOST_CTRL0_VOUT_MASK, 0);
}
static int max98927_amp_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_get(kcontrol, ucontrol, MAX98927_Boost_Control_0,
- MAX98927_Boost_Control_0_BST_VOUT_Mask,
- MAX98927_AMP_VOL_LOCATION_SHIFT);
+ return max98927_reg_get(kcontrol, ucontrol,
+ MAX98927_R0036_AMP_VOL_CTRL,
+ MAX98927_AMP_VOL_SEL,
+ MAX98927_AMP_VOL_SHIFT);
+}
+
+static int max98927_amp_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98927_reg_put(kcontrol, ucontrol,
+ MAX98927_R0036_AMP_VOL_CTRL,
+ MAX98927_AMP_VOL_SEL,
+ MAX98927_AMP_VOL_SHIFT);
}
static int max98927_amp_dsp_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_put(kcontrol, ucontrol, MAX98927_Brownout_enables,
- MAX98927_Brownout_enables_AMP_DSP_EN, MAX98927_BDE_DSP_SHIFT);
+ return max98927_reg_put(kcontrol, ucontrol,
+ MAX98927_R0052_BROWNOUT_EN,
+ MAX98927_BROWNOUT_DSP_EN,
+ MAX98927_BROWNOUT_DSP_SHIFT);
}
static int max98927_amp_dsp_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_get(kcontrol, ucontrol, MAX98927_Brownout_enables,
- MAX98927_Brownout_enables_AMP_DSP_EN, MAX98927_BDE_DSP_SHIFT);
+ return max98927_reg_get(kcontrol, ucontrol,
+ MAX98927_R0052_BROWNOUT_EN,
+ MAX98927_BROWNOUT_DSP_EN,
+ MAX98927_BROWNOUT_DSP_SHIFT);
}
static int max98927_ramp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_put(kcontrol, ucontrol, MAX98927_AMP_DSP_Config,
- MAX98927_AMP_DSP_Config_AMP_VOL_RMP_BYPASS,
- MAX98927_SPK_RMP_EN_SHIFT);
+ return max98927_reg_put(kcontrol, ucontrol,
+ MAX98927_R0037_AMP_DSP_CFG,
+ MAX98927_AMP_DSP_CFG_RMP_BYPASS,
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT);
}
static int max98927_ramp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_get(kcontrol, ucontrol, MAX98927_AMP_DSP_Config,
- MAX98927_AMP_DSP_Config_AMP_VOL_RMP_BYPASS,
- MAX98927_SPK_RMP_EN_SHIFT);
+ return max98927_reg_get(kcontrol, ucontrol,
+ MAX98927_R0037_AMP_DSP_CFG,
+ MAX98927_AMP_DSP_CFG_RMP_BYPASS,
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT);
}
static int max98927_dre_en_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_put(kcontrol, ucontrol, MAX98927_DRE_Control,
- MAX98927_DRE_Control_DRE_EN, 0);
+ return max98927_reg_put(kcontrol, ucontrol,
+ MAX98927_R0039_DRE_CTRL,
+ MAX98927_DRE_CTRL_DRE_EN, 0);
}
static int max98927_dre_en_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return max98927_reg_get(kcontrol, ucontrol, MAX98927_DRE_Control,
- MAX98927_DRE_Control_DRE_EN, 0);
-}
-static int max98927_amp_vol_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return max98927_reg_put(kcontrol, ucontrol,
- MAX98927_AMP_volume_control,
- MAX98927_AMP_volume_control_AMP_VOL_SEL,
- MAX98927_AMP_VOL_LOCATION_SHIFT);
+ return max98927_reg_get(kcontrol, ucontrol,
+ MAX98927_R0039_DRE_CTRL,
+ MAX98927_DRE_CTRL_DRE_EN, 0);
}
static int max98927_spk_src_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return max98927_reg_get(kcontrol, ucontrol,
- MAX98927_Speaker_source_select,
- MAX98927_Speaker_source_select_SPK_SOURCE_Mask, 0);
+ MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 0);
}
static int max98927_spk_src_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return max98927_reg_put(kcontrol, ucontrol,
- MAX98927_Speaker_source_select,
- MAX98927_Speaker_source_select_SPK_SOURCE_Mask, 0);
+ MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 0);
}
static int max98927_mono_out_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return max98927_reg_get(kcontrol, ucontrol,
- MAX98927_PCM_to_speaker_monomix_A,
- MAX98927_PCM_to_spkmonomix_A_DMONOMIX_CFG_Mask,
- MAX98927_PCM_to_speaker_monomix_A_SHIFT);
+ MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK,
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT);
}
static int max98927_mono_out_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return max98927_reg_put(kcontrol, ucontrol,
- MAX98927_PCM_to_speaker_monomix_A,
- MAX98927_PCM_to_spkmonomix_A_DMONOMIX_CFG_Mask,
- MAX98927_PCM_to_speaker_monomix_A_SHIFT);
+ MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK,
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT);
}
static bool max98927_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0x0001 ... 0x0028:
- case 0x002B ... 0x004E:
+ case 0x002B ... 0x002C:
+ case 0x002E ... 0x004E:
case 0x0051 ... 0x0055:
case 0x005A ... 0x0061:
case 0x0072 ... 0x0087:
@@ -630,33 +662,39 @@ static bool max98927_readable_register(struct device *dev, unsigned int reg)
};
static const struct snd_kcontrol_new max98927_snd_controls[] = {
- SOC_SINGLE_EXT_TLV("Speaker Volume", MAX98927_Speaker_Gain,
- 0, (1<<MAX98927_Speaker_Gain_Width)-1, 0,
+ SOC_SINGLE_EXT_TLV("Speaker Volume",
+ MAX98927_R003C_SPK_GAIN,
+ 0, (1<<MAX98927_SPK_GAIN_WIDTH)-1, 0,
max98927_spk_gain_get, max98927_spk_gain_put,
max98927_spk_tlv),
- SOC_SINGLE_EXT_TLV("Digital Gain", MAX98927_AMP_volume_control,
+ SOC_SINGLE_EXT_TLV("Digital Gain",
+ MAX98927_R0036_AMP_VOL_CTRL,
0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
max98927_digital_gain_get, max98927_digital_gain_put,
max98927_digital_tlv),
- SOC_SINGLE_EXT("Amp DSP Enable", MAX98927_Brownout_enables,
- MAX98927_BDE_DSP_SHIFT, 1, 0,
+ SOC_SINGLE_EXT("Amp DSP Enable",
+ MAX98927_R0052_BROWNOUT_EN,
+ MAX98927_BROWNOUT_DSP_SHIFT, 1, 0,
max98927_amp_dsp_get, max98927_amp_dsp_put),
- SOC_SINGLE_EXT("Ramp Switch", MAX98927_AMP_DSP_Config,
- MAX98927_SPK_RMP_EN_SHIFT, 1, 1,
+ SOC_SINGLE_EXT("Ramp Switch",
+ MAX98927_R0037_AMP_DSP_CFG,
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 1,
max98927_ramp_switch_get, max98927_ramp_switch_put),
- SOC_SINGLE_EXT("DRE EN", MAX98927_DRE_Control,
- MAX98927_DRE_Control_DRE_SHIFT, 1, 0,
+ SOC_SINGLE_EXT("DRE EN",
+ MAX98927_R0039_DRE_CTRL,
+ MAX98927_DRE_EN_SHIFT, 1, 0,
max98927_dre_en_get, max98927_dre_en_put),
- SOC_SINGLE_EXT("Amp Volume Location", MAX98927_AMP_volume_control,
- MAX98927_AMP_VOL_LOCATION_SHIFT, 1, 0,
+ SOC_SINGLE_EXT("Amp Volume Location",
+ MAX98927_R0036_AMP_VOL_CTRL,
+ MAX98927_AMP_VOL_SHIFT, 1, 0,
max98927_amp_vol_get, max98927_amp_vol_put),
SOC_ENUM_EXT("Boost Output Voltage", max98927_enum[2],
- max98927_boost_voltage_get, max98927_boost_voltage_put),
+ max98927_boost_voltage_get, max98927_boost_voltage_put),
SOC_ENUM_EXT("Speaker Source", max98927_enum[1],
- max98927_spk_src_get, max98927_spk_src_put),
+ max98927_spk_src_get, max98927_spk_src_put),
SOC_ENUM_EXT("Monomix Output", max98927_enum[0],
- max98927_mono_out_get, max98927_mono_out_put),
+ max98927_mono_out_get, max98927_mono_out_put),
};
static const struct snd_soc_dapm_route max98927_audio_map[] = {
@@ -687,75 +725,143 @@ static bool max98927_readable_register(struct device *dev, unsigned int reg)
static int max98927_probe(struct snd_soc_codec *codec)
{
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
- int ret = 0, reg = 0, i;
+ int ret = 0, reg = 0;
max98927->codec = codec;
codec->control_data = max98927->regmap;
codec->cache_bypass = 1;
/* Software Reset */
- max98927_wrapper_write(max98927,
- MAX98927_Software_Reset, MAX98927_Software_Reset_RST);
+ regmap_write(max98927->regmap,
+ MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
- /* Check Revision ID for the primary MAX98927*/
- ret = regmap_read(max98927->regmap, MAX98927_REV_ID, ®);
+ /* Check Revision ID */
+ ret = regmap_read(max98927->regmap,
+ MAX98927_R01FF_REV_ID, ®);
if (ret < 0)
dev_err(codec->dev,
- "Failed to read: 0x%02X\n", MAX98927_REV_ID);
+ "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
else
dev_info(codec->dev,
"MAX98927 revisionID: 0x%02X\n", reg);
- /* Check Revision ID for the secondary MAX98927*/
- if (max98927->sub_regmap) {
- ret = regmap_read(max98927->sub_regmap, MAX98927_REV_ID, ®);
- if (ret < 0)
- dev_err(codec->dev,
- "Failed to read: 0x%02X from secodnary device\n"
- , MAX98927_REV_ID);
- else
- dev_info(codec->dev,
- "Secondary device revisionID: 0x%02X\n", reg);
+ /* IV default slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ 0x80);
+ regmap_write(max98927->regmap,
+ MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+ 0x1);
+ /* Set inital volume (+13dB) */
+ regmap_write(max98927->regmap,
+ MAX98927_R0036_AMP_VOL_CTRL,
+ 0x38);
+ regmap_write(max98927->regmap,
+ MAX98927_R003C_SPK_GAIN,
+ 0x05);
+ /* Enable DC blocker */
+ regmap_write(max98927->regmap,
+ MAX98927_R0037_AMP_DSP_CFG,
+ 0x03);
+ /* Enable IMON VMON DC blocker */
+ regmap_write(max98927->regmap,
+ MAX98927_R003F_MEAS_DSP_CFG,
+ 0xF7);
+ /* Boost Output Voltage & Current limit */
+ regmap_write(max98927->regmap,
+ MAX98927_R0040_BOOST_CTRL0,
+ 0x1C);
+ regmap_write(max98927->regmap,
+ MAX98927_R0042_BOOST_CTRL1,
+ 0x3E);
+ /* Measurement ADC config */
+ regmap_write(max98927->regmap,
+ MAX98927_R0043_MEAS_ADC_CFG,
+ 0x04);
+ regmap_write(max98927->regmap,
+ MAX98927_R0044_MEAS_ADC_BASE_MSB,
+ 0x00);
+ regmap_write(max98927->regmap,
+ MAX98927_R0045_MEAS_ADC_BASE_LSB,
+ 0x24);
+ /* Brownout Level */
+ regmap_write(max98927->regmap,
+ MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+ 0x06);
+ /* Envelope Tracking configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+ 0x08);
+ regmap_write(max98927->regmap,
+ MAX98927_R0086_ENV_TRACK_CTRL,
+ 0x01);
+ regmap_write(max98927->regmap,
+ MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+ 0x10);
+
+ /* voltage, current slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001E_PCM_TX_CH_SRC_A,
+ (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
+ max98927->v_l_slot)&0xFF);
+
+ if (max98927->v_l_slot < 8) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->v_l_slot, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->v_l_slot,
+ 1 << max98927->v_l_slot);
+ } else {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->v_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->v_l_slot - 8),
+ 1 << (max98927->v_l_slot - 8));
}
- /* Register initialization */
- for (i = 0; i < sizeof(max98927_reg_map)/
- sizeof(max98927_reg_map[0]); i++)
- max98927_wrapper_write(max98927,
- max98927_reg_map[i].reg,
- max98927_reg_map[i].def);
-
- if (max98927->regmap)
- regmap_write(max98927->regmap,
- MAX98927_PCM_Tx_Channel_Sources_A,
- (max98927->i_l_slot
- <<MAX98927_PCM_Tx_Ch_Sources_A_I_SHIFT|
- max98927->v_l_slot)&0xFF);
- if (max98927->sub_regmap)
- regmap_write(max98927->sub_regmap,
- MAX98927_PCM_Tx_Channel_Sources_A,
- (max98927->i_r_slot
- <<MAX98927_PCM_Tx_Ch_Sources_A_I_SHIFT|
- max98927->v_r_slot)&0xFF);
+ if (max98927->i_l_slot < 8) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->i_l_slot, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->i_l_slot,
+ 1 << max98927->i_l_slot);
+ } else {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->i_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->i_l_slot - 8),
+ 1 << (max98927->i_l_slot - 8));
+ }
/* Set interleave mode */
if (max98927->interleave_mode)
- max98927_wrap_update_bits(max98927,
- MAX98927_PCM_Tx_Channel_Sources_B,
- MAX98927_PCM_Tx_Channel_Src_INTERLEAVE_Mask,
- MAX98927_PCM_Tx_Channel_Src_INTERLEAVE_Mask);
-
- max98927_handle_pdata(codec);
-
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001F_PCM_TX_CH_SRC_B,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
return ret;
}
static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
.probe = max98927_probe,
- .dapm_routes = max98927_audio_map,
- .num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
.dapm_widgets = max98927_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets),
+ .dapm_routes = max98927_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
.controls = max98927_snd_controls,
.num_controls = ARRAY_SIZE(max98927_snd_controls),
};
@@ -763,74 +869,32 @@ static int max98927_probe(struct snd_soc_codec *codec)
static const struct regmap_config max98927_regmap = {
.reg_bits = 16,
.val_bits = 8,
- .max_register = MAX98927_REV_ID,
- .reg_defaults = max98927_reg_map,
- .num_reg_defaults = ARRAY_SIZE(max98927_reg_map),
+ .max_register = MAX98927_R01FF_REV_ID,
+ .reg_defaults = max98927_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98927_reg),
.readable_reg = max98927_readable_register,
.cache_type = REGCACHE_RBTREE,
};
-static struct i2c_board_info max98927_i2c_sub_board[] = {
- {
- I2C_BOARD_INFO("max98927_sub", 0x39),
- }
-};
-
-static struct i2c_driver max98927_i2c_sub_driver = {
- .driver = {
- .name = "max98927_sub",
- .owner = THIS_MODULE,
- },
-};
-
-struct i2c_client *max98927_add_sub_device(int bus_id, int slave_addr)
-{
- struct i2c_client *i2c = NULL;
- struct i2c_adapter *adapter;
-
- max98927_i2c_sub_board[0].addr = slave_addr;
-
- adapter = i2c_get_adapter(bus_id);
- if (adapter) {
- i2c = i2c_new_device(adapter, max98927_i2c_sub_board);
- if (i2c)
- i2c->dev.driver = &max98927_i2c_sub_driver.driver;
- }
-
- return i2c;
-}
-
-int probe_common(struct i2c_client *i2c, struct max98927_priv *max98927)
+static void max98927_slot_config(struct i2c_client *i2c,
+ struct max98927_priv *max98927)
{
- int ret = 0, value;
+ int value;
- if (!of_property_read_u32(i2c->dev.of_node, "vmon-l-slot", &value))
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "maxim,vmon-slot-no", &value))
max98927->v_l_slot = value & 0xF;
else
max98927->v_l_slot = 0;
- if (!of_property_read_u32(i2c->dev.of_node, "imon-l-slot", &value))
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "maxim,imon-slot-no", &value))
max98927->i_l_slot = value & 0xF;
else
max98927->i_l_slot = 1;
- if (!of_property_read_u32(i2c->dev.of_node, "vmon-r-slot", &value))
- max98927->v_r_slot = value & 0xF;
- else
- max98927->v_r_slot = 2;
- if (!of_property_read_u32(i2c->dev.of_node, "imon-r-slot", &value))
- max98927->i_r_slot = value & 0xF;
- else
- max98927->i_r_slot = 3;
-
- ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
- max98927_dai, ARRAY_SIZE(max98927_dai));
- if (ret < 0)
- dev_err(&i2c->dev,
- "Failed to register codec: %d\n", ret);
- return ret;
}
static int max98927_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
int ret = 0, value;
@@ -847,7 +911,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c,
/* update interleave mode info */
if (!of_property_read_u32(i2c->dev.of_node,
- "interleave_mode", &value)) {
+ "maxim,interleave_mode", &value)) {
if (value > 0)
max98927->interleave_mode = 1;
else
@@ -855,25 +919,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c,
} else
max98927->interleave_mode = 0;
- /* update direct configuration info */
- max98927->regcfg = of_get_property(i2c->dev.of_node,
- "maxim,regcfg", &max98927->regcfg_sz);
-
- /* check for secondary MAX98927 */
- ret = of_property_read_u32(i2c->dev.of_node,
- "maxim,sub_reg", &max98927->sub_reg);
- if (ret) {
- dev_err(&i2c->dev, "Sub-device slave address was not found.\n");
- max98927->sub_reg = -1;
- }
- ret = of_property_read_u32(i2c->dev.of_node,
- "maxim,sub_bus", &max98927->sub_bus);
- if (ret) {
- dev_err(&i2c->dev, "Sub-device bus information was not found.\n");
- max98927->sub_bus = i2c->adapter->nr;
- }
-
- /* regmap initialization for primary device */
+ /* regmap initialization */
max98927->regmap
= devm_regmap_init_i2c(i2c, &max98927_regmap);
if (IS_ERR(max98927->regmap)) {
@@ -883,30 +929,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c,
goto err;
}
- /* regmap initialization for secondary device */
- if (max98927->sub_reg > 0) {
- max98927->sub_i2c = max98927_add_sub_device(max98927->sub_bus,
- max98927->sub_reg);
- if (IS_ERR(max98927->sub_i2c)) {
- dev_err(&max98927->sub_i2c->dev,
- "Second MAX98927 was not found\n");
- ret = PTR_ERR(max98927->regmap);
- goto err;
- } else {
- max98927->sub_regmap = regmap_init_i2c(
- max98927->sub_i2c, &max98927_regmap);
- if (IS_ERR(max98927->sub_regmap)) {
- ret = PTR_ERR(max98927->sub_regmap);
- dev_err(&max98927->sub_i2c->dev,
- "Failed to allocate sub_regmap: %d\n",
- ret);
- goto err;
- }
- }
- }
+ /* voltage/current slot configuration */
+ max98927_slot_config(i2c, max98927);
/* codec registeration */
- ret = probe_common(i2c, max98927);
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
+ max98927_dai, ARRAY_SIZE(max98927_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
return ret;
@@ -929,16 +959,17 @@ static int max98927_i2c_remove(struct i2c_client *client)
MODULE_DEVICE_TABLE(i2c, max98927_i2c_id);
+#if defined(CONFIG_OF)
static const struct of_device_id max98927_of_match[] = {
{ .compatible = "maxim,max98927", },
{ }
};
MODULE_DEVICE_TABLE(of, max98927_of_match);
+#endif
static struct i2c_driver max98927_i2c_driver = {
.driver = {
.name = "max98927",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(max98927_of_match),
.pm = NULL,
},
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
index 2305185..9e5041a 100755
--- a/sound/soc/codecs/max98927.h
+++ b/sound/soc/codecs/max98927.h
@@ -1,7 +1,7 @@
/*
- * max98927.c -- MAX98927 ALSA Soc Audio driver
+ * max98927.h -- MAX98927 ALSA Soc Audio driver
*
- * Copyright 2008-11 Wolfson Microelectronics PLC.
+ * Copyright 2013-15 Maxim Integrated Products
* Author: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
*
* This program is free software; you can redistribute it and/or modify it
@@ -10,1244 +10,255 @@
* option) any later version.
*
*/
-#ifndef __MAX98927_REGISTERDEFS_H
-#define __MAX98927_REGISTERDEFS_H
-#ifdef CONFIG_SND_SOC_MAXIM_DSM
-#include <sound/maxim_dsm.h>
-#endif /* CONFIG_SND_SOC_MAXIM_DSM */
+#ifndef _MAX98927_H
+#define _MAX98927_H
+
+/* Register Values */
+#define MAX98927_R0001_INT_RAW1 0x0001
+#define MAX98927_R0002_INT_RAW2 0x0002
+#define MAX98927_R0003_INT_RAW3 0x0003
+#define MAX98927_R0004_INT_STATE1 0x0004
+#define MAX98927_R0005_INT_STATE2 0x0005
+#define MAX98927_R0006_INT_STATE3 0x0006
+#define MAX98927_R0007_INT_FLAG1 0x0007
+#define MAX98927_R0008_INT_FLAG2 0x0008
+#define MAX98927_R0009_INT_FLAG3 0x0009
+#define MAX98927_R000A_INT_EN1 0x000A
+#define MAX98927_R000B_INT_EN2 0x000B
+#define MAX98927_R000C_INT_EN3 0x000C
+#define MAX98927_R000D_INT_FLAG_CLR1 0x000D
+#define MAX98927_R000E_INT_FLAG_CLR2 0x000E
+#define MAX98927_R000F_INT_FLAG_CLR3 0x000F
+#define MAX98927_R0010_IRQ_CTRL 0x0010
+#define MAX98927_R0011_CLK_MON 0x0011
+#define MAX98927_R0012_WDOG_CTRL 0x0012
+#define MAX98927_R0013_WDOG_RST 0x0013
+#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014
+#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015
+#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016
+#define MAX98927_R0017_PIN_CFG 0x0017
+#define MAX98927_R0018_PCM_RX_EN_A 0x0018
+#define MAX98927_R0019_PCM_RX_EN_B 0x0019
+#define MAX98927_R001A_PCM_TX_EN_A 0x001A
+#define MAX98927_R001B_PCM_TX_EN_B 0x001B
+#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C
+#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D
+#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E
+#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F
+#define MAX98927_R0020_PCM_MODE_CFG 0x0020
+#define MAX98927_R0021_PCM_MASTER_MODE 0x0021
+#define MAX98927_R0022_PCM_CLK_SETUP 0x0022
+#define MAX98927_R0023_PCM_SR_SETUP1 0x0023
+#define MAX98927_R0024_PCM_SR_SETUP2 0x0024
+#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025
+#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026
+#define MAX98927_R0027_ICC_RX_EN_A 0x0027
+#define MAX98927_R0028_ICC_RX_EN_B 0x0028
+#define MAX98927_R002B_ICC_TX_EN_A 0x002B
+#define MAX98927_R002C_ICC_TX_EN_B 0x002C
+#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E
+#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F
+#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030
+#define MAX98927_R0031_ICC_LNK_EN 0x0031
+#define MAX98927_R0032_PDM_TX_EN 0x0032
+#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033
+#define MAX98927_R0034_PDM_TX_CTRL 0x0034
+#define MAX98927_R0035_PDM_RX_CTRL 0x0035
+#define MAX98927_R0036_AMP_VOL_CTRL 0x0036
+#define MAX98927_R0037_AMP_DSP_CFG 0x0037
+#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038
+#define MAX98927_R0039_DRE_CTRL 0x0039
+#define MAX98927_R003A_AMP_EN 0x003A
+#define MAX98927_R003B_SPK_SRC_SEL 0x003B
+#define MAX98927_R003C_SPK_GAIN 0x003C
+#define MAX98927_R003D_SSM_CFG 0x003D
+#define MAX98927_R003E_MEAS_EN 0x003E
+#define MAX98927_R003F_MEAS_DSP_CFG 0x003F
+#define MAX98927_R0040_BOOST_CTRL0 0x0040
+#define MAX98927_R0041_BOOST_CTRL3 0x0041
+#define MAX98927_R0042_BOOST_CTRL1 0x0042
+#define MAX98927_R0043_MEAS_ADC_CFG 0x0043
+#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044
+#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045
+#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046
+#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047
+#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048
+#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049
+#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A
+#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B
+#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C
+#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D
+#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E
+#define MAX98927_R0051_BROWNOUT_STATUS 0x0051
+#define MAX98927_R0052_BROWNOUT_EN 0x0052
+#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053
+#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054
+#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055
+#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A
+#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B
+#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C
+#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D
+#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E
+#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F
+#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060
+#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061
+#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072
+#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073
+#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074
+#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075
+#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076
+#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077
+#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078
+#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079
+#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A
+#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B
+#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C
+#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D
+#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E
+#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F
+#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080
+#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081
+#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082
+#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083
+#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084
+#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085
+#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086
+#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087
+#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF
+#define MAX98927_R0100_SOFT_RESET 0x0100
+#define MAX98927_R01FF_REV_ID 0x01FF
+
+/* MAX98927_R0018_PCM_RX_EN_A */
+#define MAX98927_PCM_RX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_RX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_RX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_RX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_RX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_RX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_RX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_RX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001A_PCM_TX_EN_A */
+#define MAX98927_PCM_TX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_TX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_TX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_TX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_TX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_TX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_TX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_TX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001E_PCM_TX_CH_SRC_A */
+#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98927_R001F_PCM_TX_CH_SRC_B */
+#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5)
+
+/* MAX98927_R0020_PCM_MODE_CFG */
+#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2)
+#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+
+#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98927_R0021_PCM_MASTER_MODE */
+#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0)
+#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0)
+#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0)
+#define MAX98927_PCM_MASTER_MODE_HYBRID (0x1 << 0)
+
+#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2)
+#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2)
+
+/* MAX98927_R0022_PCM_CLK_SETUP */
+#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98927_R0023_PCM_SR_SETUP1 */
+#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0)
+
+#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0)
+#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0)
+#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0)
+#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0)
+#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0)
+#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0)
+#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0)
+#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0)
+#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0)
+
+/* MAX98927_R0024_PCM_SR_SETUP2 */
+#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4)
+#define MAX98927_PCM_SR_SET2_SR_SHIFT (4)
+#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0)
+
+/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
+
+/* MAX98927_R0036_AMP_VOL_CTRL */
+#define MAX98927_AMP_VOL_MASK (0x7f << 0)
+#define MAX98927_AMP_VOL_SEL (0x1 << 7)
+#define MAX98927_AMP_VOL_WIDTH (3)
+#define MAX98927_AMP_VOL_SHIFT (7)
+
+/* MAX98927_R0037_AMP_DSP_CFG */
+#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0)
+#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1)
+#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4)
+#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5)
+#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4)
+
+/* MAX98927_R0039_DRE_CTRL */
+#define MAX98927_DRE_CTRL_DRE_EN (0x1 << 0)
+#define MAX98927_DRE_EN_SHIFT 0x1
+
+/* MAX98927_R003A_AMP_EN */
+#define MAX98927_AMP_EN_MASK (0x1 << 0)
+
+/* MAX98927_R003B_SPK_SRC_SEL */
+#define MAX98927_SPK_SRC_MASK (0x3 << 0)
+
+/* MAX98927_R003C_SPK_GAIN */
+#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0)
+#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4)
+#define MAX98927_SPK_GAIN_WIDTH (3)
+
+/* MAX98927_R003E_MEAS_EN */
+#define MAX98927_MEAS_V_EN (0x1 << 0)
+#define MAX98927_MEAS_I_EN (0x1 << 1)
+
+/* MAX98927_R0040_BOOST_CTRL0 */
+#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0)
+#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7)
+#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7)
+
+/* MAX98927_R0052_BROWNOUT_EN */
+#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0)
+#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1)
+#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2)
+#define MAX98927_BROWNOUT_DSP_SHIFT (2)
+
+/* MAX98927_R0100_SOFT_RESET */
+#define MAX98927_SOFT_RESET (0x1 << 0)
+
+/* MAX98927_R00FF_GLOBAL_SHDN */
+#define MAX98927_GLOBAL_EN_MASK (0x1 << 0)
-enum {
- PRI_MAX98927 = 0,
- SEC_MAX98927 = 1,
- MAX_DEV_ID_MAX98927,
-} MAX98927deviceID;
-
-enum {
- /*Interrupt Raw 1 (Address 0x0001)*/
- MAX98927_Interrupt_Raw_1 = 0x0001,
- MAX98927_Interrupt_Raw_1_BDE_ACTIVE_END_RAW = (0x1 << 0),
- MAX98927_Interrupt_Raw_1_BDE_ACTIVE_BGN_RAW = (0x1 << 1),
- MAX98927_Interrupt_Raw_1_BDE_LEVEL_CHANGE_RAW = (0x1 << 2),
- MAX98927_Interrupt_Raw_1_BDE_L8_RAW = (0x1 << 3),
- MAX98927_Interrupt_Raw_1_THERMWARN_END_RAW = (0x1 << 4),
- MAX98927_Interrupt_Raw_1_THERMWARN_START_RAW = (0x1 << 5),
- MAX98927_Interrupt_Raw_1_THERMSHDN_END_RAW = (0x1 << 6),
- MAX98927_Interrupt_Raw_1_THERMSHDN_START_RAW = (0x1 << 7),
-
- /* Interrupt Raw 2 (Address 0x0002)*/
- MAX98927_Interrupt_Raw_2 = 0x0002,
- MAX98927_Interrupt_Raw_2_WATCHDOGWARN_RAW = (0x1 << 0),
- MAX98927_Interrupt_Raw_2_WATCHDOGFAIL_RAW = (0x1 << 1),
- MAX98927_Interrupt_Raw_2_BOOSTCURRLIM_RAW = (0x1 << 2),
- MAX98927_Interrupt_Raw_2_CLKSTOP_RAW = (0x1 << 3),
- MAX98927_Interrupt_Raw_2_CLKSTART_RAW = (0x1 << 4),
- MAX98927_Interrupt_Raw_2_MEASADC_END_RAW = (0x1 << 5),
- MAX98927_Interrupt_Raw_2_PWRDN_DONE_RAW = (0x1 << 6),
- MAX98927_Interrupt_Raw_2_PWRUP_DONE_RAW = (0x1 << 7),
-
- /* Interrupt Raw 3 (Address 0x0003)*/
- MAX98927_Interrupt_Raw_3 = 0x0003,
- MAX98927_Interrupt_Raw_3_PWRUP_FAIL_RAW = (0x1 << 0),
- MAX98927_Interrupt_Raw_3_AUTH_DONE_RAW = (0x1 << 1),
- MAX98927_Interrupt_Raw_3_SPK_OVC_RAW = (0x1 << 2),
- MAX98927_Interrupt_Raw_3_BST_UVLO_RAW = (0x1 << 3),
-
- /* Interrupt State 1 (Address 0x0004)*/
- MAX98927_Interrupt_State_1 = 0x0004,
- MAX98927_Interrupt_State_1_BDE_ACTIVE_END_STATE = (0x1 << 0),
- MAX98927_Interrupt_State_1_BDE_ACTIVE_BGN_STATE = (0x1 << 1),
- MAX98927_Interrupt_State_1_BDE_LEVEL_CHANGE_STATE = (0x1 << 2),
- MAX98927_Interrupt_State_1_BDE_L8_STATE = (0x1 << 3),
- MAX98927_Interrupt_State_1_THERMWARN_END_STATE = (0x1 << 4),
- MAX98927_Interrupt_State_1_THERMWARN_START_STATE = (0x1 << 5),
- MAX98927_Interrupt_State_1_THERMSHDN_END_STATE = (0x1 << 6),
- MAX98927_Interrupt_State_1_THERMSHDN_START_STATE = (0x1 << 7),
-
- /* Interrupt State 2 (Address 0x0005)*/
- MAX98927_Interrupt_State_2 = 0x0005,
- MAX98927_Interrupt_State_2_WATCHDOGWARN_STATE = (0x1 << 0),
- MAX98927_Interrupt_State_2_WATCHDOGFAIL_STATE = (0x1 << 1),
- MAX98927_Interrupt_State_2_BOOSTCURRLIM_STATE = (0x1 << 2),
- MAX98927_Interrupt_State_2_CLKSTOP_STATE = (0x1 << 3),
- MAX98927_Interrupt_State_2_CLKSTART_STATE = (0x1 << 4),
- MAX98927_Interrupt_State_2_MEASADC_END_STATE = (0x1 << 5),
- MAX98927_Interrupt_State_2_PWRDN_DONE_STATE = (0x1 << 6),
- MAX98927_Interrupt_State_2_PWRUP_DONE_STATE = (0x1 << 7),
-
- /* Interrupt State 3 (Address 0x0006)*/
- MAX98927_Interrupt_State_3 = 0x0006,
- MAX98927_Interrupt_State_3_PWRUP_FAIL_STATE = (0x1 << 0),
- MAX98927_Interrupt_State_3_AUTH_DONE_STATE = (0x1 << 1),
- MAX98927_Interrupt_State_3_SPK_OVC_STATE = (0x1 << 2),
- MAX98927_Interrupt_State_3_BST_UVLO_STATE = (0x1 << 3),
-
- /* Interrupt Flag 1 (Address 0x0007)*/
- MAX98927_Interrupt_Flag_1 = 0x0007,
- MAX98927_Interrupt_Flag_1_BDE_ACTIVE_END_FLAG = (0x1 << 0),
- MAX98927_Interrupt_Flag_1_BDE_ACTIVE_BGN_FLAG = (0x1 << 1),
- MAX98927_Interrupt_Flag_1_BDE_LEVEL_CHANGE_FLAG = (0x1 << 2),
- MAX98927_Interrupt_Flag_1_BDE_L8_FLAG = (0x1 << 3),
- MAX98927_Interrupt_Flag_1_THERMWARN_END_FLAG = (0x1 << 4),
- MAX98927_Interrupt_Flag_1_THERMWARN_START_FLAG = (0x1 << 5),
- MAX98927_Interrupt_Flag_1_THERMSHDN_END_FLAG = (0x1 << 6),
- MAX98927_Interrupt_Flag_1_THERMSHDN_START_FLAG = (0x1 << 7),
-
- /* Interrupt Flag 2 (Address 0x0008)*/
- MAX98927_Interrupt_Flag_2 = 0x0008,
- MAX98927_Interrupt_Flag_2_WATCHDOGWARN_FLAG = (0x1 << 0),
- MAX98927_Interrupt_Flag_2_WATCHDOGFAIL_FLAG = (0x1 << 1),
- MAX98927_Interrupt_Flag_2_BOOSTCURRLIM_FLAG = (0x1 << 2),
- MAX98927_Interrupt_Flag_2_CLKSTOP_FLAG = (0x1 << 3),
- MAX98927_Interrupt_Flag_2_CLKSTART_FLAG = (0x1 << 4),
- MAX98927_Interrupt_Flag_2_MEASADC_END_FLAG = (0x1 << 5),
- MAX98927_Interrupt_Flag_2_PWRDN_DONE_FLAG = (0x1 << 6),
- MAX98927_Interrupt_Flag_2_PWRUP_DONE_FLAG = (0x1 << 7),
-
- /* Interrupt Flag 3 (Address 0x0009)*/
- MAX98927_Interrupt_Flag_3 = 0x0009,
- MAX98927_Interrupt_Flag_3_PWRUP_FAIL_FLAG = (0x1 << 0),
- MAX98927_Interrupt_Flag_3_AUTH_DONE_FLAG = (0x1 << 1),
- MAX98927_Interrupt_Flag_3_SPK_OVC_FLAG = (0x1 << 2),
- MAX98927_Interrupt_Flag_3_BST_UVLO_FLAG = (0x1 << 3),
-
- /* Interrupt Enable 1 (Address 0x000a)*/
- MAX98927_Interrupt_Enable_1 = 0x000a,
- MAX98927_Interrupt_Enable_1_BDE_ACTIVE_END_EN = (0x1 << 0),
- MAX98927_Interrupt_Enable_1_BDE_ACTIVE_BGN_EN = (0x1 << 1),
- MAX98927_Interrupt_Enable_1_BDE_LEVEL_CHANGE_EN = (0x1 << 2),
- MAX98927_Interrupt_Enable_1_BDE_L8_EN = (0x1 << 3),
- MAX98927_Interrupt_Enable_1_THERMWARN_END_EN = (0x1 << 4),
- MAX98927_Interrupt_Enable_1_THERMWARN_START_EN = (0x1 << 5),
- MAX98927_Interrupt_Enable_1_THERMSHDN_END_EN = (0x1 << 6),
- MAX98927_Interrupt_Enable_1_THERMSHDN_START_EN = (0x1 << 7),
-
- /* Interrupt Enable 2 (Address 0x000b)*/
- MAX98927_Interrupt_Enable_2 = 0x000b,
- MAX98927_Interrupt_Enable_2_WATCHDOGWARN_EN = (0x1 << 0),
- MAX98927_Interrupt_Enable_2_WATCHDOGFAIL_EN = (0x1 << 1),
- MAX98927_Interrupt_Enable_2_BOOSTCURRLIM_EN = (0x1 << 2),
- MAX98927_Interrupt_Enable_2_CLKSTOP_EN = (0x1 << 3),
- MAX98927_Interrupt_Enable_2_CLKSTART_EN = (0x1 << 4),
- MAX98927_Interrupt_Enable_2_MEASADC_END_EN = (0x1 << 5),
- MAX98927_Interrupt_Enable_2_PWRDN_DONE_EN = (0x1 << 6),
- MAX98927_Interrupt_Enable_2_PWRUP_DONE_EN = (0x1 << 7),
-
- /* Interrupt Enable 3 (Address 0x000c)*/
- MAX98927_Interrupt_Enable_3 = 0x000c,
- MAX98927_Interrupt_Enable_3_PWRUP_FAIL_EN = (0x1 << 0),
- MAX98927_Interrupt_Enable_3_AUTH_DONE_EN = (0x1 << 1),
- MAX98927_Interrupt_Enable_3_SPK_OVC_EN = (0x1 << 2),
- MAX98927_Interrupt_Enable_3_BST_UVLO_EN = (0x1 << 3),
-
- /* Interrupt Flag Clear 1 (Address 0x000d)*/
- MAX98927_Interrupt_Flag_Clear_1 = 0x000d,
- MAX98927_Interrupt_Flag_Clear_1_BDE_ACTIVE_END_CLR = (0x1 << 0),
- MAX98927_Interrupt_Flag_Clear_1_BDE_ACTIVE_BGN_CLR = (0x1 << 1),
- MAX98927_Interrupt_Flag_Clear_1_BDE_LEVEL_CHANGE_CLR = (0x1 << 2),
- MAX98927_Interrupt_Flag_Clear_1_BDE_L8_CLR = (0x1 << 3),
- MAX98927_Interrupt_Flag_Clear_1_THERMWARN_END_CLR = (0x1 << 4),
- MAX98927_Interrupt_Flag_Clear_1_THERMWARN_START_CLR = (0x1 << 5),
- MAX98927_Interrupt_Flag_Clear_1_THERMSHDN_END_CLR = (0x1 << 6),
- MAX98927_Interrupt_Flag_Clear_1_THERMSHDN_START_CLR = (0x1 << 7),
-
- /* Interrupt Flag Clear 2 (Address 0x000e)*/
- MAX98927_Interrupt_Flag_Clear_2 = 0x000e,
- MAX98927_Interrupt_Flag_Clear_2_WATCHDOGWARN_CLR = (0x1 << 0),
- MAX98927_Interrupt_Flag_Clear_2_WATCHDOGFAIL_CLR = (0x1 << 1),
- MAX98927_Interrupt_Flag_Clear_2_BOOSTCURRLIM_CLR = (0x1 << 2),
- MAX98927_Interrupt_Flag_Clear_2_CLKSTOP_CLR = (0x1 << 3),
- MAX98927_Interrupt_Flag_Clear_2_CLKSTART_CLR = (0x1 << 4),
- MAX98927_Interrupt_Flag_Clear_2_MEASADC_END_CLR = (0x1 << 5),
- MAX98927_Interrupt_Flag_Clear_2_PWRDN_DONE_CLR = (0x1 << 6),
- MAX98927_Interrupt_Flag_Clear_2_PWRUP_DONE_CLR = (0x1 << 7),
-
- /* Interrupt Flag Clear 3 (Address 0x000f)*/
- MAX98927_Interrupt_Flag_Clear_3 = 0x000f,
- MAX98927_Interrupt_Flag_Clear_3_PWRUP_FAIL_CLR = (0x1 << 0),
- MAX98927_Interrupt_Flag_Clear_3_AUTH_DONE_CLR = (0x1 << 1),
- MAX98927_Interrupt_Flag_Clear_3_SPK_OVC_CLR = (0x1 << 2),
- MAX98927_Interrupt_Flag_Clear_3_BST_UVLO_CLR = (0x1 << 3),
-
- /* IRQ Control (Address 0x0010)*/
- MAX98927_IRQ_Control = 0x0010,
- MAX98927_IRQ_Control_IRQ_EN = (0x1 << 0),
- MAX98927_IRQ_Control_IRQ_POL = (0x1 << 1),
- MAX98927_IRQ_Control_IRQ_MODE = (0x1 << 2),
-
- /* Clock monitor enable (Address 0x0011)*/
- MAX98927_Clock_monitor_enable = 0x0011,
- MAX98927_Clock_monitor_enable_CMON_ENA = (0x1 << 0),
- MAX98927_Clock_monitor_enable_CMON_AUTORESTART_ENA = (0x1 << 1),
-
- /* Watchdog Control (Address 0x0012)*/
- MAX98927_Watchdog_Control = 0x0012,
- MAX98927_Watchdog_Control_WDT_ENA = (0x1 << 0),
- MAX98927_Watchdog_Control_WDT_MODE = (0x1 << 1),
- MAX98927_Watchdog_Control_WDT_TO_SEL_Mask = (0x3 << 2),
- MAX98927_Watchdog_Control_WDT_TO_SEL_5 = (0x0 << 2),
- MAX98927_Watchdog_Control_WDT_TO_SEL_10 = (0x1 << 2),
- MAX98927_Watchdog_Control_WDT_TO_SEL_35 = (0x2 << 2),
- MAX98927_Watchdog_Control_WDT_TO_SEL_50 = (0x3 << 2),
- MAX98927_Watchdog_Control_WDT_HW_SOURCE = (0x1 << 4),
-
- /* Watchdog SW Reset (Address 0x0013)*/
- MAX98927_Watchdog_SW_Reset = 0x0013,
- MAX98927_Watchdog_SW_Reset_WDT_SW_RST_Mask = (0xff << 0),
-
- /* Meas ADC Thermal Warning Threshhold (Address 0x0014)*/
- MAX98927_Meas_ADC_TW_Threshhold = 0x0014,
- MAX98927_Meas_ADC_TW_Threshhold_MEAS_ADC_WARN_THRESH_Mask
- = (0xff << 0),
-
- /* Meas ADC Thermal Shutdown Threshhold (Address 0x0015)*/
- MAX98927_Meas_ADC_TS_Threshhold = 0x0015,
- MAX98927_Meas_ADC_TS_Threshhold_MEAS_ADC_SHDN_THRESH_Mask
- = (0xff << 0),
-
- /* Meas ADC Thermal Hysteresis (Address 0x0016)*/
- MAX98927_Meas_ADC_Thermal_Hysteresis = 0x0016,
- MAX98927_Meas_ADC_TH_MEAS_ADC_THERM_HYST_Mask = (0x1f << 0),
-
- /* Pin Config (Address 0x0017)*/
- MAX98927_Pin_Config = 0x0017,
- MAX98927_Pin_Config_DOUT_DRV_Mask = (0x3 << 0),
- MAX98927_Pin_Config_DOUT_DRV_01 = (0x0 << 0),
- MAX98927_Pin_Config_DOUT_DRV_11 = (0x2 << 0),
- MAX98927_Pin_Config_BCLK_DRV_Mask = (0x3 << 2),
- MAX98927_Pin_Config_BCLK_DRV_01 = (0x0 << 2),
- MAX98927_Pin_Config_BCLK_DRV_11 = (0x2 << 2),
- MAX98927_Pin_Config_LRCLK_DRV_Mask = (0x3 << 4),
- MAX98927_Pin_Config_LRCLK_DRV_01 = (0x0 << 4),
- MAX98927_Pin_Config_LRCLK_DRV_11 = (0x2 << 4),
- MAX98927_Pin_Config_ICC_DRV_Mask = (0x3 << 6),
- MAX98927_Pin_Config_ICC_DRV_01 = (0x0 << 6),
- MAX98927_Pin_Config_ICC_DRV_11 = (0x2 << 6),
-
- /* PCM Rx Enables A (Address 0x0018)*/
- MAX98927_PCM_Rx_Enables_A = 0x0018,
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH0_EN = (0x1 << 0),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH1_EN = (0x1 << 1),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH2_EN = (0x1 << 2),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH3_EN = (0x1 << 3),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH4_EN = (0x1 << 4),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH5_EN = (0x1 << 5),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH6_EN = (0x1 << 6),
- MAX98927_PCM_Rx_Enables_A_PCM_RX_CH7_EN = (0x1 << 7),
-
- /* PCM Rx Enables B (Address 0x0019)*/
- MAX98927_PCM_Rx_Enables_B = 0x0019,
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH8_EN = (0x1 << 0),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH9_EN = (0x1 << 1),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH10_EN = (0x1 << 2),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH11_EN = (0x1 << 3),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH12_EN = (0x1 << 4),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH13_EN = (0x1 << 5),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH14_EN = (0x1 << 6),
- MAX98927_PCM_Rx_Enables_B_PCM_RX_CH15_EN = (0x1 << 7),
-
- /* PCM Tx Enables A (Address 0x001a)*/
- MAX98927_PCM_Tx_Enables_A = 0x001a,
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH0_EN = (0x1 << 0),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH1_EN = (0x1 << 1),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH2_EN = (0x1 << 2),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH3_EN = (0x1 << 3),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH4_EN = (0x1 << 4),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH5_EN = (0x1 << 5),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH6_EN = (0x1 << 6),
- MAX98927_PCM_Tx_Enables_A_PCM_TX_CH7_EN = (0x1 << 7),
-
- /* PCM Tx Enables B (Address 0x001b)*/
- MAX98927_PCM_Tx_Enables_B = 0x001b,
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH8_EN = (0x1 << 0),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH9_EN = (0x1 << 1),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH10_EN = (0x1 << 2),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH11_EN = (0x1 << 3),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH12_EN = (0x1 << 4),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH13_EN = (0x1 << 5),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH14_EN = (0x1 << 6),
- MAX98927_PCM_Tx_Enables_B_PCM_TX_CH15_EN = (0x1 << 7),
-
- /* PCM Tx HiZ Control A (Address 0x001c)*/
- MAX98927_PCM_Tx_HiZ_Control_A = 0x001c,
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH0_HIZ = (0x1 << 0),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH1_HIZ = (0x1 << 1),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH2_HIZ = (0x1 << 2),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH3_HIZ = (0x1 << 3),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH4_HIZ = (0x1 << 4),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH5_HIZ = (0x1 << 5),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH6_HIZ = (0x1 << 6),
- MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH7_HIZ = (0x1 << 7),
-
- /* PCM Tx HiZ Control B (Address 0x001d)*/
- MAX98927_PCM_Tx_HiZ_Control_B = 0x001d,
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH8_HIZ = (0x1 << 0),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH9_HIZ = (0x1 << 1),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH10_HIZ = (0x1 << 2),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH11_HIZ = (0x1 << 3),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH12_HIZ = (0x1 << 4),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH13_HIZ = (0x1 << 5),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH14_HIZ = (0x1 << 6),
- MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH15_HIZ = (0x1 << 7),
-
- /* PCM Tx Channel Sources A (Address 0x001e)*/
- MAX98927_PCM_Tx_Channel_Sources_A = 0x001e,
- MAX98927_PCM_Tx_Channel_Sources_A_PCM_IVADC_V_DEST_Mask = (0xf << 0),
- MAX98927_PCM_Tx_Channel_Sources_A_PCM_IVADC_I_DEST_Mask = (0xf << 4),
-
- /* PCM Tx Channel Sources B (Address 0x001f)*/
- MAX98927_PCM_Tx_Channel_Sources_B = 0x001f,
- MAX98927_PCM_Tx_Channel_Sources_B_PCM_AMP_DSP_DEST_Mask = (0xf << 0),
- MAX98927_PCM_Tx_Channel_Src_INTERLEAVE_Mask = (0x1 << 5),
-
- /* PCM Mode Config (Address 0x0020)*/
- MAX98927_PCM_Mode_Config = 0x0020,
- MAX98927_PCM_Mode_Config_PCM_TX_EXTRA_HIZ = (0x1 << 0),
- MAX98927_PCM_Mode_Config_PCM_CHANSEL = (0x1 << 1),
- MAX98927_PCM_Mode_Config_PCM_BCLKEDGE = (0x1 << 2),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_Mask = (0x7 << 3),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_I2S = (0x0 << 3),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_LEFT = (0x1 << 3),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_TDM_0 = (0x3 << 3),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_TDM_1 = (0x4 << 3),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_TDM_2 = (0x5 << 3),
- MAX98927_PCM_Mode_Config_PCM_FORMAT_ = (0x6 << 3),
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_Mask = (0x3 << 6),
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_16 = (0x1 << 6),
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_24 = (0x2 << 6),
- MAX98927_PCM_Mode_Config_PCM_CHANSZ_32 = (0x3 << 6),
-
- /* PCM Master Mode (Address 0x0021)*/
- MAX98927_PCM_Master_Mode = 0x0021,
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask = (0x3 << 0),
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_SLAVE = (0x0 << 0),
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_MASTER = (0x3 << 0),
- MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_HYBRID = (0x1 << 0),
- MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_Mask = (0xf << 2),
- MAX98927_PCM_Master_Mode_PCM_CLK_SOURCE = (0x1 << 6),
-
- /* PCM Clock setup (Address 0x0022)*/
- MAX98927_PCM_Clock_setup = 0x0022,
- MAX98927_PCM_Clock_setup_PCM_BSEL_Mask = (0xf << 0),
- MAX98927_PCM_Clock_setup_PCM_MSEL_Mask = (0xf << 4),
-
- /* PCM Sample rate setup 1 (Address 0x0023)*/
- MAX98927_PCM_Sample_rate_setup_1 = 0x0023,
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_Mask = (0xf << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_8000 = (0x0 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_11025 = (0x1 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_12000 = (0x2 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_16000 = (0x3 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_22050 = (0x4 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_24000 = (0x5 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_32000 = (0x6 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_44100 = (0x7 << 0),
- MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_48000 = (0x8 << 0),
-
- /* PCM Sample rate setup 1 (Address 0x0024)*/
- MAX98927_PCM_Sample_rate_setup_2 = 0x0024,
- MAX98927_PCM_Sample_rate_setup_2_IVADC_SR_Mask = (0xf << 0),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_Mask = (0xf << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0001 = (0x0 << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0011 = (0x2 << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0101 = (0x4 << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0111 = (0x6 << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_1001 = (0x8 << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_1011 = (0xa << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_1101 = (0xc << 4),
- MAX98927_PCM_Sample_rate_setup_2_SPK_SR_ = (0xf << 4),
-
- /* PCM to speaker monomix A (Address 0x0025)*/
- MAX98927_PCM_to_speaker_monomix_A = 0x0025,
- MAX98927_PCM_to_spkmonomix_A_DMONOMIX_CH0_SOURCE_Mask = (0xf << 0),
- MAX98927_PCM_to_spkmonomix_A_DMONOMIX_CFG_Mask = (0x3 << 6),
- MAX98927_PCM_to_spkmonomix_A_DMONOMIX_CFG_1 = (0x0 << 6),
- MAX98927_PCM_to_spkmonomix_A_DMONOMIX_CFG_3 = (0x0 << 6),
-
- /* PCM to speaker monomix B (Address 0x0026)*/
- MAX98927_PCM_to_spkmonomix_B = 0x0026,
- MAX98927_PCM_to_spkmonomix_B_DMONOMIX_CH1_SOURCE_Mask = (0xf << 0),
-
- /* ICC RX Enables A (Address 0x0027)*/
- MAX98927_ICC_RX_Enables_A = 0x0027,
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH0_EN = (0x1 << 0),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH1_EN = (0x1 << 1),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH2_EN = (0x1 << 2),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH3_EN = (0x1 << 3),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH4_EN = (0x1 << 4),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH5_EN = (0x1 << 5),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH6_EN = (0x1 << 6),
- MAX98927_ICC_RX_Enables_A_ICC_RX_CH7_EN = (0x1 << 7),
-
- /* ICC RX Enables B (Address 0x0028)*/
- MAX98927_ICC_RX_Enables_B = 0x0028,
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH8_EN = (0x1 << 0),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH9_EN = (0x1 << 1),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH10_EN = (0x1 << 2),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH11_EN = (0x1 << 3),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH12_EN = (0x1 << 4),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH13_EN = (0x1 << 5),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH14_EN = (0x1 << 6),
- MAX98927_ICC_RX_Enables_B_ICC_RX_CH15_EN = (0x1 << 7),
-
- /* ICC TX Enables A (Address 0x002b)*/
- MAX98927_ICC_TX_Enables_A = 0x002b,
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH0_EN = (0x1 << 0),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH1_EN = (0x1 << 1),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH2_EN = (0x1 << 2),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH3_EN = (0x1 << 3),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH4_EN = (0x1 << 4),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH5_EN = (0x1 << 5),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH6_EN = (0x1 << 6),
- MAX98927_ICC_TX_Enables_A_ICC_TX_CH7_EN = (0x1 << 7),
-
- /* ICC TX Enables B (Address 0x002c)*/
- MAX98927_ICC_TX_Enables_B = 0x002c,
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH8_EN = (0x1 << 0),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH9_EN = (0x1 << 1),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH10_EN = (0x1 << 2),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH11_EN = (0x1 << 3),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH12_EN = (0x1 << 4),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH13_EN = (0x1 << 5),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH14_EN = (0x1 << 6),
- MAX98927_ICC_TX_Enables_B_ICC_TX_CH15_EN = (0x1 << 7),
-
- /* ICC Data Order Select (Address 0x002d)*/
- MAX98927_ICC_Data_Order_Select = 0x002d,
- MAX98927_ICC_Data_Order_Select_ICC_DRIVE_MODE = (0x1 << 3),
-
- /* ICC HiZ Manual Mode (Address 0x002e)*/
- MAX98927_ICC_HiZ_Manual_Mode = 0x002e,
- MAX98927_ICC_HiZ_Manual_Mode_ICC_TX_HIZ_MANUAL = (0x1 << 0),
- MAX98927_ICC_HiZ_Manual_Mode_ICC_TX_EXTRA_HIZ = (0x1 << 1),
-
- /* ICC TX HiZ Enables A (Address 0x002f)*/
- MAX98927_ICC_TX_HiZ_Enables_A = 0x002f,
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH0_HIZ = (0x1 << 0),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH1_HIZ = (0x1 << 1),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH2_HIZ = (0x1 << 2),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH3_HIZ = (0x1 << 3),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH4_HIZ = (0x1 << 4),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH5_HIZ = (0x1 << 5),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH6_HIZ = (0x1 << 6),
- MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH7_HIZ = (0x1 << 7),
-
- /* ICC TX HiZ Enables B (Address 0x0030)*/
- MAX98927_ICC_TX_HiZ_Enables_B = 0x0030,
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH8_HIZ = (0x1 << 0),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH9_HIZ = (0x1 << 1),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH10_HIZ = (0x1 << 2),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH11_HIZ = (0x1 << 3),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH12_HIZ = (0x1 << 4),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH13_HIZ = (0x1 << 5),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH14_HIZ = (0x1 << 6),
- MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH15_HIZ = (0x1 << 7),
-
- /* ICC Link Enables (Address 0x0031)*/
- MAX98927_ICC_Link_Enables = 0x0031,
- MAX98927_ICC_Link_Enables_ICC_LINK_EN = (0x1 << 1),
-
- /* PDM Tx Enables (Address 0x0032)*/
- MAX98927_PDM_Tx_Enables = 0x0032,
- MAX98927_PDM_Tx_Enables_PDM_TX_EN = (0x1 << 0),
- MAX98927_PDM_Tx_Enables_PDM_TX_CLK_DIV2 = (0x1 << 1),
-
- /* PDM Tx HiZ Control (Address 0x0033)*/
- MAX98927_PDM_Tx_HiZ_Control = 0x0033,
- MAX98927_PDM_Tx_HiZ_Control_PDM_TX_HIZ = (0x1 << 0),
-
- /* PDM Tx Control (Address 0x0034)*/
- MAX98927_PDM_Tx_Control = 0x0034,
- MAX98927_PDM_Tx_Control_PDM_TX_CH0_SOURCE = (0x1 << 0),
- MAX98927_PDM_Tx_Control_PDM_TX_CH1_SOURCE = (0x1 << 1),
-
- /* PDM Rx Enable (Address 0x0034)*/
- MAX98927_PDM_Rx_Enable = 0x0035,
- MAX98927_PDM_Rx_Enable_PDM_RX_EN = (0x1 << 0),
- MAX98927_PDM_Rx_Enable_PDM_DSP_EN = (0x1 << 1),
- MAX98927_PDM_Rx_Enable_PDM_DITH_EN = (0x1 << 2),
- MAX98927_PDM_Rx_Enable_PDM_RX_CH_SEL = (0x1 << 3),
- MAX98927_PDM_Rx_Enable_PDM_FIFO_RDY_LVL_Mask = (0xf << 4),
-
- /* AMP volume control (Address 0x0036)*/
- MAX98927_AMP_volume_control = 0x0036,
- MAX98927_AMP_volume_control_AMP_VOL_Mask = (0x7f << 0),
- MAX98927_AMP_volume_control_AMP_VOL_SEL = (0x1 << 7),
-
- /* AMP DSP Config (Address 0x0037)*/
- MAX98927_AMP_DSP_Config = 0x0037,
- MAX98927_AMP_DSP_Config_AMP_DCBLK_EN = (0x1 << 0),
- MAX98927_AMP_DSP_Config_AMP_DITH_EN = (0x1 << 1),
- MAX98927_AMP_DSP_Config_DAC_HALF_REF_CURRENT = (0x1 << 2),
- MAX98927_AMP_DSP_Config_DAC_DOUBLE_RFB = (0x1 << 3),
- MAX98927_AMP_DSP_Config_AMP_VOL_RMP_BYPASS = (0x1 << 4),
- MAX98927_AMP_DSP_Config_DAC_INVERT = (0x1 << 5),
-
- /* Tone Generator and DC Config (Address 0x0038)*/
- MAX98927_Tone_Generator_and_DC_Config = 0x0038,
- MAX98927_Tone_Generator_and_DC_Config_TONE_CONFIG_Mask = (0xf << 0),
-
- /* DRE Control (Address 0x0039)*/
- MAX98927_DRE_Control = 0x0039,
- MAX98927_DRE_Control_DRE_EN = (0x1 << 0),
-
- /* AMP enables (Address 0x003a)*/
- MAX98927_AMP_enables = 0x003a,
- MAX98927_AMP_enables_SPK_EN = (0x1 << 0),
-
- /* Speaker source select (Address 0x003b)*/
- MAX98927_Speaker_source_select = 0x003b,
- MAX98927_Speaker_source_select_SPK_SOURCE_Mask = (0x3 << 0),
- MAX98927_Speaker_source_select_SPK_SOURCE_01 = (0x0 << 0),
- MAX98927_Speaker_source_select_SPK_SOURCE_11 = (0x2 << 0),
-
- /* Speaker Gain (Address 0x003c)*/
- MAX98927_Speaker_Gain = 0x003c,
- MAX98927_Speaker_Gain_SPK_PCM_GAIN_Mask = (0x7 << 0),
- MAX98927_Speaker_Gain_SPK_PCM_GAIN_001 = (0x0 << 0),
- MAX98927_Speaker_Gain_SPK_PCM_GAIN_011 = (0x2 << 0),
- MAX98927_Speaker_Gain_SPK_PCM_GAIN_101 = (0x4 << 0),
- MAX98927_Speaker_Gain_SPK_PCM_GAIN_111 = (0x6 << 0),
- MAX98927_Speaker_Gain_SPK_PDM_GAIN_Mask = (0x7 << 4),
- MAX98927_Speaker_Gain_SPK_PDM_GAIN_001 = (0x0 << 4),
- MAX98927_Speaker_Gain_SPK_PDM_GAIN_011 = (0x2 << 4),
- MAX98927_Speaker_Gain_SPK_PDM_GAIN_101 = (0x4 << 4),
- MAX98927_Speaker_Gain_SPK_PDM_GAIN_111 = (0x6 << 4),
-
- /* SSM Configuration (Address 0x003d)*/
- MAX98927_SSM_Configuration = 0x003d,
- MAX98927_SSM_Configuration_SSM_MOD_INDEX_Mask = (0x7 << 0),
- MAX98927_SSM_Configuration_SSM_MOD_INDEX_001 = (0x0 << 0),
- MAX98927_SSM_Configuration_SSM_MOD_INDEX_011 = (0x2 << 0),
- MAX98927_SSM_Configuration_SSM_MOD_INDEX_101 = (0x4 << 0),
- MAX98927_SSM_Configuration_SSM_MOD_INDEX_ = (0x6 << 0),
- MAX98927_SSM_Configuration_SPK_FSW_SEL = (0x1 << 3),
- MAX98927_SSM_Configuration_SSM_ENA = (0x1 << 7),
-
- /* Measurement enables (Address 0x003e)*/
- MAX98927_Measurement_enables = 0x003e,
- MAX98927_Measurement_enables_IVADC_V_EN = (0x1 << 0),
- MAX98927_Measurement_enables_IVADC_I_EN = (0x1 << 1),
-
- /* Measurement DSP Config (Address 0x003f)*/
- MAX98927_Measurement_DSP_Config = 0x003f,
- MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_EN = (0x1 << 0),
- MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_EN = (0x1 << 1),
- MAX98927_Measurement_DSP_Config_MEAS_DITH_EN = (0x1 << 2),
- MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_Mask = (0x3 << 4),
- MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_01 = (0x0 << 4),
- MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_11 = (0x2 << 4),
- MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_Mask = (0x3 << 6),
- MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_01 = (0x0 << 6),
- MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_11 = (0x2 << 6),
-
- /* Boost Control 0 (Address 0x0040)*/
- MAX98927_Boost_Control_0 = 0x0040,
- MAX98927_Boost_Control_0_BST_VOUT_Mask = (0x1f << 0),
- MAX98927_Boost_Control_0_EXT_PVDD_EN = (0x1 << 7),
-
- /* Boost Control 3 (Address 0x0041)*/
- MAX98927_Boost_Control_3 = 0x0041,
- MAX98927_Boost_Control_3_BST_SKIPLOAD_Mask = (0x3 << 0),
- MAX98927_Boost_Control_3_BST_SKIPLOAD_01 = (0x0 << 0),
- MAX98927_Boost_Control_3_BST_SKIPLOAD_11 = (0x2 << 0),
- MAX98927_Boost_Control_3_BST_PHASE_Mask = (0x7 << 2),
- MAX98927_Boost_Control_3_BST_PHASE_001 = (0x0 << 2),
- MAX98927_Boost_Control_3_BST_PHASE_011 = (0x2 << 2),
- MAX98927_Boost_Control_3_BST_PHASE_ = (0x1 << 2),
- MAX98927_Boost_Control_3_BST_SLOWSTART = (0x1 << 5),
-
- /* Boost Control 1 (Address 0x0042)*/
- MAX98927_Boost_Control_1 = 0x0042,
- /*#BYHAND width >= 5:*/
- MAX98927_Boost_Control_1_BST_ILIM_Mask = (0x3f << 0),
-
- /* Meas ADC Config (Address 0x0043)*/
- MAX98927_Meas_ADC_Config = 0x0043,
- MAX98927_Meas_ADC_Config_MEAS_ADC_CH0_EN = (0x1 << 0),
- MAX98927_Meas_ADC_Config_MEAS_ADC_CH1_EN = (0x1 << 1),
- MAX98927_Meas_ADC_Config_MEAS_ADC_CH2_EN = (0x1 << 2),
-
- /* Meas ADC Base Divide MSByte (Address 0x0044)*/
- MAX98927_Meas_ADC_Base_Divide_MSByte = 0x0044,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Base_Divide_MSByte_MEAS_ADC_BASE_DIV_Mask
- = (0xff << 0),
-
- /* Meas ADC Base Divide LSByte (Address 0x0045)*/
- MAX98927_Meas_ADC_Base_Divide_LSByte = 0x0045,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Base_Divide_LSByte_MEAS_ADC_BASE_DIV_Mask
- = (0xff << 0),
-
- /* Meas ADC Chan 0 Divide (Address 0x0046)*/
- MAX98927_Meas_ADC_Chan_0_Divide = 0x0046,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Chan_0_Divide_MEAS_ADC_CH0_DIV_Mask = (0xff << 0),
-
- /* Meas ADC Chan 1 Divide (Address 0x0047)*/
- MAX98927_Meas_ADC_Chan_1_Divide = 0x0047,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Chan_1_Divide_MEAS_ADC_CH1_DIV_Mask = (0xff << 0),
-
- /* Meas ADC Chan 2 Divide (Address 0x0048)*/
- MAX98927_Meas_ADC_Chan_2_Divide = 0x0048,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Chan_2_Divide_MEAS_ADC_CH2_DIV_Mask = (0xff << 0),
-
- /* Meas ADC Chan 0 Filt Config (Address 0x0049)*/
- MAX98927_Meas_ADC_Chan_0_Filt_Config = 0x0049,
- MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_Mask
- = (0x7 << 0),
- MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_001
- = (0x0 << 0),
- MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_011
- = (0x2 << 0),
- MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_101
- = (0x4 << 0),
- MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_EN
- = (0x1 << 3),
-
- /* Meas ADC Chan 1 Filt Config (Address 0x004a)*/
- MAX98927_Meas_ADC_Chan_1_Filt_Config = 0x004a,
- MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_Mask
- = (0x7 << 0),
- MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_001
- = (0x0 << 0),
- MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_011
- = (0x2 << 0),
- MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_101
- = (0x4 << 0),
- MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_EN
- = (0x1 << 3),
-
- /* Meas ADC Chan 2 Filt Config (Address 0x004b)*/
- MAX98927_Meas_ADC_Chan_2_Filt_Config = 0x004b,
- MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_Mask
- = (0x7 << 0),
- MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_001
- = (0x0 << 0),
- MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_011
- = (0x2 << 0),
- MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_101
- = (0x4 << 0),
- MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_EN
- = (0x1 << 3),
-
- /* Meas ADC Chan 0 Readback (Address 0x004c)*/
- MAX98927_Meas_ADC_Chan_0_Readback = 0x004c,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Chan_0_Readback_MEAS_ADC_CH0_DATA_Mask
- = (0xff << 0),
-
- /* Meas ADC Chan 1 Readback (Address 0x004d)*/
- MAX98927_Meas_ADC_Chan_1_Readback = 0x004d,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Chan_1_Readback_MEAS_ADC_CH1_DATA_Mask
- = (0xff << 0),
-
- /* Meas ADC Chan 2 Readback (Address 0x004e)*/
- MAX98927_Meas_ADC_Chan_2_Readback = 0x004e,
- /*#BYHAND width >= 5:*/
- MAX98927_Meas_ADC_Chan_2_Readback_MEAS_ADC_CH2_DATA_Mask
- = (0xff << 0),
-
- /* Brownout status (Address 0x0051)*/
- MAX98927_Brownout_status = 0x0051,
- MAX98927_Brownout_status_BDE_STATE_Mask = (0xf << 0),
-
- /* Brownout enables (Address 0x0052)*/
- MAX98927_Brownout_enables = 0x0052,
- MAX98927_Brownout_enables_BDE_EN = (0x1 << 0),
- MAX98927_Brownout_enables_BDE_AMP_EN = (0x1 << 1),
- MAX98927_Brownout_enables_AMP_DSP_EN = (0x1 << 2),
-
- /* Brownout level infinite hold (Address 0x0053)*/
- MAX98927_Brownout_level_infinite_hold = 0x0053,
- MAX98927_Brownout_level_infinite_hold_BDE_L8_INF_HLD = (0x1 << 1),
-
- /* Brownout level infinite hold clear (Address 0x0054)*/
- MAX98927_Brownout_level_infinite_hold_clear = 0x0054,
- MAX98927_Brownout_level_infinite_hold_clear_BDE_L8_HLD_RLS
- = (0x1 << 1),
-
- /* Brownout level hold (Address 0x0055)*/
- MAX98927_Brownout_level_hold = 0x0055,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout_level_hold_BDE_HLD_Mask = (0xff << 0),
-
- /* Brownout level 1 threshold (Address 0x0056)*/
- MAX98927_Brownout__level_1_threshold = 0x0056,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_1_threshold_BDE_L1_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 2 threshold (Address 0x0057)*/
- MAX98927_Brownout__level_2_threshold = 0x0057,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_2_threshold_BDE_L2_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 3 threshold (Address 0x0058)*/
- MAX98927_Brownout__level_3_threshold = 0x0058,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_3_threshold_BDE_L3_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 4 threshold (Address 0x0059)*/
- MAX98927_Brownout__level_4_threshold = 0x0059,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_4_threshold_BDE_L4_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 5 threshold (Address 0x005a)*/
- MAX98927_Brownout__level_5_threshold = 0x005a,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_5_threshold_BDE_L5_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 6 threshold (Address 0x005b)*/
- MAX98927_Brownout__level_6_threshold = 0x005b,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_6_threshold_BDE_L6_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 7 threshold (Address 0x005c)*/
- MAX98927_Brownout__level_7_threshold = 0x005c,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_7_threshold_BDE_L7_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout level 8 threshold (Address 0x005d)*/
- MAX98927_Brownout__level_8_threshold = 0x005d,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_8_threshold_BDE_L8_VTHRESH_Mask = (0xff << 0),
-
- /* Brownout threshold hysterysis (Address 0x005e)*/
- MAX98927_Brownout_threshold_hysterysis = 0x005e,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout_threshold_hysterysis_BDE_VTHRESH_HYST_Mask
- = (0xff << 0),
- /* Brownout AMP limiter attack/release (Address 0x005f)*/
- MAX98927_Brownout_AMP_limiter_attack_release = 0x005f,
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_Mask
- = (0xf << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0001
- = (0x0 << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0011
- = (0x2 << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0101
- = (0x4 << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0111
- = (0x6 << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1001
- = (0x8 << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1011
- = (0xa << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1101
- = (0xc << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1111
- = (0xe << 0),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_Mask
- = (0xf << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0001
- = (0x0 << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0011
- = (0x2 << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0101
- = (0x4 << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0111
- = (0x6 << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1001
- = (0x8 << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1011
- = (0xa << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1101
- = (0xc << 4),
- MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1111
- = (0xe << 4),
-
- /* Brownout AMP gain attack/release (Address 0x0060)*/
- MAX98927_Brownout_AMP_gain_attack_release = 0x0060,
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_Mask
- = (0xf << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0001
- = (0x0 << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0011
- = (0x2 << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0101
- = (0x4 << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0111
- = (0x6 << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1001
- = (0x8 << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1011
- = (0xa << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1101
- = (0xc << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1111
- = (0xe << 0),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_Mask
- = (0xf << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0001
- = (0x0 << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0011
- = (0x2 << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0101
- = (0x4 << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0111
- = (0x6 << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1001
- = (0x8 << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1011
- = (0xa << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1101
- = (0xc << 4),
- MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1111
- = (0xe << 4),
-
- /* Brownout AMP1 clip mode (Address 0x0061)*/
- MAX98927_Brownout_AMP1_clip_mode = 0x0061,
- MAX98927_Brownout_AMP1_clip_mode_AMP_CLIP_MODE = (0x1 << 0),
-
- /* Brownout level 1 current limit (Address 0x0062)*/
- MAX98927_Brownout__level_1_current_limit = 0x0062,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_1_current_limit_BDE_L1_ILIM_Mask
- = (0x3f << 0),
-
- /* Brownout level 1 amp 1 control 1 (Address 0x0063)*/
- MAX98927_Brownout__level_1_amp_1_control_1 = 0x0063,
- MAX98927_Brownout__level_1_amp_1_control_1_BDE_L1_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 1 amp 1 control 2 (Address 0x0064)*/
- MAX98927_Brownout__level_1_amp_1_control_2 = 0x0064,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_1_amp_1_control_2_BDE_L1_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 1 amp 1 control 3 (Address 0x0065)*/
- MAX98927_Brownout__level_1_amp_1_control_3 = 0x0065,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_1_amp_1_control_3_BDE_L1_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 2 current limit (Address 0x0066)*/
- MAX98927_Brownout__level_2_current_limit = 0x0066,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_2_current_limit_BDE_L2_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 2 amp 1 control 1 (Address 0x0067)*/
- MAX98927_Brownout__level_2_amp_1_control_1 = 0x0067,
- MAX98927_Brownout__level_2_amp_1_control_1_BDE_L2_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 2 amp 1 control 2 (Address 0x0068)*/
- MAX98927_Brownout__level_2_amp_1_control_2 = 0x0068,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_2_amp_1_control_2_BDE_L2_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 2 amp 1 control 3 (Address 0x0069)*/
- MAX98927_Brownout__level_2_amp_1_control_3 = 0x0069,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_2_amp_1_control_3_BDE_L2_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 3 current limit (Address 0x006a)*/
- MAX98927_Brownout__level_3_current_limit = 0x006a,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_3_current_limit_BDE_L3_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 3 amp 1 control 1 (Address 0x006b)*/
- MAX98927_Brownout__level_3_amp_1_control_1 = 0x006b,
- MAX98927_Brownout__level_3_amp_1_control_1_BDE_L3_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 3 amp 1 control 2 (Address 0x006c)*/
- MAX98927_Brownout__level_3_amp_1_control_2 = 0x006c,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_3_amp_1_control_2_BDE_L3_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 3 amp 1 control 3 (Address 0x006d)*/
- MAX98927_Brownout__level_3_amp_1_control_3 = 0x006d,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_3_amp_1_control_3_BDE_L3_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 4 current limit (Address 0x006e)*/
- MAX98927_Brownout__level_4_current_limit = 0x006e,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_4_current_limit_BDE_L4_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 4 amp 1 control 1 (Address 0x006f)*/
- MAX98927_Brownout__level_4_amp_1_control_1 = 0x006f,
- MAX98927_Brownout__level_4_amp_1_control_1_BDE_L4_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 4 amp 1 control 2 (Address 0x0070)*/
- MAX98927_Brownout__level_4_amp_1_control_2 = 0x0070,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_4_amp_1_control_2_BDE_L4_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 4 amp 1 control 3 (Address 0x0071)*/
- MAX98927_Brownout__level_4_amp_1_control_3 = 0x0071,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_4_amp_1_control_3_BDE_L4_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 5 current limit (Address 0x0072)*/
- MAX98927_Brownout__level_5_current_limit = 0x0072,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_5_current_limit_BDE_L5_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 5 amp 1 control 1 (Address 0x0073)*/
- MAX98927_Brownout__level_5_amp_1_control_1 = 0x0073,
- MAX98927_Brownout__level_5_amp_1_control_1_BDE_L5_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 5 amp 1 control 2 (Address 0x0074)*/
- MAX98927_Brownout__level_5_amp_1_control_2 = 0x0074,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_5_amp_1_control_2_BDE_L5_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 5 amp 1 control 3 (Address 0x0075)*/
- MAX98927_Brownout__level_5_amp_1_control_3 = 0x0075,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_5_amp_1_control_3_BDE_L5_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 6 current limit (Address 0x0076)*/
- MAX98927_Brownout__level_6_current_limit = 0x0076,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_6_current_limit_BDE_L6_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 6 amp 1 control 1 (Address 0x0077)*/
- MAX98927_Brownout__level_6_amp_1_control_1 = 0x0077,
- MAX98927_Brownout__level_6_amp_1_control_1_BDE_L6_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 6 amp 1 control 2 (Address 0x0078)*/
- MAX98927_Brownout__level_6_amp_1_control_2 = 0x0078,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_6_amp_1_control_2_BDE_L6_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 6 amp 1 control 3 (Address 0x0079)*/
- MAX98927_Brownout__level_6_amp_1_control_3 = 0x0079,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_6_amp_1_control_3_BDE_L6_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 7 current limit (Address 0x007a)*/
- MAX98927_Brownout__level_7_current_limit = 0x007a,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_7_current_limit_BDE_L7_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 7 amp 1 control 1 (Address 0x007b)*/
- MAX98927_Brownout__level_7_amp_1_control_1 = 0x007b,
- MAX98927_Brownout__level_7_amp_1_control_1_BDE_L7_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 7 amp 1 control 2 (Address 0x007c)*/
- MAX98927_Brownout__level_7_amp_1_control_2 = 0x007c,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_7_amp_1_control_2_BDE_L7_AMP1_CLIP_Mask
- = (0x3f << 0),
-
- /* Brownout level 7 amp 1 control 3 (Address 0x007d)*/
- MAX98927_Brownout__level_7_amp_1_control_3 = 0x007d,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_7_amp_1_control_3_BDE_L7_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Brownout level 8 current limit (Address 0x007e)*/
- MAX98927_Brownout__level_8_current_limit = 0x007e,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_8_current_limit_BDE_L8_ILIM_Mask = (0x3f << 0),
-
- /* Brownout level 8 amp 1 control 1 (Address 0x007f)*/
- MAX98927_Brownout__level_8_amp_1_control_1 = 0x007f,
- MAX98927_Brownout__level_8_amp_1_control_1_BDE_L8_AMP1_LIM_Mask
- = (0xf << 0),
-
- /* Brownout level 8 amp 1 control 2 (Address 0x0080)*/
- MAX98927_Brownout__lvl_8_amp_1_control_2 = 0x0080,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__lvl_8_amp_1_control_2_BDE_L8_AMP1_CLIP_Mask
- = (0x3f << 0),
- MAX98927_Brownout__lvl_8_amp_1_control_2_BDE_L8_AMP1_MUTE
- = (0x1 << 7),
-
- /* Brownout level 8 amp 1 control 3 (Address 0x0081)*/
- MAX98927_Brownout__level_8_amp_1_control_3 = 0x0081,
- /*#BYHAND width >= 5:*/
- MAX98927_Brownout__level_8_amp_1_control_3_BDE_L8_AMP1_GAIN_Mask
- = (0x3f << 0),
-
- /* Env Tracker Vout Headroom (Address 0x0082)*/
- MAX98927_Env_Tracker_Vout_Headroom = 0x0082,
- /*#BYHAND width >= 5:*/
- MAX98927_Env_Tracker_Vout_Head_ENV_TRACKER_BST_VOUT_HEADROOM_Mask
- = (0x1f << 0),
-
- /* Env Tracker Boost Vout Delay (Address 0x0083)*/
- MAX98927_Env_Tracker_Boost_Vout_Delay = 0x0083,
- /*#BYHAND width >= 5:*/
- MAX98927_Env_Tracker_Boost_V_Delay_ENV_TRACKER_BST_VOUT_DELAY_Mask
- = (0x1f << 0),
- MAX98927_Env_Tracker_Boost_Vout_Delay_ENV_TRACKER_BDE_MODE
- = (0x1 << 7),
-
- /* Env Tracker Release Rate (Address 0x0084)*/
- MAX98927_Env_Tracker_Release_Rate = 0x0084,
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_Mask
- = (0x7 << 0),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_001
- = (0x0 << 0),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_011
- = (0x2 << 0),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_101
- = (0x4 << 0),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_111
- = (0x6 << 0),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_PEAK_DET_LPF_BYP_EN
- = (0x1 << 3),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_SCALE_Mask
- = (0x3 << 4),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_SCALE_01
- = (0x0 << 4),
- MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_SCALE_11
- = (0x2 << 4),
-
- /* Env Tracker Hold Rate (Address 0x0085)*/
- MAX98927_Env_Tracker_Hold_Rate = 0x0085,
- MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_Mask
- = (0x7 << 0),
- MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_001
- = (0x0 << 0),
- MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_011
- = (0x2 << 0),
- MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_101
- = (0x4 << 0),
- MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_111
- = (0x6 << 0),
-
- /* Env Tracker Control (Address 0x0086)*/
- MAX98927_Env_Tracker_Control = 0x0086,
- MAX98927_Env_Tracker_Control_ENV_TRACKER_EN = (0x1 << 0),
-
- /* Env Tracker Boost Vout ReadBack (Address 0x0087)*/
- MAX98927_Env_Tracker__Boost_Vout_ReadBack = 0x0087,
- /*#BYHAND width >= 5:*/
- MAX98927_Env_Tracker__Boost_Vout_RB_ENV_TRACKER_BST_VOUT_RD_Mask
- = (0x1f << 0),
-
- /* Advanced Settings (Address 0x0089)*/
- MAX98927_Advanced_Settings = 0x0089,
- MAX98927_Advanced_Settings_DAC_HALF_FIR = (0x1 << 0),
- MAX98927_Advanced_Settings_PDM_MOD_SEL = (0x1 << 1),
- MAX98927_Advanced_Settings_ISOCH_EN = (0x1 << 2),
-
- /* DAC Test 1 (Address 0x009f)*/
- MAX98927_DAC_Test_1 = 0x009f,
- MAX98927_DAC_Test_1_DAC_PCM_TIMING = (0x1 << 0),
- MAX98927_DAC_Test_1_DAC_HALFI_AMP = (0x1 << 1),
- MAX98927_DAC_Test_1_DAC_LONG_HOLD = (0x1 << 3),
- MAX98927_DAC_Test_1_DAC_DISABLE_CHOP = (0x1 << 4),
- MAX98927_DAC_Test_1_DAC_TM = (0x1 << 5),
- MAX98927_DAC_Test_1_DAC_INVERT_DACCLK = (0x1 << 6),
-
- /* Authentication key 0 (Address 0x00ea)*/
- MAX98927_Authentication_key_0 = 0x00ea,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_key_0_AUTH_KEY_Mask = (0xff << 0),
-
- /* Authentication key 1 (Address 0x00eb)*/
- MAX98927_Authentication_key_1 = 0x00eb,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_key_1_AUTH_KEY_Mask = (0xff << 0),
-
- /* Authentication key 2 (Address 0x00ec)*/
- MAX98927_Authentication_key_2 = 0x00ec,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_key_2_AUTH_KEY_Mask = (0xff << 0),
-
- /* Authentication key 3 (Address 0x00ed)*/
- MAX98927_Authentication_key_3 = 0x00ed,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_key_3_AUTH_KEY_Mask = (0xff << 0),
-
- /* Authentication enable (Address 0x00ee)*/
- MAX98927_Authentication_enable = 0x00ee,
- MAX98927_Authentication_enable_AUTH_EN = (0x1 << 0),
-
- /* Authentication result 0 (Address 0x00ef)*/
- MAX98927_Authentication_result_0 = 0x00ef,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_0_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 1 (Address 0x00f0)*/
- MAX98927_Authentication_result_1 = 0x00f0,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_1_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 2 (Address 0x00f1)*/
- MAX98927_Authentication_result_2 = 0x00f1,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_2_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 3 (Address 0x00f2)*/
- MAX98927_Authentication_result_3 = 0x00f2,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_3_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 4 (Address 0x00f3)*/
- MAX98927_Authentication_result_4 = 0x00f3,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_4_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 5 (Address 0x00f4)*/
- MAX98927_Authentication_result_5 = 0x00f4,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_5_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 6 (Address 0x00f5)*/
- MAX98927_Authentication_result_6 = 0x00f5,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_6_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 7 (Address 0x00f6)*/
- MAX98927_Authentication_result_7 = 0x00f6,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_7_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 8 (Address 0x00f7)*/
- MAX98927_Authentication_result_8 = 0x00f7,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_8_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 9 (Address 0x00f8)*/
- MAX98927_Authentication_result_9 = 0x00f8,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_9_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 10 (Address 0x00f9)*/
- MAX98927_Authentication_result_10 = 0x00f9,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_10_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 11 (Address 0x00fa)*/
- MAX98927_Authentication_result_11 = 0x00fa,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_11_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 12 (Address 0x00fb)*/
- MAX98927_Authentication_result_12 = 0x00fb,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_12_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 13 (Address 0x00fc)*/
- MAX98927_Authentication_result_13 = 0x00fc,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_13_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 14 (Address 0x00fd)*/
- MAX98927_Authentication_result_14 = 0x00fd,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_14_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Authentication result 15 (Address 0x00fe)*/
- MAX98927_Authentication_result_15 = 0x00fe,
- /*#BYHAND width >= 5:*/
- MAX98927_Authentication_result_15_AUTH_RESULT_Mask = (0xff << 0),
-
- /* Global Enable (Address 0x00ff)*/
- MAX98927_Global_Enable = 0x00ff,
- MAX98927_Global_Enable_EN = (0x1 << 0),
- /* Software Reset (Address 0x0100)*/
- MAX98927_Software_Reset = 0x0100,
- MAX98927_Software_Reset_RST = (0x1 << 0),
-
- /* REV ID (Address 0x01ff)*/
- MAX98927_REV_ID = 0x01ff,
- /*#BYHAND width >= 5:*/
- MAX98927_REV_ID_REV_ID_Mask = (0xff << 0),
-} MAX98927Registers;
-
-struct max98927_reg_default {
- unsigned int ch;
- unsigned int reg;
- unsigned int def;
-};
struct max98927_priv {
struct regmap *regmap;
- struct regmap *sub_regmap;
struct snd_soc_codec *codec;
struct max98927_pdata *pdata;
- const uint32_t *regcfg;
- uint32_t regcfg_sz;
unsigned int spk_gain;
unsigned int sysclk;
unsigned int v_l_slot;
unsigned int i_l_slot;
- unsigned int v_r_slot;
- unsigned int i_r_slot;
bool interleave_mode;
unsigned int ch_size;
unsigned int rate;
unsigned int iface;
unsigned int master;
- unsigned int thres_hyste;
- unsigned int level5_hold;
- unsigned int level6_hold;
- unsigned int level7_hold;
- unsigned int level8_hold;
- unsigned int amp_limit;
- unsigned int amp_limit_rel;
- unsigned int amp1_level;
- unsigned int amp2_level;
- unsigned int amp3_level;
- unsigned int amp1_level8;
- unsigned int amp2_level8;
- unsigned int amp3_level8;
- unsigned int amp1_level7;
- unsigned int amp2_level7;
- unsigned int amp3_level7;
- unsigned int amp1_level6;
- unsigned int amp2_level6;
- unsigned int amp3_level6;
- unsigned int amp1_level5;
- unsigned int amp2_level5;
- unsigned int amp3_level5;
unsigned int digital_gain;
- unsigned int pdm_gain;
- unsigned int level_hold;
- struct i2c_client *sub_i2c;
- int sub_reg;
- int sub_bus;
};
-
-#define MAX98927_GLOBAL_SHIFT 0
-#define M98927_DAI_MSEL_SHIFT 4
-#define M98927_DAI_BSEL_SHIFT 0
-#define M98927_DAI_BSEL_32 (2 << M98927_DAI_BSEL_SHIFT)
-#define M98927_DAI_BSEL_48 (3 << M98927_DAI_BSEL_SHIFT)
-#define M98927_DAI_BSEL_64 (4 << M98927_DAI_BSEL_SHIFT)
-#define M98927_DAI_MSEL_32 (2 << M98927_DAI_MSEL_SHIFT)
-#define M98927_DAI_MSEL_48 (3 << M98927_DAI_MSEL_SHIFT)
-#define M98927_DAI_MSEL_64 (4 << M98927_DAI_MSEL_SHIFT)
-#define MAX98927_Speaker_Gain_Width 3
-#define MAX98927_SPK_RMP_EN_SHIFT 4
-#define MAX98927_PDM_GAIN_SHIFT 4
-#define MAX98927_pdm_Gain_Width 3
-#define MAX98927_AMP_VOL_WIDTH 7
-#define MAX98927_AMP_VOL_LOCATION_SHIFT 7
-#define MAX98927_PDM_Rx_Enable_PDM_CH_SHIFT 3
-#define MAX98927_PCM_to_speaker_monomix_A_SHIFT 6
-#define MAX98927_PCM_Sample_rate_setup_2_DIG_IF_SR_48000 (0x8 << 4)
-#define MAX98927_PCM_FORMAT_DSP_A (0x3 << 3)
-#define MAX98927_DRE_Control_DRE_SHIFT 0x1
-#define MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_SHIFT (2)
-#define MAX98927_Brownout_AMP_limiter_attack_release_shift 4
-#define MAX98927_BDE_DSP_SHIFT 2
-#define MAX98927_Speaker_Gain_SPK_PDM_GAIN_SHIFT (4)
-#define MAX98927_BDE_AMP_SHIFT (1)
-#define MAX98927_PCM_Tx_Ch_Sources_A_I_SHIFT (4)
#endif
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v2 0/3] increase TSCADC clock to 24MHz and fix ti,charge-delay to represent in nS
From: Mugunthan V N @ 2016-11-25 4:57 UTC (permalink / raw)
To: linux-input
Cc: Dmitry Torokhov, Jonathan Cameron, Rob Herring, Mark Rutland,
Lee Jones, Sekhar Nori, Vignesh R, devicetree, linux-omap,
linux-kernel
In-Reply-To: <20161110163515.27598-1-mugunthanvnm@ti.com>
Hi Dmitry Torokhov,
On Thursday 10 November 2016 10:05 PM, Mugunthan V N wrote:
> This patch series enables ADC to be clocked at 24MHz as the
> TI AM335x ADC driver has already adopted to use DMA to transfer
> ADC samples. Now ADC can generated upto 800K Samples per second
> with the patch [1] on AM335x BBB and AM437x GP EVM.
>
> when ADC ref clock is set at 24MHz, I am seeing some issue with
> touch screen pointer as the pointer jumps to random locations
> with free draw application. The issue is due to increase in ADC
> clock and charge delay for the touchscreen ADC line duration
> reduced.
>
> So the notation of ti,charge-delay in terms of ADC clock is
> wrong, it has to be represented in time and driver has to convert
> the charge delay time to ADC clocks based on what ADC clock
> frequency is set.
>
> Measured the performance with the iio_generic_buffer with the
> patch [2] applied
>
> Verified the touch screen on AM335x GP EVM and AM335x BBB LCD7
> cape with [3] dts for display and touch screen to work.
>
Since there are acks from DT and MFD maintainers, can you pull the patch
series if you do not have any more comments.
Regards
Mugunthan V N
^ permalink raw reply
* [PATCH 2/2] dt-bindings: Add DT bindings info for FlexRM mailbox driver
From: Anup Patel @ 2016-11-25 4:35 UTC (permalink / raw)
To: Jassi Brar, Rob Herring
Cc: Mark Rutland, Ray Jui, Scott Branden, Pramod KUMAR, Rob Rice,
devicetree, linux-kernel, linux-arm-kernel,
bcm-kernel-feedback-list, Anup Patel
In-Reply-To: <1480048551-3285-1-git-send-email-anup.patel@broadcom.com>
This patch adds device tree bindings document for the FlexRM
mailbox driver.
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
Signed-off-by: Anup Patel <anup.patel@broadcom.com>
---
.../bindings/mailbox/brcm,flexrm-mbox.txt | 60 ++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mailbox/brcm,flexrm-mbox.txt
diff --git a/Documentation/devicetree/bindings/mailbox/brcm,flexrm-mbox.txt b/Documentation/devicetree/bindings/mailbox/brcm,flexrm-mbox.txt
new file mode 100644
index 0000000..7969b1c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/brcm,flexrm-mbox.txt
@@ -0,0 +1,60 @@
+Broadcom FlexRM Mailbox Driver
+===============================
+The Broadcom FlexRM ring manager provides a set of rings which can be
+used to submit work to offload engines. An SoC may have multiple FlexRM
+hardware blocks. There is one device tree entry per block. The FlexRM
+mailbox drivers creates a mailbox instance using FlexRM rings where
+each mailbox channel is a separate FlexRM ring.
+
+Required properties:
+--------------------
+- compatible: Should be "brcm,flexrm-mbox"
+- reg: Specifies base physical address and size of the FlexRM
+ ring registers
+- msi-parent: Phandles (and potential Device IDs) to MSI controllers
+ The FlexRM engine will send MSIs (instead of wired
+ interrupts) to CPU. There is one MSI for each FlexRM ring.
+ Refer devicetree/bindings/interrupt-controller/msi.txt
+- #mbox-cells: Specifies the number of cells needed to encode a mailbox
+ channel. This should be 3.
+
+ The 1st cell is the mailbox channel number.
+
+ The 2nd cell contains MSI completion threshold. This is the
+ number of completion messages for which FlexRM will inject
+ one MSI interrupt to CPU.
+
+ The 3nd cell contains MSI timer value representing time for
+ which FlexRM will wait to accumulate N completion messages
+ where N is the value specified by 2nd cell above. If FlexRM
+ does not get required number of completion messages in time
+ specified by this cell then it will inject one MSI interrupt
+ to CPU provided atleast one completion message is available.
+
+Optional properties:
+--------------------
+- dma-coherent: Present if DMA operations made by the FlexRM engine (such
+ as DMA descriptor access, access to buffers pointed by DMA
+ descriptors and read/write pointer updates to DDR) are
+ cache coherent with the CPU.
+
+Example:
+--------
+crypto_mbox: mbox@67000000 {
+ compatible = "brcm,flexrm-mbox";
+ reg = <0x67000000 0x200000>;
+ msi-parent = <&gic_its 0x7f00>;
+ #mbox-cells = <3>;
+};
+
+crypto_client {
+ ...
+ mboxes = <&crypto_mbox 0 0x1 0xffff>,
+ <&crypto_mbox 1 0x1 0xffff>,
+ <&crypto_mbox 16 0x1 0xffff>,
+ <&crypto_mbox 17 0x1 0xffff>,
+ <&crypto_mbox 30 0x1 0xffff>,
+ <&crypto_mbox 31 0x1 0xffff>;
+ };
+ ...
+};
--
2.7.4
^ permalink raw reply related
* [PATCH 1/2] mailbox: Add driver for Broadcom FlexRM ring manager
From: Anup Patel @ 2016-11-25 4:35 UTC (permalink / raw)
To: Jassi Brar, Rob Herring
Cc: Mark Rutland, Ray Jui, Scott Branden, Pramod KUMAR, Rob Rice,
devicetree, linux-kernel, linux-arm-kernel,
bcm-kernel-feedback-list, Anup Patel
In-Reply-To: <1480048551-3285-1-git-send-email-anup.patel@broadcom.com>
Some of the Broadcom iProc SoCs have FlexRM ring manager
which provides a ring-based programming interface to various
offload engines (e.g. RAID, Crypto, etc).
This patch adds a common mailbox driver for Broadcom FlexRM
ring manager which can be shared by various offload engine
drivers (implemented as mailbox clients).
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
Reviewed-by: Pramod KUMAR <pramod.kumar@broadcom.com>
Signed-off-by: Anup Patel <anup.patel@broadcom.com>
---
drivers/mailbox/Kconfig | 11 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/mailbox-flexrm/Makefile | 6 +
drivers/mailbox/mailbox-flexrm/flexrm-desc.c | 764 ++++++++++++++++++++++++
drivers/mailbox/mailbox-flexrm/flexrm-desc.h | 47 ++
drivers/mailbox/mailbox-flexrm/flexrm-main.c | 829 +++++++++++++++++++++++++++
include/linux/mailbox/brcm-message.h | 12 +-
7 files changed, 1667 insertions(+), 4 deletions(-)
create mode 100644 drivers/mailbox/mailbox-flexrm/Makefile
create mode 100644 drivers/mailbox/mailbox-flexrm/flexrm-desc.c
create mode 100644 drivers/mailbox/mailbox-flexrm/flexrm-desc.h
create mode 100644 drivers/mailbox/mailbox-flexrm/flexrm-main.c
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 11eebfe..bfeced1 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -143,4 +143,15 @@ config BCM_PDC_MBOX
Mailbox implementation for the Broadcom PDC ring manager,
which provides access to various offload engines on Broadcom
SoCs. Say Y here if you want to use the Broadcom PDC.
+
+config BCM_FLEXRM_MBOX
+ tristate "Broadcom FlexRM Mailbox"
+ depends on ARM64 || COMPILE_TEST
+ depends on HAS_DMA
+ select GENERIC_MSI_IRQ_DOMAIN
+ default ARCH_BCM_IPROC
+ help
+ Mailbox implementation of the Broadcom FlexRM ring manager,
+ which provides access to various offload engines on Broadcom
+ SoCs. Say Y here if you want to use the Broadcom FlexRM.
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index ace6fed..9594266 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o
obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o
obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o
+
+obj-$(CONFIG_BCM_FLEXRM_MBOX) += mailbox-flexrm/
diff --git a/drivers/mailbox/mailbox-flexrm/Makefile b/drivers/mailbox/mailbox-flexrm/Makefile
new file mode 100644
index 0000000..f5bf069
--- /dev/null
+++ b/drivers/mailbox/mailbox-flexrm/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Broadcom FlexRM Mailbox Driver.
+#
+
+flexrm-mbox-objs := flexrm-main.o flexrm-desc.o
+obj-$(CONFIG_BCM_FLEXRM_MBOX) += flexrm-mbox.o
diff --git a/drivers/mailbox/mailbox-flexrm/flexrm-desc.c b/drivers/mailbox/mailbox-flexrm/flexrm-desc.c
new file mode 100644
index 0000000..9432ec7
--- /dev/null
+++ b/drivers/mailbox/mailbox-flexrm/flexrm-desc.c
@@ -0,0 +1,764 @@
+/* Broadcom FlexRM Mailbox Driver
+ *
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * FlexRM descriptor library
+ */
+
+#include <asm/barrier.h>
+#include <asm/byteorder.h>
+#include <linux/dma-mapping.h>
+#include <linux/printk.h>
+
+#include "flexrm-desc.h"
+
+/* Completion descriptor format */
+#define CMPL_OPAQUE_SHIFT 0
+#define CMPL_OPAQUE_MASK 0xffff
+#define CMPL_ENGINE_STATUS_SHIFT 16
+#define CMPL_ENGINE_STATUS_MASK 0xffff
+#define CMPL_DME_STATUS_SHIFT 32
+#define CMPL_DME_STATUS_MASK 0xffff
+#define CMPL_RM_STATUS_SHIFT 48
+#define CMPL_RM_STATUS_MASK 0xffff
+
+/* Completion DME status code */
+#define DME_STATUS_MEM_COR_ERR BIT(0)
+#define DME_STATUS_MEM_UCOR_ERR BIT(1)
+#define DME_STATUS_FIFO_UNDERFLOW BIT(2)
+#define DME_STATUS_FIFO_OVERFLOW BIT(3)
+#define DME_STATUS_RRESP_ERR BIT(4)
+#define DME_STATUS_BRESP_ERR BIT(5)
+#define DME_STATUS_ERROR_MASK (DME_STATUS_MEM_COR_ERR | \
+ DME_STATUS_MEM_UCOR_ERR | \
+ DME_STATUS_FIFO_UNDERFLOW | \
+ DME_STATUS_FIFO_OVERFLOW | \
+ DME_STATUS_RRESP_ERR | \
+ DME_STATUS_BRESP_ERR)
+
+/* Completion RM status code */
+#define RM_STATUS_CODE_SHIFT 0
+#define RM_STATUS_CODE_MASK 0x3ff
+#define RM_STATUS_CODE_GOOD 0x0
+#define RM_STATUS_CODE_AE_TIMEOUT 0x3ff
+
+/* General descriptor format */
+#define DESC_TYPE_SHIFT 60
+#define DESC_TYPE_MASK 0xf
+#define DESC_PAYLOAD_SHIFT 0
+#define DESC_PAYLOAD_MASK 0x0fffffffffffffff
+
+/* Null descriptor format */
+#define NULL_TYPE 0
+#define NULL_TOGGLE_SHIFT 58
+#define NULL_TOGGLE_MASK 0x1
+
+/* Header descriptor format */
+#define HEADER_TYPE 1
+#define HEADER_TOGGLE_SHIFT 58
+#define HEADER_TOGGLE_MASK 0x1
+#define HEADER_ENDPKT_SHIFT 57
+#define HEADER_ENDPKT_MASK 0x1
+#define HEADER_STARTPKT_SHIFT 56
+#define HEADER_STARTPKT_MASK 0x1
+#define HEADER_BDCOUNT_SHIFT 36
+#define HEADER_BDCOUNT_MASK 0x1f
+#define HEADER_BDCOUNT_MAX HEADER_BDCOUNT_MASK
+#define HEADER_FLAGS_SHIFT 16
+#define HEADER_FLAGS_MASK 0xffff
+#define HEADER_OPAQUE_SHIFT 0
+#define HEADER_OPAQUE_MASK 0xffff
+
+/* Source (SRC) descriptor format */
+#define SRC_TYPE 2
+#define SRC_LENGTH_SHIFT 44
+#define SRC_LENGTH_MASK 0xffff
+#define SRC_ADDR_SHIFT 0
+#define SRC_ADDR_MASK 0x00000fffffffffff
+
+/* Destination (DST) descriptor format */
+#define DST_TYPE 3
+#define DST_LENGTH_SHIFT 44
+#define DST_LENGTH_MASK 0xffff
+#define DST_ADDR_SHIFT 0
+#define DST_ADDR_MASK 0x00000fffffffffff
+
+/* Immediate (IMM) descriptor format */
+#define IMM_TYPE 4
+#define IMM_DATA_SHIFT 0
+#define IMM_DATA_MASK 0x0fffffffffffffff
+
+/* Next pointer (NPTR) descriptor format */
+#define NPTR_TYPE 5
+#define NPTR_TOGGLE_SHIFT 58
+#define NPTR_TOGGLE_MASK 0x1
+#define NPTR_ADDR_SHIFT 0
+#define NPTR_ADDR_MASK 0x00000fffffffffff
+
+/* Mega source (MSRC) descriptor format */
+#define MSRC_TYPE 6
+#define MSRC_LENGTH_SHIFT 44
+#define MSRC_LENGTH_MASK 0xffff
+#define MSRC_ADDR_SHIFT 0
+#define MSRC_ADDR_MASK 0x00000fffffffffff
+
+/* Mega destination (MDST) descriptor format */
+#define MDST_TYPE 7
+#define MDST_LENGTH_SHIFT 44
+#define MDST_LENGTH_MASK 0xffff
+#define MDST_ADDR_SHIFT 0
+#define MDST_ADDR_MASK 0x00000fffffffffff
+
+/* Source with tlast (SRCT) descriptor format */
+#define SRCT_TYPE 8
+#define SRCT_LENGTH_SHIFT 44
+#define SRCT_LENGTH_MASK 0xffff
+#define SRCT_ADDR_SHIFT 0
+#define SRCT_ADDR_MASK 0x00000fffffffffff
+
+/* Destination with tlast (DSTT) descriptor format */
+#define DSTT_TYPE 9
+#define DSTT_LENGTH_SHIFT 44
+#define DSTT_LENGTH_MASK 0xffff
+#define DSTT_ADDR_SHIFT 0
+#define DSTT_ADDR_MASK 0x00000fffffffffff
+
+/* Immediate with tlast (IMMT) descriptor format */
+#define IMMT_TYPE 10
+#define IMMT_DATA_SHIFT 0
+#define IMMT_DATA_MASK 0x0fffffffffffffff
+
+/* Descriptor helper macros */
+#define DESC_DEC(_d, _s, _m) (((_d) >> (_s)) & (_m))
+#define DESC_ENC(_d, _v, _s, _m) \
+ do { \
+ (_d) &= ~((u64)(_m) << (_s)); \
+ (_d) |= (((u64)(_v) & (_m)) << (_s)); \
+ } while (0)
+
+u64 flexrm_read_desc(void *desc_ptr)
+{
+ return le64_to_cpu(*((u64 *)desc_ptr));
+}
+
+void flexrm_write_desc(void *desc_ptr, u64 desc)
+{
+ *((u64 *)desc_ptr) = cpu_to_le64(desc);
+}
+
+u32 flexrm_cmpl_desc_to_reqid(u64 cmpl_desc)
+{
+ return (u32)(cmpl_desc & CMPL_OPAQUE_MASK);
+}
+
+int flexrm_cmpl_desc_to_error(u64 cmpl_desc)
+{
+ u32 status;
+
+ status = DESC_DEC(cmpl_desc, CMPL_DME_STATUS_SHIFT,
+ CMPL_DME_STATUS_MASK);
+ if (status & DME_STATUS_ERROR_MASK)
+ return -EIO;
+
+ status = DESC_DEC(cmpl_desc, CMPL_RM_STATUS_SHIFT,
+ CMPL_RM_STATUS_MASK);
+ status &= RM_STATUS_CODE_MASK;
+ if (status == RM_STATUS_CODE_AE_TIMEOUT)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+bool flexrm_is_next_table_desc(void *desc_ptr)
+{
+ u64 desc = flexrm_read_desc(desc_ptr);
+ u32 type = DESC_DEC(desc, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+
+ return (type == NPTR_TYPE) ? true : false;
+}
+
+u64 flexrm_next_table_desc(u32 toggle, dma_addr_t next_addr)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, NPTR_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, toggle, NPTR_TOGGLE_SHIFT, NPTR_TOGGLE_MASK);
+ DESC_ENC(desc, next_addr, NPTR_ADDR_SHIFT, NPTR_ADDR_MASK);
+
+ return desc;
+}
+
+u64 flexrm_null_desc(u32 toggle)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, NULL_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, toggle, NULL_TOGGLE_SHIFT, NULL_TOGGLE_MASK);
+
+ return desc;
+}
+
+u32 flexrm_estimate_header_desc_count(u32 nhcnt)
+{
+ u32 hcnt = nhcnt / HEADER_BDCOUNT_MAX;
+
+ if (!(nhcnt % HEADER_BDCOUNT_MAX))
+ hcnt += 1;
+
+ return hcnt;
+}
+
+static void flexrm_flip_header_toogle(void *desc_ptr)
+{
+ u64 desc = flexrm_read_desc(desc_ptr);
+
+ if (desc & ((u64)0x1 << HEADER_TOGGLE_SHIFT))
+ desc &= ~((u64)0x1 << HEADER_TOGGLE_SHIFT);
+ else
+ desc |= ((u64)0x1 << HEADER_TOGGLE_SHIFT);
+
+ flexrm_write_desc(desc_ptr, desc);
+}
+
+static u64 flexrm_header_desc(u32 toggle, u32 startpkt, u32 endpkt,
+ u32 bdcount, u32 flags, u32 opaque)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, HEADER_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, toggle, HEADER_TOGGLE_SHIFT, HEADER_TOGGLE_MASK);
+ DESC_ENC(desc, startpkt, HEADER_STARTPKT_SHIFT, HEADER_STARTPKT_MASK);
+ DESC_ENC(desc, endpkt, HEADER_ENDPKT_SHIFT, HEADER_ENDPKT_MASK);
+ DESC_ENC(desc, bdcount, HEADER_BDCOUNT_SHIFT, HEADER_BDCOUNT_MASK);
+ DESC_ENC(desc, flags, HEADER_FLAGS_SHIFT, HEADER_FLAGS_MASK);
+ DESC_ENC(desc, opaque, HEADER_OPAQUE_SHIFT, HEADER_OPAQUE_MASK);
+
+ return desc;
+}
+
+static void flexrm_enqueue_desc(u32 nhpos, u32 nhcnt, u32 reqid,
+ u64 desc, void **desc_ptr, u32 *toggle,
+ void *start_desc, void *end_desc)
+{
+ u64 d;
+ u32 nhavail, _toggle, _startpkt, _endpkt, _bdcount;
+
+ /* Sanity check */
+ if (nhcnt <= nhpos)
+ return;
+
+ /*
+ * Each request or packet start with a HEADER descriptor followed
+ * by one or more non-HEADER descriptors (SRC, SRCT, MSRC, DST,
+ * DSTT, MDST, IMM, and IMMT). The number of non-HEADER descriptors
+ * following a HEADER descriptor is represented by BDCOUNT field
+ * of HEADER descriptor. The max value of BDCOUNT field is 31 which
+ * means we can only have 31 non-HEADER descriptors following one
+ * HEADER descriptor.
+ *
+ * In general use, number of non-HEADER descriptors can easily go
+ * beyond 31. To tackle this situation, we have packet (or request)
+ * extenstion bits (STARTPKT and ENDPKT) in the HEADER descriptor.
+ *
+ * To use packet extension, the first HEADER descriptor of request
+ * (or packet) will have STARTPKT=1 and ENDPKT=0. The intermediate
+ * HEADER descriptors will have STARTPKT=0 and ENDPKT=0. The last
+ * HEADER descriptor will have STARTPKT=0 and ENDPKT=1. Also, the
+ * TOGGLE bit of the first HEADER will be set to invalid state to
+ * ensure that FlexRM does not start fetching descriptors till all
+ * descriptors are enqueued. The user of this function will flip
+ * the TOGGLE bit of first HEADER after all descriptors are
+ * enqueued.
+ */
+
+ if ((nhpos % HEADER_BDCOUNT_MAX == 0) && (nhcnt - nhpos)) {
+ /* Prepare the header descriptor */
+ nhavail = (nhcnt - nhpos);
+ _toggle = (nhpos == 0) ? !(*toggle) : (*toggle);
+ _startpkt = (nhpos == 0) ? 0x1 : 0x0;
+ _endpkt = (nhavail <= HEADER_BDCOUNT_MAX) ? 0x1 : 0x0;
+ _bdcount = (nhavail <= HEADER_BDCOUNT_MAX) ?
+ nhavail : HEADER_BDCOUNT_MAX;
+ if (nhavail <= HEADER_BDCOUNT_MAX)
+ _bdcount = nhavail;
+ else
+ _bdcount = HEADER_BDCOUNT_MAX;
+ d = flexrm_header_desc(_toggle, _startpkt, _endpkt,
+ _bdcount, 0x0, reqid);
+
+ /* Write header descriptor */
+ flexrm_write_desc(*desc_ptr, d);
+
+ /* Point to next descriptor */
+ *desc_ptr += sizeof(desc);
+ if (*desc_ptr == end_desc)
+ *desc_ptr = start_desc;
+
+ /* Skip next pointer descriptors */
+ while (flexrm_is_next_table_desc(*desc_ptr)) {
+ *toggle = (*toggle) ? 0 : 1;
+ *desc_ptr += sizeof(desc);
+ if (*desc_ptr == end_desc)
+ *desc_ptr = start_desc;
+ }
+ }
+
+ /* Write desired descriptor */
+ flexrm_write_desc(*desc_ptr, desc);
+
+ /* Point to next descriptor */
+ *desc_ptr += sizeof(desc);
+ if (*desc_ptr == end_desc)
+ *desc_ptr = start_desc;
+
+ /* Skip next pointer descriptors */
+ while (flexrm_is_next_table_desc(*desc_ptr)) {
+ *toggle = (*toggle) ? 0 : 1;
+ *desc_ptr += sizeof(desc);
+ if (*desc_ptr == end_desc)
+ *desc_ptr = start_desc;
+ }
+}
+
+static u64 flexrm_src_desc(dma_addr_t addr, unsigned int length)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, SRC_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, length, SRC_LENGTH_SHIFT, SRC_LENGTH_MASK);
+ DESC_ENC(desc, addr, SRC_ADDR_SHIFT, SRC_ADDR_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_msrc_desc(dma_addr_t addr, unsigned int length_div_16)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, MSRC_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, length_div_16, MSRC_LENGTH_SHIFT, MSRC_LENGTH_MASK);
+ DESC_ENC(desc, addr, MSRC_ADDR_SHIFT, MSRC_ADDR_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_dst_desc(dma_addr_t addr, unsigned int length)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, DST_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, length, DST_LENGTH_SHIFT, DST_LENGTH_MASK);
+ DESC_ENC(desc, addr, DST_ADDR_SHIFT, DST_ADDR_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_mdst_desc(dma_addr_t addr, unsigned int length_div_16)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, MDST_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, length_div_16, MDST_LENGTH_SHIFT, MDST_LENGTH_MASK);
+ DESC_ENC(desc, addr, MDST_ADDR_SHIFT, MDST_ADDR_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_imm_desc(u64 data)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, IMM_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, data, IMM_DATA_SHIFT, IMM_DATA_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_srct_desc(dma_addr_t addr, unsigned int length)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, SRCT_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, length, SRCT_LENGTH_SHIFT, SRCT_LENGTH_MASK);
+ DESC_ENC(desc, addr, SRCT_ADDR_SHIFT, SRCT_ADDR_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_dstt_desc(dma_addr_t addr, unsigned int length)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, DSTT_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, length, DSTT_LENGTH_SHIFT, DSTT_LENGTH_MASK);
+ DESC_ENC(desc, addr, DSTT_ADDR_SHIFT, DSTT_ADDR_MASK);
+
+ return desc;
+}
+
+static u64 flexrm_immt_desc(u64 data)
+{
+ u64 desc = 0;
+
+ DESC_ENC(desc, IMMT_TYPE, DESC_TYPE_SHIFT, DESC_TYPE_MASK);
+ DESC_ENC(desc, data, IMMT_DATA_SHIFT, IMMT_DATA_MASK);
+
+ return desc;
+}
+
+static bool flexrm_spu_sanity_check(struct brcm_message *msg)
+{
+ struct scatterlist *sg;
+
+ if (!msg->spu.src || !msg->spu.dst)
+ return false;
+ for (sg = msg->spu.src; sg; sg = sg_next(sg)) {
+ if (sg->length & 0xf) {
+ if (sg->length > SRC_LENGTH_MASK)
+ return false;
+ } else {
+ if (sg->length > (MSRC_LENGTH_MASK * 16))
+ return false;
+ }
+ }
+ for (sg = msg->spu.dst; sg; sg = sg_next(sg)) {
+ if (sg->length & 0xf) {
+ if (sg->length > DST_LENGTH_MASK)
+ return false;
+ } else {
+ if (sg->length > (MDST_LENGTH_MASK * 16))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static u32 flexrm_spu_estimate_nonheader_desc_count(struct brcm_message *msg)
+{
+ u32 cnt = 0;
+ unsigned int dst_target = 0;
+ struct scatterlist *src_sg = msg->spu.src, *dst_sg = msg->spu.dst;
+
+ while (src_sg || dst_sg) {
+ if (src_sg) {
+ cnt++;
+ dst_target = src_sg->length;
+ src_sg = sg_next(src_sg);
+ } else
+ dst_target = UINT_MAX;
+
+ while (dst_target && dst_sg) {
+ cnt++;
+ if (dst_sg->length < dst_target)
+ dst_target -= dst_sg->length;
+ else
+ dst_target = 0;
+ dst_sg = sg_next(dst_sg);
+ }
+ }
+
+ return cnt;
+}
+
+static int flexrm_spu_dma_map(struct device *dev, struct brcm_message *msg)
+{
+ int rc;
+
+ rc = dma_map_sg(dev, msg->spu.src, sg_nents(msg->spu.src),
+ DMA_TO_DEVICE);
+ if (rc < 0)
+ return rc;
+
+ rc = dma_map_sg(dev, msg->spu.dst, sg_nents(msg->spu.dst),
+ DMA_FROM_DEVICE);
+ if (rc < 0) {
+ dma_unmap_sg(dev, msg->spu.src, sg_nents(msg->spu.src),
+ DMA_TO_DEVICE);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void flexrm_spu_dma_unmap(struct device *dev, struct brcm_message *msg)
+{
+ dma_unmap_sg(dev, msg->spu.dst, sg_nents(msg->spu.dst),
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, msg->spu.src, sg_nents(msg->spu.src),
+ DMA_TO_DEVICE);
+}
+
+static void *flexrm_spu_write_descs(struct brcm_message *msg, u32 nhcnt,
+ u32 reqid, void *desc_ptr, u32 toggle,
+ void *start_desc, void *end_desc)
+{
+ u64 d;
+ u32 nhpos = 0;
+ void *orig_desc_ptr = desc_ptr;
+ unsigned int dst_target = 0;
+ struct scatterlist *src_sg = msg->spu.src, *dst_sg = msg->spu.dst;
+
+ while (src_sg || dst_sg) {
+ if (src_sg) {
+ if (sg_dma_len(src_sg) & 0xf)
+ d = flexrm_src_desc(sg_dma_address(src_sg),
+ sg_dma_len(src_sg));
+ else
+ d = flexrm_msrc_desc(sg_dma_address(src_sg),
+ sg_dma_len(src_sg)/16);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ dst_target = sg_dma_len(src_sg);
+ src_sg = sg_next(src_sg);
+ } else
+ dst_target = UINT_MAX;
+
+ while (dst_target && dst_sg) {
+ if (sg_dma_len(dst_sg) & 0xf)
+ d = flexrm_dst_desc(sg_dma_address(dst_sg),
+ sg_dma_len(dst_sg));
+ else
+ d = flexrm_mdst_desc(sg_dma_address(dst_sg),
+ sg_dma_len(dst_sg)/16);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ if (sg_dma_len(dst_sg) < dst_target)
+ dst_target -= sg_dma_len(dst_sg);
+ else
+ dst_target = 0;
+ dst_sg = sg_next(dst_sg);
+ }
+ }
+
+ /* Null descriptor with invalid toggle bit */
+ flexrm_write_desc(desc_ptr, flexrm_null_desc(!toggle));
+
+ /* Ensure that descriptors have been written to memory */
+ wmb();
+
+ /* Flip toggle bit in header */
+ flexrm_flip_header_toogle(orig_desc_ptr);
+
+ return desc_ptr;
+}
+
+static bool flexrm_sba_sanity_check(struct brcm_message *msg)
+{
+ u32 i;
+
+ if (!msg->sba.cmds || !msg->sba.cmds_count)
+ return false;
+
+ for (i = 0; i < msg->sba.cmds_count; i++) {
+ if (((msg->sba.cmds[i].flags & BRCM_SBA_CMD_TYPE_B) ||
+ (msg->sba.cmds[i].flags & BRCM_SBA_CMD_TYPE_C)) &&
+ (msg->sba.cmds[i].flags & BRCM_SBA_CMD_HAS_OUTPUT))
+ return false;
+ if ((msg->sba.cmds[i].flags & BRCM_SBA_CMD_TYPE_B) &&
+ (msg->sba.cmds[i].data_len > SRCT_LENGTH_MASK))
+ return false;
+ if ((msg->sba.cmds[i].flags & BRCM_SBA_CMD_TYPE_C) &&
+ (msg->sba.cmds[i].data_len > SRCT_LENGTH_MASK))
+ return false;
+ if ((msg->sba.cmds[i].flags & BRCM_SBA_CMD_HAS_RESP) &&
+ (msg->sba.cmds[i].resp_len > DSTT_LENGTH_MASK))
+ return false;
+ if ((msg->sba.cmds[i].flags & BRCM_SBA_CMD_HAS_OUTPUT) &&
+ (msg->sba.cmds[i].data_len > DSTT_LENGTH_MASK))
+ return false;
+ }
+
+ return true;
+}
+
+static u32 flexrm_sba_estimate_nonheader_desc_count(struct brcm_message *msg)
+{
+ u32 i, cnt;
+
+ cnt = 0;
+ for (i = 0; i < msg->sba.cmds_count; i++) {
+ cnt++;
+
+ if ((msg->sba.cmds[i].flags & BRCM_SBA_CMD_TYPE_B) ||
+ (msg->sba.cmds[i].flags & BRCM_SBA_CMD_TYPE_C))
+ cnt++;
+
+ if (msg->sba.cmds[i].flags & BRCM_SBA_CMD_HAS_RESP)
+ cnt++;
+
+ if (msg->sba.cmds[i].flags & BRCM_SBA_CMD_HAS_OUTPUT)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+static void *flexrm_sba_write_descs(struct brcm_message *msg, u32 nhcnt,
+ u32 reqid, void *desc_ptr, u32 toggle,
+ void *start_desc, void *end_desc)
+{
+ u64 d;
+ u32 i, nhpos = 0;
+ struct brcm_sba_command *c;
+ void *orig_desc_ptr = desc_ptr;
+
+ /* Convert SBA commands into descriptors */
+ for (i = 0; i < msg->sba.cmds_count; i++) {
+ c = &msg->sba.cmds[i];
+
+ if ((c->flags & BRCM_SBA_CMD_HAS_RESP) &&
+ (c->flags & BRCM_SBA_CMD_HAS_OUTPUT)) {
+ /* Destination response descriptor */
+ d = flexrm_dst_desc(c->resp, c->resp_len);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ } else if (c->flags & BRCM_SBA_CMD_HAS_RESP) {
+ /* Destination response with tlast descriptor */
+ d = flexrm_dstt_desc(c->resp, c->resp_len);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ }
+
+ if (c->flags & BRCM_SBA_CMD_HAS_OUTPUT) {
+ /* Destination with tlast descriptor */
+ d = flexrm_dstt_desc(c->data, c->data_len);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ }
+
+ if (c->flags & BRCM_SBA_CMD_TYPE_B) {
+ /* Command as immediate descriptor */
+ d = flexrm_imm_desc(c->cmd);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ } else {
+ /* Command as immediate descriptor with tlast */
+ d = flexrm_immt_desc(c->cmd);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ }
+
+ if ((c->flags & BRCM_SBA_CMD_TYPE_B) ||
+ (c->flags & BRCM_SBA_CMD_TYPE_C)) {
+ /* Source with tlast descriptor */
+ d = flexrm_srct_desc(c->data, c->data_len);
+ flexrm_enqueue_desc(nhpos, nhcnt, reqid,
+ d, &desc_ptr, &toggle,
+ start_desc, end_desc);
+ nhpos++;
+ }
+ }
+
+ /* Null descriptor with invalid toggle bit */
+ flexrm_write_desc(desc_ptr, flexrm_null_desc(!toggle));
+
+ /* Ensure that descriptors have been written to memory */
+ wmb();
+
+ /* Flip toggle bit in header */
+ flexrm_flip_header_toogle(orig_desc_ptr);
+
+ return desc_ptr;
+}
+
+bool flexrm_sanity_check(struct brcm_message *msg)
+{
+ if (!msg)
+ return false;
+
+ switch (msg->type) {
+ case BRCM_MESSAGE_SPU:
+ return flexrm_spu_sanity_check(msg);
+ case BRCM_MESSAGE_SBA:
+ return flexrm_sba_sanity_check(msg);
+ default:
+ return false;
+ };
+}
+
+u32 flexrm_estimate_nonheader_desc_count(struct brcm_message *msg)
+{
+ if (!msg)
+ return 0;
+
+ switch (msg->type) {
+ case BRCM_MESSAGE_SPU:
+ return flexrm_spu_estimate_nonheader_desc_count(msg);
+ case BRCM_MESSAGE_SBA:
+ return flexrm_sba_estimate_nonheader_desc_count(msg);
+ default:
+ return 0;
+ };
+}
+
+int flexrm_dma_map(struct device *dev, struct brcm_message *msg)
+{
+ if (!dev || !msg)
+ return -EINVAL;
+
+ switch (msg->type) {
+ case BRCM_MESSAGE_SPU:
+ return flexrm_spu_dma_map(dev, msg);
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+void flexrm_dma_unmap(struct device *dev, struct brcm_message *msg)
+{
+ if (!dev || !msg)
+ return;
+
+ switch (msg->type) {
+ case BRCM_MESSAGE_SPU:
+ flexrm_spu_dma_unmap(dev, msg);
+ break;
+ default:
+ break;
+ };
+}
+
+void *flexrm_write_descs(struct brcm_message *msg, u32 nhcnt,
+ u32 reqid, void *desc_ptr, u32 toggle,
+ void *start_desc, void *end_desc)
+{
+ if (!msg || !desc_ptr || !start_desc || !end_desc)
+ return ERR_PTR(-ENOTSUPP);
+
+ if ((desc_ptr < start_desc) || (end_desc <= desc_ptr))
+ return ERR_PTR(-ERANGE);
+
+ switch (msg->type) {
+ case BRCM_MESSAGE_SPU:
+ return flexrm_spu_write_descs(msg, nhcnt, reqid,
+ desc_ptr, toggle,
+ start_desc, end_desc);
+ case BRCM_MESSAGE_SBA:
+ return flexrm_sba_write_descs(msg, nhcnt, reqid,
+ desc_ptr, toggle,
+ start_desc, end_desc);
+ default:
+ return ERR_PTR(-ENOTSUPP);
+ };
+}
diff --git a/drivers/mailbox/mailbox-flexrm/flexrm-desc.h b/drivers/mailbox/mailbox-flexrm/flexrm-desc.h
new file mode 100644
index 0000000..a95cf61
--- /dev/null
+++ b/drivers/mailbox/mailbox-flexrm/flexrm-desc.h
@@ -0,0 +1,47 @@
+/* Broadcom FlexRM Mailbox Driver
+ *
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * FlexRM descriptor library
+ */
+
+#ifndef __FLEXRM_DESC_H__
+#define __FLEXRM_DESC_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mailbox/brcm-message.h>
+
+extern u64 flexrm_read_desc(void *desc_ptr);
+
+extern void flexrm_write_desc(void *desc_ptr, u64 desc);
+
+extern u32 flexrm_cmpl_desc_to_reqid(u64 cmpl_desc);
+
+extern int flexrm_cmpl_desc_to_error(u64 cmpl_desc);
+
+extern bool flexrm_is_next_table_desc(void *desc_ptr);
+
+extern u64 flexrm_next_table_desc(u32 toggle, dma_addr_t next_addr);
+
+extern u64 flexrm_null_desc(u32 toogle);
+
+extern u32 flexrm_estimate_header_desc_count(u32 nhcnt);
+
+extern bool flexrm_sanity_check(struct brcm_message *msg);
+
+extern u32 flexrm_estimate_nonheader_desc_count(struct brcm_message *msg);
+
+extern int flexrm_dma_map(struct device *dev, struct brcm_message *msg);
+
+extern void flexrm_dma_unmap(struct device *dev, struct brcm_message *msg);
+
+extern void *flexrm_write_descs(struct brcm_message *msg, u32 nhcnt,
+ u32 reqid, void *desc_ptr, u32 toggle,
+ void *start_desc, void *end_desc);
+
+#endif /* __FLEXRM_DESC_H__ */
diff --git a/drivers/mailbox/mailbox-flexrm/flexrm-main.c b/drivers/mailbox/mailbox-flexrm/flexrm-main.c
new file mode 100644
index 0000000..66ca497
--- /dev/null
+++ b/drivers/mailbox/mailbox-flexrm/flexrm-main.c
@@ -0,0 +1,829 @@
+/* Broadcom FlexRM Mailbox Driver
+ *
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Each Broadcom FlexSparx4 offload engine is implemented as an
+ * extension to Broadcom FlexRM ring manager. The FlexRM ring
+ * manager provides a set of rings which can be used to submit
+ * work to a FlexSparx4 offload engine.
+ *
+ * This driver creates a mailbox controller using a set of FlexRM
+ * rings where each mailbox channel represents a separate FlexRM ring.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
+#include <linux/mailbox/brcm-message.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "flexrm-desc.h"
+
+/* FlexRM configuration */
+#define RING_REGS_SIZE 0x10000
+#define RING_DESC_SIZE 8
+#define RING_DESC_INDEX(offset) \
+ ((offset) / RING_DESC_SIZE)
+#define RING_DESC_OFFSET(index) \
+ ((index) * RING_DESC_SIZE)
+#define RING_MAX_REQ_COUNT 1024
+#define RING_BD_ALIGN_ORDER 12
+#define RING_BD_ALIGN_CHECK(addr) \
+ (!((addr) & ((0x1 << RING_BD_ALIGN_ORDER) - 1)))
+#define RING_BD_TOGGLE_INVALID(offset) \
+ (((offset) >> RING_BD_ALIGN_ORDER) & 0x1)
+#define RING_BD_TOGGLE_VALID(offset) \
+ (!RING_BD_TOGGLE_INVALID(offset))
+#define RING_BD_DESC_PER_REQ 32
+#define RING_BD_DESC_COUNT \
+ (RING_MAX_REQ_COUNT * RING_BD_DESC_PER_REQ)
+#define RING_BD_SIZE \
+ (RING_BD_DESC_COUNT * RING_DESC_SIZE)
+#define RING_CMPL_ALIGN_ORDER 13
+#define RING_CMPL_DESC_COUNT RING_MAX_REQ_COUNT
+#define RING_CMPL_SIZE \
+ (RING_CMPL_DESC_COUNT * RING_DESC_SIZE)
+#define RING_VER_MAGIC 0x76303031
+
+/* Per-Ring register offsets */
+#define RING_VER 0x000
+#define RING_BD_START_ADDR 0x004
+#define RING_BD_READ_PTR 0x008
+#define RING_BD_WRITE_PTR 0x00c
+#define RING_BD_READ_PTR_DDR_LS 0x010
+#define RING_BD_READ_PTR_DDR_MS 0x014
+#define RING_CMPL_START_ADDR 0x018
+#define RING_CMPL_WRITE_PTR 0x01c
+#define RING_NUM_REQ_RECV_LS 0x020
+#define RING_NUM_REQ_RECV_MS 0x024
+#define RING_NUM_REQ_TRANS_LS 0x028
+#define RING_NUM_REQ_TRANS_MS 0x02c
+#define RING_NUM_REQ_OUTSTAND 0x030
+#define RING_CONTROL 0x034
+#define RING_FLUSH_DONE 0x038
+#define RING_MSI_ADDR_LS 0x03c
+#define RING_MSI_ADDR_MS 0x040
+#define RING_MSI_CONTROL 0x048
+#define RING_BD_READ_PTR_DDR_CONTROL 0x04c
+#define RING_MSI_DATA_VALUE 0x064
+
+/* Register RING_BD_START_ADDR fields */
+#define BD_LAST_UPDATE_HW_SHIFT 28
+#define BD_LAST_UPDATE_HW_MASK 0x1
+#define BD_START_ADDR_VALUE(pa) \
+ ((u32)((((dma_addr_t)(pa)) >> RING_BD_ALIGN_ORDER) & 0x0fffffff))
+#define BD_START_ADDR_DECODE(val) \
+ ((dma_addr_t)((val) & 0x0fffffff) << RING_BD_ALIGN_ORDER)
+
+/* Register RING_CMPL_START_ADDR fields */
+#define CMPL_START_ADDR_VALUE(pa) \
+ ((u32)((((u64)(pa)) >> RING_CMPL_ALIGN_ORDER) & 0x03ffffff))
+
+/* Register RING_CONTROL fields */
+#define CONTROL_MASK_DISABLE_CONTROL 12
+#define CONTROL_FLUSH_SHIFT 5
+#define CONTROL_ACTIVE_SHIFT 4
+#define CONTROL_RATE_ADAPT_MASK 0xf
+#define CONTROL_RATE_DYNAMIC 0x0
+#define CONTROL_RATE_FAST 0x8
+#define CONTROL_RATE_MEDIUM 0x9
+#define CONTROL_RATE_SLOW 0xa
+#define CONTROL_RATE_IDLE 0xb
+
+/* Register RING_FLUSH_DONE fields */
+#define FLUSH_DONE_MASK 0x1
+
+/* Register RING_MSI_CONTROL fields */
+#define MSI_TIMER_VAL_SHIFT 16
+#define MSI_TIMER_VAL_MASK 0xffff
+#define MSI_ENABLE_SHIFT 15
+#define MSI_ENABLE_MASK 0x1
+#define MSI_COUNT_SHIFT 0
+#define MSI_COUNT_MASK 0x3ff
+
+/* Register RING_BD_READ_PTR_DDR_CONTROL fields */
+#define BD_READ_PTR_DDR_TIMER_VAL_SHIFT 16
+#define BD_READ_PTR_DDR_TIMER_VAL_MASK 0xffff
+#define BD_READ_PTR_DDR_ENABLE_SHIFT 15
+#define BD_READ_PTR_DDR_ENABLE_MASK 0x1
+
+struct flexrm_ring {
+ /* Unprotected members */
+ int num;
+ struct flexrm_mbox *mbox;
+ void __iomem *regs;
+ bool irq_requested;
+ unsigned int irq;
+ unsigned int msi_timer_val;
+ unsigned int msi_count_threshold;
+ struct ida requests_ida;
+ struct brcm_message *requests[RING_MAX_REQ_COUNT];
+ void *bd_base;
+ dma_addr_t bd_dma_base;
+ u32 bd_write_offset;
+ void *cmpl_base;
+ dma_addr_t cmpl_dma_base;
+ /* Protected members */
+ spinlock_t lock;
+ struct brcm_message *last_pending_msg;
+ u32 cmpl_read_offset;
+};
+
+struct flexrm_mbox {
+ struct device *dev;
+ void __iomem *regs;
+ u32 num_rings;
+ struct flexrm_ring *rings;
+ u64 dma_mask;
+ struct dma_pool *bd_pool;
+ struct dma_pool *cmpl_pool;
+ struct mbox_controller controller;
+};
+
+static int flexrm_new_request(struct flexrm_ring *ring,
+ struct brcm_message *batch_msg,
+ struct brcm_message *msg)
+{
+ void *next;
+ unsigned long flags;
+ u32 val, count, nhcnt;
+ u32 read_offset, write_offset;
+ bool exit_cleanup = false;
+ int ret = 0, reqid;
+
+ /* Do sanity check on message */
+ if (!flexrm_sanity_check(msg))
+ return -EIO;
+ msg->error = 0;
+
+ /* If no requests possible then save data pointer and goto done. */
+ reqid = ida_simple_get(&ring->requests_ida, 0,
+ RING_MAX_REQ_COUNT, GFP_KERNEL);
+ if (reqid < 0) {
+ spin_lock_irqsave(&ring->lock, flags);
+ if (batch_msg)
+ ring->last_pending_msg = batch_msg;
+ else
+ ring->last_pending_msg = msg;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ return 0;
+ }
+ ring->requests[reqid] = msg;
+
+ /* Do DMA mappings for the message */
+ ret = flexrm_dma_map(ring->mbox->dev, msg);
+ if (ret < 0) {
+ ring->requests[reqid] = NULL;
+ ida_simple_remove(&ring->requests_ida, reqid);
+ return ret;
+ }
+
+ /* If last_pending_msg is already set then goto done with error */
+ spin_lock_irqsave(&ring->lock, flags);
+ if (ring->last_pending_msg)
+ ret = -ENOSPC;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ if (ret < 0) {
+ dev_warn(ring->mbox->dev, "no space in ring %d\n", ring->num);
+ exit_cleanup = true;
+ goto exit;
+ }
+
+ /* Determine current HW BD read offset */
+ read_offset = readl_relaxed(ring->regs + RING_BD_READ_PTR);
+ val = readl_relaxed(ring->regs + RING_BD_START_ADDR);
+ read_offset *= RING_DESC_SIZE;
+ read_offset += (u32)(BD_START_ADDR_DECODE(val) - ring->bd_dma_base);
+
+ /*
+ * Number required descriptors = number of non-header descriptors +
+ * number of header descriptors +
+ * 1x null descriptor
+ */
+ nhcnt = flexrm_estimate_nonheader_desc_count(msg);
+ count = flexrm_estimate_header_desc_count(nhcnt) + nhcnt + 1;
+
+ /* Check for available descriptor space. */
+ write_offset = ring->bd_write_offset;
+ while (count) {
+ if (!flexrm_is_next_table_desc(ring->bd_base + write_offset))
+ count--;
+ write_offset += RING_DESC_SIZE;
+ if (write_offset == RING_BD_SIZE)
+ write_offset = 0x0;
+ if (write_offset == read_offset)
+ break;
+ }
+ if (count) {
+ spin_lock_irqsave(&ring->lock, flags);
+ if (batch_msg)
+ ring->last_pending_msg = batch_msg;
+ else
+ ring->last_pending_msg = msg;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ ret = 0;
+ exit_cleanup = true;
+ goto exit;
+ }
+
+ /* Write descriptors to ring */
+ next = flexrm_write_descs(msg, nhcnt, reqid,
+ ring->bd_base + ring->bd_write_offset,
+ RING_BD_TOGGLE_VALID(ring->bd_write_offset),
+ ring->bd_base, ring->bd_base + RING_BD_SIZE);
+ if (IS_ERR(next)) {
+ ret = PTR_ERR(next);
+ exit_cleanup = true;
+ goto exit;
+ }
+
+ /* Save ring BD write offset */
+ ring->bd_write_offset = (unsigned long)(next - ring->bd_base);
+
+exit:
+ /* Update error status in message */
+ msg->error = ret;
+
+ /* Cleanup if we failed */
+ if (exit_cleanup) {
+ flexrm_dma_unmap(ring->mbox->dev, msg);
+ ring->requests[reqid] = NULL;
+ ida_simple_remove(&ring->requests_ida, reqid);
+ }
+
+ return ret;
+}
+
+static int flexrm_process_completions(struct flexrm_ring *ring)
+{
+ u64 desc;
+ int err, count = 0;
+ unsigned long flags;
+ struct brcm_message *msg = NULL;
+ u32 reqid, cmpl_read_offset, cmpl_write_offset;
+ struct mbox_chan *chan = &ring->mbox->controller.chans[ring->num];
+
+ spin_lock_irqsave(&ring->lock, flags);
+
+ /* Check last_pending_msg */
+ if (ring->last_pending_msg) {
+ msg = ring->last_pending_msg;
+ ring->last_pending_msg = NULL;
+ }
+
+ /*
+ * Get current completion read and write offset
+ *
+ * Note: We should read completion write pointer atleast once
+ * after we get a MSI interrupt because HW maintains internal
+ * MSI status which will allow next MSI interrupt only after
+ * completion write pointer is read.
+ */
+ cmpl_write_offset = readl_relaxed(ring->regs + RING_CMPL_WRITE_PTR);
+ cmpl_write_offset *= RING_DESC_SIZE;
+ cmpl_read_offset = ring->cmpl_read_offset;
+ ring->cmpl_read_offset = cmpl_write_offset;
+
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ /* If last_pending_msg was set then queue it back */
+ if (msg)
+ mbox_send_message(chan, msg);
+
+ /* For each completed request notify mailbox clients */
+ reqid = 0;
+ while (cmpl_read_offset != cmpl_write_offset) {
+ /* Dequeue next completion descriptor */
+ desc = *((u64 *)(ring->cmpl_base + cmpl_read_offset));
+
+ /* Next read offset */
+ cmpl_read_offset += RING_DESC_SIZE;
+ if (cmpl_read_offset == RING_CMPL_SIZE)
+ cmpl_read_offset = 0;
+
+ /* Decode error from completion descriptor */
+ err = flexrm_cmpl_desc_to_error(desc);
+ if (err < 0) {
+ dev_warn(ring->mbox->dev,
+ "got completion desc=0x%lx with error %d",
+ (unsigned long)desc, err);
+ }
+
+ /* Determine request id from completion descriptor */
+ reqid = flexrm_cmpl_desc_to_reqid(desc);
+
+ /* Determine message pointer based on reqid */
+ msg = ring->requests[reqid];
+ if (!msg) {
+ dev_warn(ring->mbox->dev,
+ "null msg pointer for completion desc=0x%lx",
+ (unsigned long)desc);
+ continue;
+ }
+
+ /* Release reqid for recycling */
+ ring->requests[reqid] = NULL;
+ ida_simple_remove(&ring->requests_ida, reqid);
+
+ /* Unmap DMA mappings */
+ flexrm_dma_unmap(ring->mbox->dev, msg);
+
+ /* Give-back message to mailbox client */
+ msg->error = err;
+ mbox_chan_received_data(chan, msg);
+
+ /* Increment number of completions processed */
+ count++;
+ }
+
+ return count;
+}
+
+static irqreturn_t flexrm_irq_event(int irq, void *dev_id)
+{
+ /* We only have MSI for completions so just wakeup IRQ thread */
+ /* Ring related errors will be informed via completion descriptors */
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t flexrm_irq_thread(int irq, void *dev_id)
+{
+ flexrm_process_completions(dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static int flexrm_send_data(struct mbox_chan *chan, void *data)
+{
+ int i, rc;
+ struct flexrm_ring *ring = chan->con_priv;
+ struct brcm_message *msg = data;
+
+ if (msg->type == BRCM_MESSAGE_BATCH) {
+ for (i = msg->batch.msgs_queued;
+ i < msg->batch.msgs_count; i++) {
+ rc = flexrm_new_request(ring, msg,
+ &msg->batch.msgs[i]);
+ if (rc) {
+ msg->error = rc;
+ return rc;
+ }
+ msg->batch.msgs_queued++;
+ }
+ return 0;
+ }
+
+ return flexrm_new_request(ring, NULL, data);
+}
+
+static bool flexrm_peek_data(struct mbox_chan *chan)
+{
+ int cnt = flexrm_process_completions(chan->con_priv);
+
+ return (cnt > 0) ? true : false;
+}
+
+static int flexrm_startup(struct mbox_chan *chan)
+{
+ u64 d;
+ u32 val, off;
+ int ret = 0;
+ dma_addr_t next_addr;
+ struct flexrm_ring *ring = chan->con_priv;
+
+ /* Allocate BD memory */
+ ring->bd_base = dma_pool_alloc(ring->mbox->bd_pool,
+ GFP_KERNEL, &ring->bd_dma_base);
+ if (!ring->bd_base) {
+ dev_err(ring->mbox->dev, "can't allocate BD memory\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* Configure next table pointer entries in BD memory */
+ for (off = 0; off < RING_BD_SIZE; off += RING_DESC_SIZE) {
+ next_addr = off + RING_DESC_SIZE;
+ if (next_addr == RING_BD_SIZE)
+ next_addr = 0;
+ next_addr += ring->bd_dma_base;
+ if (RING_BD_ALIGN_CHECK(next_addr))
+ d = flexrm_next_table_desc(RING_BD_TOGGLE_VALID(off),
+ next_addr);
+ else
+ d = flexrm_null_desc(RING_BD_TOGGLE_INVALID(off));
+ flexrm_write_desc(ring->bd_base + off, d);
+ }
+
+ /* Allocate completion memory */
+ ring->cmpl_base = dma_pool_alloc(ring->mbox->cmpl_pool,
+ GFP_KERNEL, &ring->cmpl_dma_base);
+ if (!ring->cmpl_base) {
+ dev_err(ring->mbox->dev, "can't allocate completion memory\n");
+ ret = -ENOMEM;
+ goto fail_free_bd_memory;
+ }
+ memset(ring->cmpl_base, 0, RING_CMPL_SIZE);
+
+ /* Request IRQ */
+ if (ring->irq == UINT_MAX) {
+ dev_err(ring->mbox->dev, "ring IRQ not available\n");
+ ret = -ENODEV;
+ goto fail_free_cmpl_memory;
+ }
+ ret = request_threaded_irq(ring->irq,
+ flexrm_irq_event,
+ flexrm_irq_thread,
+ 0, dev_name(ring->mbox->dev), ring);
+ if (ret) {
+ dev_err(ring->mbox->dev, "failed to request ring IRQ\n");
+ goto fail_free_cmpl_memory;
+ }
+ ring->irq_requested = true;
+
+ /* Disable/inactivate ring */
+ writel_relaxed(0x0, ring->regs + RING_CONTROL);
+
+ /* Program BD start address */
+ val = BD_START_ADDR_VALUE(ring->bd_dma_base);
+ writel_relaxed(val, ring->regs + RING_BD_START_ADDR);
+
+ /* BD write pointer will be same as HW write pointer */
+ ring->bd_write_offset =
+ readl_relaxed(ring->regs + RING_BD_WRITE_PTR);
+ ring->bd_write_offset *= RING_DESC_SIZE;
+
+ /* Program completion start address */
+ val = CMPL_START_ADDR_VALUE(ring->cmpl_dma_base);
+ writel_relaxed(val, ring->regs + RING_CMPL_START_ADDR);
+
+ /* Ensure last pending message is cleared */
+ ring->last_pending_msg = NULL;
+
+ /* Completion read pointer will be same as HW write pointer */
+ ring->cmpl_read_offset =
+ readl_relaxed(ring->regs + RING_CMPL_WRITE_PTR);
+ ring->cmpl_read_offset *= RING_DESC_SIZE;
+
+ /* Read ring Tx, Rx, and Outstanding counts to clear */
+ readl_relaxed(ring->regs + RING_NUM_REQ_RECV_LS);
+ readl_relaxed(ring->regs + RING_NUM_REQ_RECV_MS);
+ readl_relaxed(ring->regs + RING_NUM_REQ_TRANS_LS);
+ readl_relaxed(ring->regs + RING_NUM_REQ_TRANS_MS);
+ readl_relaxed(ring->regs + RING_NUM_REQ_OUTSTAND);
+
+ /* Configure RING_MSI_CONTROL */
+ val = 0;
+ val |= (ring->msi_timer_val << MSI_TIMER_VAL_SHIFT);
+ val |= BIT(MSI_ENABLE_SHIFT);
+ val |= (ring->msi_count_threshold & MSI_COUNT_MASK) << MSI_COUNT_SHIFT;
+ writel_relaxed(val, ring->regs + RING_MSI_CONTROL);
+
+ /* Enable/activate ring */
+ val = BIT(CONTROL_ACTIVE_SHIFT);
+ writel_relaxed(val, ring->regs + RING_CONTROL);
+
+ return 0;
+
+fail_free_cmpl_memory:
+ dma_pool_free(ring->mbox->cmpl_pool,
+ ring->cmpl_base, ring->cmpl_dma_base);
+ ring->cmpl_base = NULL;
+fail_free_bd_memory:
+ dma_pool_free(ring->mbox->bd_pool,
+ ring->bd_base, ring->bd_dma_base);
+ ring->bd_base = NULL;
+fail:
+ return ret;
+}
+
+static void flexrm_shutdown(struct mbox_chan *chan)
+{
+ u32 reqid;
+ unsigned int timeout;
+ struct brcm_message *msg;
+ struct flexrm_ring *ring = chan->con_priv;
+
+ /* Disable/inactivate ring */
+ writel_relaxed(0x0, ring->regs + RING_CONTROL);
+
+ /* Flush ring with timeout of 1s */
+ timeout = 1000;
+ writel_relaxed(BIT(CONTROL_FLUSH_SHIFT),
+ ring->regs + RING_CONTROL);
+ do {
+ if (readl_relaxed(ring->regs + RING_FLUSH_DONE) &
+ FLUSH_DONE_MASK)
+ break;
+ mdelay(1);
+ } while (timeout--);
+
+ /* Abort all in-flight requests */
+ for (reqid = 0; reqid < RING_MAX_REQ_COUNT; reqid++) {
+ msg = ring->requests[reqid];
+ if (!msg)
+ continue;
+
+ /* Release reqid for recycling */
+ ring->requests[reqid] = NULL;
+ ida_simple_remove(&ring->requests_ida, reqid);
+
+ /* Unmap DMA mappings */
+ flexrm_dma_unmap(ring->mbox->dev, msg);
+
+ /* Give-back message to mailbox client */
+ msg->error = -EIO;
+ mbox_chan_received_data(chan, msg);
+ }
+
+ /* Release IRQ */
+ if (ring->irq_requested) {
+ free_irq(ring->irq, ring);
+ ring->irq_requested = false;
+ }
+
+ /* Free-up completion descriptor ring */
+ if (ring->cmpl_base) {
+ dma_pool_free(ring->mbox->cmpl_pool,
+ ring->cmpl_base, ring->cmpl_dma_base);
+ ring->cmpl_base = NULL;
+ }
+
+ /* Free-up BD descriptor ring */
+ if (ring->bd_base) {
+ dma_pool_free(ring->mbox->bd_pool,
+ ring->bd_base, ring->bd_dma_base);
+ ring->bd_base = NULL;
+ }
+}
+
+static bool flexrm_last_tx_done(struct mbox_chan *chan)
+{
+ bool ret;
+ unsigned long flags;
+ struct flexrm_ring *ring = chan->con_priv;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ ret = (ring->last_pending_msg) ? false : true;
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ return ret;
+}
+
+static const struct mbox_chan_ops flexrm_mbox_chan_ops = {
+ .send_data = flexrm_send_data,
+ .startup = flexrm_startup,
+ .shutdown = flexrm_shutdown,
+ .last_tx_done = flexrm_last_tx_done,
+ .peek_data = flexrm_peek_data,
+};
+
+static void flexrm_mbox_msi_write(struct msi_desc *desc, struct msi_msg *msg)
+{
+ struct device *dev = msi_desc_to_dev(desc);
+ struct flexrm_mbox *mbox = dev_get_drvdata(dev);
+ struct flexrm_ring *ring = &mbox->rings[desc->platform.msi_index];
+
+ /* Configure per-Ring MSI registers */
+ writel_relaxed(msg->address_lo, ring->regs + RING_MSI_ADDR_LS);
+ writel_relaxed(msg->address_hi, ring->regs + RING_MSI_ADDR_MS);
+ writel_relaxed(msg->data, ring->regs + RING_MSI_DATA_VALUE);
+}
+
+static struct mbox_chan *flexrm_mbox_of_xlate(struct mbox_controller *cntlr,
+ const struct of_phandle_args *pa)
+{
+ struct mbox_chan *chan;
+ struct flexrm_ring *ring;
+
+ if (pa->args_count < 3)
+ return ERR_PTR(-EINVAL);
+
+ if (pa->args[0] >= cntlr->num_chans)
+ return ERR_PTR(-ENOENT);
+
+ if (pa->args[1] > MSI_COUNT_MASK)
+ return ERR_PTR(-EINVAL);
+
+ if (pa->args[2] > MSI_TIMER_VAL_MASK)
+ return ERR_PTR(-EINVAL);
+
+ chan = &cntlr->chans[pa->args[0]];
+ ring = chan->con_priv;
+ ring->msi_count_threshold = pa->args[1];
+ ring->msi_timer_val = pa->args[2];
+
+ return chan;
+}
+
+static int flexrm_mbox_probe(struct platform_device *pdev)
+{
+ int index, ret = 0;
+ void __iomem *regs;
+ void __iomem *regs_end;
+ struct msi_desc *desc;
+ struct resource *iomem;
+ struct flexrm_ring *ring;
+ struct flexrm_mbox *mbox;
+ struct device *dev = &pdev->dev;
+
+ /* Allocate driver mailbox struct */
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ mbox->dev = dev;
+ platform_set_drvdata(pdev, mbox);
+
+ /* Get resource for registers */
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem || (resource_size(iomem) < RING_REGS_SIZE)) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ /* Map registers of all rings */
+ mbox->regs = devm_ioremap_resource(&pdev->dev, iomem);
+ if (IS_ERR(mbox->regs)) {
+ ret = PTR_ERR(mbox->regs);
+ dev_err(&pdev->dev, "Failed to remap mailbox regs: %d\n", ret);
+ goto fail;
+ }
+ regs_end = mbox->regs + resource_size(iomem);
+
+ /* Scan and count available rings */
+ mbox->num_rings = 0;
+ for (regs = mbox->regs; regs < regs_end; regs += RING_REGS_SIZE) {
+ if (readl_relaxed(regs + RING_VER) == RING_VER_MAGIC)
+ mbox->num_rings++;
+ }
+ if (!mbox->num_rings) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ /* Allocate driver ring structs */
+ ring = devm_kcalloc(dev, mbox->num_rings, sizeof(*ring), GFP_KERNEL);
+ if (!ring) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ mbox->rings = ring;
+
+ /* Initialize members of driver ring structs */
+ regs = mbox->regs;
+ for (index = 0; index < mbox->num_rings; index++) {
+ ring = &mbox->rings[index];
+ ring->num = index;
+ ring->mbox = mbox;
+ while ((regs < regs_end) &&
+ (readl_relaxed(regs + RING_VER) != RING_VER_MAGIC))
+ regs += RING_REGS_SIZE;
+ if (regs_end <= regs) {
+ ret = -ENODEV;
+ goto fail;
+ }
+ ring->regs = regs;
+ regs += RING_REGS_SIZE;
+ ring->irq = UINT_MAX;
+ ring->irq_requested = false;
+ ring->msi_timer_val = MSI_TIMER_VAL_MASK;
+ ring->msi_count_threshold = 0x1;
+ ida_init(&ring->requests_ida);
+ memset(ring->requests, 0, sizeof(ring->requests));
+ ring->bd_base = NULL;
+ ring->bd_dma_base = 0;
+ ring->cmpl_base = NULL;
+ ring->cmpl_dma_base = 0;
+ spin_lock_init(&ring->lock);
+ ring->last_pending_msg = NULL;
+ ring->cmpl_read_offset = 0;
+ }
+
+ /* FlexRM is capable of 40-bit physical addresses only */
+ mbox->dma_mask = DMA_BIT_MASK(40);
+ dev->dma_mask = &mbox->dma_mask;
+
+ /* Create DMA pool for ring BD memory */
+ mbox->bd_pool = dma_pool_create("bd", dev, RING_BD_SIZE,
+ 1 << RING_BD_ALIGN_ORDER, 0);
+ if (!mbox->bd_pool) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* Create DMA pool for ring completion memory */
+ mbox->cmpl_pool = dma_pool_create("cmpl", dev, RING_CMPL_SIZE,
+ 1 << RING_CMPL_ALIGN_ORDER, 0);
+ if (!mbox->cmpl_pool) {
+ ret = -ENOMEM;
+ goto fail_destroy_bd_pool;
+ }
+
+ /* Allocate platform MSIs for each ring */
+ ret = platform_msi_domain_alloc_irqs(dev, mbox->num_rings,
+ flexrm_mbox_msi_write);
+ if (ret)
+ goto fail_destroy_cmpl_pool;
+
+ /* Save alloced IRQ numbers for each ring */
+ for_each_msi_entry(desc, dev) {
+ ring = &mbox->rings[desc->platform.msi_index];
+ ring->irq = desc->irq;
+ }
+
+ /* Initialize mailbox controller */
+ mbox->controller.txdone_irq = false;
+ mbox->controller.txdone_poll = true;
+ mbox->controller.txpoll_period = 1;
+ mbox->controller.ops = &flexrm_mbox_chan_ops;
+ mbox->controller.dev = dev;
+ mbox->controller.num_chans = mbox->num_rings;
+ mbox->controller.of_xlate = flexrm_mbox_of_xlate;
+ mbox->controller.chans = devm_kcalloc(dev, mbox->num_rings,
+ sizeof(*mbox->controller.chans), GFP_KERNEL);
+ if (!mbox->controller.chans) {
+ ret = -ENOMEM;
+ goto fail_free_msis;
+ }
+ for (index = 0; index < mbox->num_rings; index++)
+ mbox->controller.chans[index].con_priv = &mbox->rings[index];
+
+ /* Register mailbox controller */
+ ret = mbox_controller_register(&mbox->controller);
+ if (ret)
+ goto fail_free_msis;
+
+ dev_info(dev, "registered flexrm mailbox with %d channels\n",
+ mbox->controller.num_chans);
+
+ return 0;
+
+fail_free_msis:
+ platform_msi_domain_free_irqs(dev);
+fail_destroy_cmpl_pool:
+ dma_pool_destroy(mbox->cmpl_pool);
+fail_destroy_bd_pool:
+ dma_pool_destroy(mbox->bd_pool);
+fail:
+ return ret;
+}
+
+static int flexrm_mbox_remove(struct platform_device *pdev)
+{
+ int index;
+ struct device *dev = &pdev->dev;
+ struct flexrm_ring *ring;
+ struct flexrm_mbox *mbox = platform_get_drvdata(pdev);
+
+ mbox_controller_unregister(&mbox->controller);
+
+ platform_msi_domain_free_irqs(dev);
+
+ dma_pool_destroy(mbox->cmpl_pool);
+ dma_pool_destroy(mbox->bd_pool);
+
+ for (index = 0; index < mbox->num_rings; index++) {
+ ring = &mbox->rings[index];
+ ida_destroy(&ring->requests_ida);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id flexrm_mbox_of_match[] = {
+ { .compatible = "brcm,flexrm-mbox", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, flexrm_mbox_of_match);
+
+static struct platform_driver flexrm_mbox_driver = {
+ .driver = {
+ .name = "brcm-flexrm-mbox",
+ .of_match_table = flexrm_mbox_of_match,
+ },
+ .probe = flexrm_mbox_probe,
+ .remove = flexrm_mbox_remove,
+};
+module_platform_driver(flexrm_mbox_driver);
+
+MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom FlexRM mailbox driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mailbox/brcm-message.h b/include/linux/mailbox/brcm-message.h
index 6b55c93..f03bbdd 100644
--- a/include/linux/mailbox/brcm-message.h
+++ b/include/linux/mailbox/brcm-message.h
@@ -16,6 +16,7 @@
enum brcm_message_type {
BRCM_MESSAGE_UNKNOWN = 0,
+ BRCM_MESSAGE_BATCH,
BRCM_MESSAGE_SPU,
BRCM_MESSAGE_SBA,
BRCM_MESSAGE_MAX,
@@ -29,18 +30,21 @@ struct brcm_sba_command {
#define BRCM_SBA_CMD_HAS_RESP BIT(3)
#define BRCM_SBA_CMD_HAS_OUTPUT BIT(4)
u64 flags;
- dma_addr_t input;
- size_t input_len;
dma_addr_t resp;
size_t resp_len;
- dma_addr_t output;
- size_t output_len;
+ dma_addr_t data;
+ size_t data_len;
};
struct brcm_message {
enum brcm_message_type type;
union {
struct {
+ struct brcm_message *msgs;
+ unsigned int msgs_queued;
+ unsigned int msgs_count;
+ } batch;
+ struct {
struct scatterlist *src;
struct scatterlist *dst;
} spu;
--
2.7.4
^ permalink raw reply related
* [PATCH 0/2] Broadcom FlexRM ring manager support
From: Anup Patel @ 2016-11-25 4:35 UTC (permalink / raw)
To: Jassi Brar, Rob Herring
Cc: Mark Rutland, Ray Jui, Scott Branden, Pramod KUMAR, Rob Rice,
devicetree, linux-kernel, linux-arm-kernel,
bcm-kernel-feedback-list, Anup Patel
The Broadcom FlexRM ring manager provides producer-consumer style
ring interface for offload engines on Broadcom iProc SoCs. We can
have one or more instances of Broadcom FlexRM ring manager in a SoC.
This patchset adds a mailbox driver for Broadcom FlexRM ring manager
which can be used by offload engine drivers as mailbox clients.
The Broadcom FlexRM mailbox driver is feature complete for RAID and
Crypto offload engines. We will have incremental patches in-future
for ring-level statistics using debugfs and minor optimizations.
This patchset is based on Linux-4.9-rc6 and it is also available
at flexrm-v1 branch of https://github.com/Broadcom/arm64-linux.git
Anup Patel (2):
mailbox: Add driver for Broadcom FlexRM ring manager
dt-bindings: Add DT bindings info for FlexRM mailbox driver
.../bindings/mailbox/brcm,flexrm-mbox.txt | 60 ++
drivers/mailbox/Kconfig | 11 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/mailbox-flexrm/Makefile | 6 +
drivers/mailbox/mailbox-flexrm/flexrm-desc.c | 764 +++++++++++++++++++
drivers/mailbox/mailbox-flexrm/flexrm-desc.h | 47 ++
drivers/mailbox/mailbox-flexrm/flexrm-main.c | 829 +++++++++++++++++++++
include/linux/mailbox/brcm-message.h | 12 +-
8 files changed, 1727 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mailbox/brcm,flexrm-mbox.txt
create mode 100644 drivers/mailbox/mailbox-flexrm/Makefile
create mode 100644 drivers/mailbox/mailbox-flexrm/flexrm-desc.c
create mode 100644 drivers/mailbox/mailbox-flexrm/flexrm-desc.h
create mode 100644 drivers/mailbox/mailbox-flexrm/flexrm-main.c
--
2.7.4
^ permalink raw reply
* Re: [PATCH v9 3/4] dtc: Plugin and fixup support
From: David Gibson @ 2016-11-25 4:11 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Jon Loeliger, Grant Likely, Frank Rowand, Rob Herring, Jan Luebbe,
Sascha Hauer, Phil Elwell, Simon Glass, Maxime Ripard,
Thomas Petazzoni, Boris Brezillon, Antoine Tenart, Stephen Boyd,
Devicetree Compiler, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1479990693-14260-4-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 31134 bytes --]
On Thu, Nov 24, 2016 at 02:31:32PM +0200, Pantelis Antoniou wrote:
> This patch enable the generation of symbols & local fixup information
> for trees compiled with the -@ (--symbols) option.
>
> Using this patch labels in the tree and their users emit information
> in __symbols__ and __local_fixups__ nodes.
>
> The __fixups__ node make possible the dynamic resolution of phandle
> references which are present in the plugin tree but lie in the
> tree that are applying the overlay against.
>
> While there is a new magic number for dynamic device tree/overlays blobs
> it is by default disabled. This is in order to give time for DT blob
> methods to be updated.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
> Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Signed-off-by: Jan Luebbe <jlu-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> ---
> Documentation/manual.txt | 25 +++++-
> checks.c | 8 +-
> dtc-lexer.l | 5 ++
> dtc-parser.y | 49 +++++++++--
> dtc.c | 39 +++++++-
> dtc.h | 20 ++++-
> fdtdump.c | 2 +-
> flattree.c | 17 ++--
> fstree.c | 2 +-
> libfdt/fdt.c | 2 +-
> libfdt/fdt.h | 3 +-
> livetree.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++-
> tests/mangle-layout.c | 7 +-
> treesource.c | 7 +-
> 14 files changed, 380 insertions(+), 31 deletions(-)
>
> diff --git a/Documentation/manual.txt b/Documentation/manual.txt
> index 398de32..65fbf09 100644
> --- a/Documentation/manual.txt
> +++ b/Documentation/manual.txt
> @@ -119,6 +119,24 @@ Options:
> Make space for <number> reserve map entries
> Relevant for dtb and asm output only.
>
> + -@
> + Generates a __symbols__ node at the root node of the resulting blob
> + for any node labels used, and for any local references using phandles
> + it also generates a __local_fixups__ node that tracks them.
> +
> + When using the /plugin/ tag all unresolved label references to
> + be tracked in the __fixups__ node, making dynamic resolution possible.
> +
> + -A
> + Generate automatically aliases for all node labels. This is similar to
> + the -@ option (the __symbols__ node contain identical information) but
> + the semantics are slightly different since no phandles are automatically
> + generated for labeled nodes.
> +
> + -M
> + Generate blobs with the new FDT magic number. By default blobs with the
> + standard FDT magic number are generated.
First, this description is incomplete since -M *only* affects the
magic number for /plugin/ input, not in other cases. Second, the
default is the wrong way around. If we make old-style the default,
then new-style will never be used, which defeats the purpose.
> +
> -S <bytes>
> Ensure the blob at least <bytes> long, adding additional
> space if needed.
> @@ -146,13 +164,18 @@ Additionally, dtc performs various sanity checks on the tree.
> Here is a very rough overview of the layout of a DTS source file:
>
>
> - sourcefile: list_of_memreserve devicetree
> + sourcefile: versioninfo plugindecl list_of_memreserve devicetree
>
> memreserve: label 'memreserve' ADDR ADDR ';'
> | label 'memreserve' ADDR '-' ADDR ';'
>
> devicetree: '/' nodedef
>
> + versioninfo: '/' 'dts-v1' '/' ';'
> +
> + plugindecl: '/' 'plugin' '/' ';'
> + | /* empty */
> +
> nodedef: '{' list_of_property list_of_subnode '}' ';'
>
> property: label PROPNAME '=' propdata ';'
> diff --git a/checks.c b/checks.c
> index 609975a..bc03d42 100644
> --- a/checks.c
> +++ b/checks.c
> @@ -486,8 +486,12 @@ static void fixup_phandle_references(struct check *c, struct boot_info *bi,
>
> refnode = get_node_by_ref(dt, m->ref);
> if (! refnode) {
> - FAIL(c, "Reference to non-existent node or label \"%s\"\n",
> - m->ref);
> + if (!(bi->versionflags & VF_PLUGIN))
> + FAIL(c, "Reference to non-existent node or "
> + "label \"%s\"\n", m->ref);
> + else /* mark the entry as unresolved */
> + *((cell_t *)(prop->val.val + m->offset)) =
> + cpu_to_fdt32(0xffffffff);
> continue;
> }
>
> diff --git a/dtc-lexer.l b/dtc-lexer.l
> index 790fbf6..40bbc87 100644
> --- a/dtc-lexer.l
> +++ b/dtc-lexer.l
> @@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
> return DT_V1;
> }
>
> +<*>"/plugin/" {
> + DPRINT("Keyword: /plugin/\n");
> + return DT_PLUGIN;
> + }
> +
> <*>"/memreserve/" {
> DPRINT("Keyword: /memreserve/\n");
> BEGIN_DEFAULT();
> diff --git a/dtc-parser.y b/dtc-parser.y
> index 14aaf2e..4afc592 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -19,6 +19,7 @@
> */
> %{
> #include <stdio.h>
> +#include <inttypes.h>
>
> #include "dtc.h"
> #include "srcpos.h"
> @@ -33,6 +34,9 @@ extern void yyerror(char const *s);
>
> extern struct boot_info *the_boot_info;
> extern bool treesource_error;
> +
> +/* temporary while the tree is not built */
> +static unsigned int the_versionflags;
Hrm. Using a global during parsing is pretty dangerous - it makes
assumptions about the order in which bison will execute semantic
actions that may not always be correct.
It'll probably work in practice, so I *might* be convinced it's
adequate for a first cut. I'm a bit reluctant though, since I suspect
once merged it will become entrenched.
The correct way to handle this, IMO, is not to ever attempt to apply
overlays during the parse. Basically, we'd change the overall
structure so that the output from the parser is not a single tree, but
a list of overlays / fragments. Then, once the parse is complete, so
versioninfo (which could now become a member of bootinfo) is well
defined, we either apply the fragments in place (base tree) or encode
them into the overlay structure (plugin mode).
See https://github.com/dgibson/dtc/tree/overlay for some incomplete
work I did in this direction.
In addition to not making unsafe assumptions about parser operation, I
think this will also allow for better error reporting. It also moves
more code into plain-old-C instead of potentially hard to follow bison
code fragments.
> %}
>
> %union {
> @@ -52,9 +56,11 @@ extern bool treesource_error;
> struct node *nodelist;
> struct reserve_info *re;
> uint64_t integer;
> + unsigned int flags;
> }
>
> %token DT_V1
> +%token DT_PLUGIN
> %token DT_MEMRESERVE
> %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
> %token DT_BITS
> @@ -71,6 +77,8 @@ extern bool treesource_error;
>
> %type <data> propdata
> %type <data> propdataprefix
> +%type <flags> versioninfo
> +%type <flags> plugindecl
> %type <re> memreserve
> %type <re> memreserves
> %type <array> arrayprefix
> @@ -101,16 +109,36 @@ extern bool treesource_error;
> %%
>
> sourcefile:
> - v1tag memreserves devicetree
> + versioninfo plugindecl memreserves devicetree
> + {
> + the_boot_info = build_boot_info($1 | $2, $3, $4,
> + guess_boot_cpuid($4));
> + }
> + ;
> +
> +versioninfo:
> + v1tag
> {
> - the_boot_info = build_boot_info($2, $3,
> - guess_boot_cpuid($3));
> + the_versionflags |= VF_DT_V1;
> + $$ = the_versionflags;
> }
> ;
>
> v1tag:
> DT_V1 ';'
> + | DT_V1
> | DT_V1 ';' v1tag
> +
> +plugindecl:
> + DT_PLUGIN ';'
> + {
> + the_versionflags |= VF_PLUGIN;
> + $$ = VF_PLUGIN;
> + }
> + | /* empty */
> + {
> + $$ = 0;
> + }
> ;
>
> memreserves:
> @@ -161,10 +189,14 @@ devicetree:
> {
> struct node *target = get_node_by_ref($1, $2);
>
> - if (target)
> + if (target) {
> merge_nodes(target, $3);
> - else
> - ERROR(&@2, "Label or path %s not found", $2);
> + } else {
> + if (the_versionflags & VF_PLUGIN)
> + add_orphan_node($1, $3, $2);
> + else
> + ERROR(&@2, "Label or path %s not found", $2);
> + }
> $$ = $1;
> }
> | devicetree DT_DEL_NODE DT_REF ';'
> @@ -179,6 +211,11 @@ devicetree:
>
> $$ = $1;
> }
> + | /* empty */
> + {
> + /* build empty node */
> + $$ = name_node(build_node(NULL, NULL), "");
> + }
> ;
>
> nodedef:
> diff --git a/dtc.c b/dtc.c
> index 9dcf640..a654267 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -32,6 +32,9 @@ int minsize; /* Minimum blob size */
> int padsize; /* Additional padding to blob */
> int alignsize; /* Additional padding to blob accroding to the alignsize */
> int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
> +int symbol_fixup_support; /* enable symbols & fixup support */
> +int auto_label_aliases; /* auto generate labels -> aliases */
> +int new_magic; /* use new FDT magic values for objects */
>
> static int is_power_of_2(int x)
> {
> @@ -59,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
> #define FDT_VERSION(version) _FDT_VERSION(version)
> #define _FDT_VERSION(version) #version
> static const char usage_synopsis[] = "dtc [options] <input file>";
> -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:hv";
> +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AMhv";
> static struct option const usage_long_opts[] = {
> {"quiet", no_argument, NULL, 'q'},
> {"in-format", a_argument, NULL, 'I'},
> @@ -78,6 +81,9 @@ static struct option const usage_long_opts[] = {
> {"phandle", a_argument, NULL, 'H'},
> {"warning", a_argument, NULL, 'W'},
> {"error", a_argument, NULL, 'E'},
> + {"symbols", no_argument, NULL, '@'},
> + {"auto-alias", no_argument, NULL, 'A'},
> + {"new-magic", no_argument, NULL, 'M'},
> {"help", no_argument, NULL, 'h'},
> {"version", no_argument, NULL, 'v'},
> {NULL, no_argument, NULL, 0x0},
> @@ -109,6 +115,9 @@ static const char * const usage_opts_help[] = {
> "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
> "\n\tEnable/disable warnings (prefix with \"no-\")",
> "\n\tEnable/disable errors (prefix with \"no-\")",
> + "\n\tEnable symbols/fixup support",
> + "\n\tEnable auto-alias of labels",
> + "\n\tUse new blog magic value",
> "\n\tPrint this help and exit",
> "\n\tPrint version and exit",
> NULL,
> @@ -153,7 +162,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
> fclose(f);
>
> magic = fdt32_to_cpu(magic);
> - if (magic == FDT_MAGIC)
> + if (magic == FDT_MAGIC || magic == FDT_MAGIC_DTBO)
> return "dtb";
>
> return guess_type_by_name(fname, fallback);
> @@ -172,6 +181,7 @@ int main(int argc, char *argv[])
> FILE *outf = NULL;
> int outversion = DEFAULT_FDT_VERSION;
> long long cmdline_boot_cpuid = -1;
> + fdt32_t out_magic = FDT_MAGIC;
>
> quiet = 0;
> reservenum = 0;
> @@ -249,6 +259,16 @@ int main(int argc, char *argv[])
> parse_checks_option(false, true, optarg);
> break;
>
> + case '@':
> + symbol_fixup_support = 1;
> + break;
> + case 'A':
> + auto_label_aliases = 1;
> + break;
> + case 'M':
> + new_magic = 1;
> + break;
> +
> case 'h':
> usage(NULL);
> default:
> @@ -306,6 +326,14 @@ int main(int argc, char *argv[])
> fill_fullpaths(bi->dt, "");
> process_checks(force, bi);
>
> + if (auto_label_aliases)
> + generate_label_tree(bi->dt, "aliases", false);
> +
> + if (symbol_fixup_support) {
> + generate_label_tree(bi->dt, "__symbols__", true);
> + generate_fixups_tree(bi->dt);
> + }
> +
> if (sort)
> sort_tree(bi);
>
> @@ -318,12 +346,15 @@ int main(int argc, char *argv[])
> outname, strerror(errno));
> }
>
> + if (new_magic && (bi->versionflags & VF_PLUGIN))
> + out_magic = FDT_MAGIC_DTBO;
> +
> if (streq(outform, "dts")) {
> dt_to_source(outf, bi);
> } else if (streq(outform, "dtb")) {
> - dt_to_blob(outf, bi, outversion);
> + dt_to_blob(outf, bi, out_magic, outversion);
> } else if (streq(outform, "asm")) {
> - dt_to_asm(outf, bi, outversion);
> + dt_to_asm(outf, bi, out_magic, outversion);
> } else if (streq(outform, "null")) {
> /* do nothing */
> } else {
> diff --git a/dtc.h b/dtc.h
> index 32009bc..889b8f8 100644
> --- a/dtc.h
> +++ b/dtc.h
> @@ -55,6 +55,9 @@ extern int minsize; /* Minimum blob size */
> extern int padsize; /* Additional padding to blob */
> extern int alignsize; /* Additional padding to blob accroding to the alignsize */
> extern int phandle_format; /* Use linux,phandle or phandle properties */
> +extern int symbol_fixup_support;/* enable symbols & fixup support */
> +extern int auto_label_aliases; /* auto generate labels -> aliases */
> +extern int new_magic; /* use new FDT magic values for objects */
>
> #define PHANDLE_LEGACY 0x1
> #define PHANDLE_EPAPR 0x2
> @@ -195,6 +198,7 @@ struct node *build_node_delete(void);
> struct node *name_node(struct node *node, char *name);
> struct node *chain_node(struct node *first, struct node *list);
> struct node *merge_nodes(struct node *old_node, struct node *new_node);
> +void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
>
> void add_property(struct node *node, struct property *prop);
> void delete_property_by_name(struct node *node, char *name);
> @@ -202,6 +206,8 @@ void delete_property(struct property *prop);
> void add_child(struct node *parent, struct node *child);
> void delete_node_by_name(struct node *parent, char *name);
> void delete_node(struct node *node);
> +void append_to_property(struct node *node,
> + char *name, const void *data, int len);
>
> const char *get_unitname(struct node *node);
> struct property *get_property(struct node *node, const char *propname);
> @@ -237,14 +243,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
>
>
> struct boot_info {
> + unsigned int versionflags;
> struct reserve_info *reservelist;
> struct node *dt; /* the device tree */
> uint32_t boot_cpuid_phys;
> };
>
> -struct boot_info *build_boot_info(struct reserve_info *reservelist,
> +/* version flags definitions */
> +#define VF_DT_V1 0x0001 /* /dts-v1/ */
> +#define VF_PLUGIN 0x0002 /* /plugin/ */
> +
> +struct boot_info *build_boot_info(unsigned int versionflags,
> + struct reserve_info *reservelist,
> struct node *tree, uint32_t boot_cpuid_phys);
> void sort_tree(struct boot_info *bi);
> +void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph);
> +void generate_fixups_tree(struct node *dt);
>
> /* Checks */
>
> @@ -253,8 +267,8 @@ void process_checks(bool force, struct boot_info *bi);
>
> /* Flattened trees */
>
> -void dt_to_blob(FILE *f, struct boot_info *bi, int version);
> -void dt_to_asm(FILE *f, struct boot_info *bi, int version);
> +void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
> +void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
>
> struct boot_info *dt_from_blob(const char *fname);
>
> diff --git a/fdtdump.c b/fdtdump.c
> index a9a2484..dd63ac2 100644
> --- a/fdtdump.c
> +++ b/fdtdump.c
> @@ -201,7 +201,7 @@ int main(int argc, char *argv[])
> p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
> if (!p)
> break;
> - if (fdt_magic(p) == FDT_MAGIC) {
> + if (fdt_magic(p) == FDT_MAGIC || fdt_magic(p) == FDT_MAGIC_DTBO) {
> /* try and validate the main struct */
> off_t this_len = endp - p;
> fdt32_t max_version = 17;
> diff --git a/flattree.c b/flattree.c
> index a9d9520..57d76cf 100644
> --- a/flattree.c
> +++ b/flattree.c
> @@ -335,6 +335,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
> }
>
> static void make_fdt_header(struct fdt_header *fdt,
> + fdt32_t magic,
> struct version_info *vi,
> int reservesize, int dtsize, int strsize,
> int boot_cpuid_phys)
> @@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt,
>
> memset(fdt, 0xff, sizeof(*fdt));
>
> - fdt->magic = cpu_to_fdt32(FDT_MAGIC);
> + fdt->magic = cpu_to_fdt32(magic);
> fdt->version = cpu_to_fdt32(vi->version);
> fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
>
> @@ -366,7 +367,7 @@ static void make_fdt_header(struct fdt_header *fdt,
> fdt->size_dt_struct = cpu_to_fdt32(dtsize);
> }
>
> -void dt_to_blob(FILE *f, struct boot_info *bi, int version)
> +void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
> {
> struct version_info *vi = NULL;
> int i;
> @@ -390,7 +391,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
> reservebuf = flatten_reserve_list(bi->reservelist, vi);
>
> /* Make header */
> - make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
> + make_fdt_header(&fdt, magic, vi, reservebuf.len, dtbuf.len, strbuf.len,
> bi->boot_cpuid_phys);
>
> /*
> @@ -467,7 +468,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
> }
> }
>
> -void dt_to_asm(FILE *f, struct boot_info *bi, int version)
> +void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
> {
> struct version_info *vi = NULL;
> int i;
> @@ -830,6 +831,7 @@ struct boot_info *dt_from_blob(const char *fname)
> struct node *tree;
> uint32_t val;
> int flags = 0;
> + unsigned int versionflags = VF_DT_V1;
>
> f = srcfile_relative_open(fname, NULL);
>
> @@ -845,9 +847,12 @@ struct boot_info *dt_from_blob(const char *fname)
> }
>
> magic = fdt32_to_cpu(magic);
> - if (magic != FDT_MAGIC)
> + if (magic != FDT_MAGIC && magic != FDT_MAGIC_DTBO)
> die("Blob has incorrect magic number\n");
>
> + if (magic == FDT_MAGIC_DTBO)
> + versionflags |= VF_PLUGIN;
> +
> rc = fread(&totalsize, sizeof(totalsize), 1, f);
> if (ferror(f))
> die("Error reading DT blob size: %s\n", strerror(errno));
> @@ -942,5 +947,5 @@ struct boot_info *dt_from_blob(const char *fname)
>
> fclose(f);
>
> - return build_boot_info(reservelist, tree, boot_cpuid_phys);
> + return build_boot_info(versionflags, reservelist, tree, boot_cpuid_phys);
> }
> diff --git a/fstree.c b/fstree.c
> index 6d1beec..54f520b 100644
> --- a/fstree.c
> +++ b/fstree.c
> @@ -86,6 +86,6 @@ struct boot_info *dt_from_fs(const char *dirname)
> tree = read_fstree(dirname);
> tree = name_node(tree, "");
>
> - return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
> + return build_boot_info(VF_DT_V1, NULL, tree, guess_boot_cpuid(tree));
> }
>
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index 22286a1..28d422c 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -57,7 +57,7 @@
>
> int fdt_check_header(const void *fdt)
> {
> - if (fdt_magic(fdt) == FDT_MAGIC) {
> + if (fdt_magic(fdt) == FDT_MAGIC || fdt_magic(fdt) == FDT_MAGIC_DTBO) {
> /* Complete tree */
> if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
> return -FDT_ERR_BADVERSION;
> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
> index 526aedb..493cd55 100644
> --- a/libfdt/fdt.h
> +++ b/libfdt/fdt.h
> @@ -55,7 +55,7 @@
> #ifndef __ASSEMBLY__
>
> struct fdt_header {
> - fdt32_t magic; /* magic word FDT_MAGIC */
> + fdt32_t magic; /* magic word FDT_MAGIC[|_DTBO] */
> fdt32_t totalsize; /* total size of DT block */
> fdt32_t off_dt_struct; /* offset to structure */
> fdt32_t off_dt_strings; /* offset to strings */
> @@ -93,6 +93,7 @@ struct fdt_property {
> #endif /* !__ASSEMBLY */
>
> #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
> +#define FDT_MAGIC_DTBO 0xd00dfdb0 /* DTBO magic */
> #define FDT_TAGSIZE sizeof(fdt32_t)
>
> #define FDT_BEGIN_NODE 0x1 /* Start node: full name */
> diff --git a/livetree.c b/livetree.c
> index 3dc7559..1a2f4b1 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -216,6 +216,31 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
> return old_node;
> }
>
> +void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
> +{
> + static unsigned int next_orphan_fragment = 0;
> + struct node *node = xmalloc(sizeof(*node));
You shouldn't use a bare malloc() for a node. Use build_node() instead.
> + struct property *p;
> + struct data d = empty_data;
> + char *name;
> +
> + memset(node, 0, sizeof(*node));
> +
> + d = data_add_marker(d, REF_PHANDLE, ref);
> + d = data_append_integer(d, 0xffffffff, 32);
> +
> + p = build_property("target", d);
> + add_property(node, p);
> +
> + xasprintf(&name, "fragment@%u",
> + next_orphan_fragment++);
> + name_node(node, name);
> + name_node(new_node, "__overlay__");
> +
> + add_child(dt, node);
> + add_child(node, new_node);
> +}
> +
> struct node *chain_node(struct node *first, struct node *list)
> {
> assert(first->next_sibling == NULL);
> @@ -296,6 +321,23 @@ void delete_node(struct node *node)
> delete_labels(&node->labels);
> }
>
> +void append_to_property(struct node *node,
> + char *name, const void *data, int len)
> +{
> + struct data d;
> + struct property *p;
> +
> + p = get_property(node, name);
> + if (p) {
> + d = data_append_data(p->val, data, len);
> + p->val = d;
> + } else {
> + d = data_append_data(empty_data, data, len);
> + p = build_property(name, d);
> + add_property(node, p);
> + }
> +}
> +
> struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
> {
> struct reserve_info *new = xmalloc(sizeof(*new));
> @@ -335,12 +377,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
> return list;
> }
>
> -struct boot_info *build_boot_info(struct reserve_info *reservelist,
> +struct boot_info *build_boot_info(unsigned int versionflags,
> + struct reserve_info *reservelist,
> struct node *tree, uint32_t boot_cpuid_phys)
> {
> struct boot_info *bi;
>
> bi = xmalloc(sizeof(*bi));
> + bi->versionflags = versionflags;
> bi->reservelist = reservelist;
> bi->dt = tree;
> bi->boot_cpuid_phys = boot_cpuid_phys;
> @@ -709,3 +753,182 @@ void sort_tree(struct boot_info *bi)
> sort_reserve_entries(bi);
> sort_node(bi->dt);
> }
> +
> +/* utility helper to avoid code duplication */
> +static struct node *build_and_name_child_node(struct node *parent, char *name)
> +{
> + struct node *node;
> +
> + node = build_node(NULL, NULL);
> + name_node(node, xstrdup(name));
> + add_child(parent, node);
> +
> + return node;
> +}
> +
> +static void generate_label_tree_internal(struct node *dt, struct node *node,
> + struct node *an, bool allocph)
> +{
> + struct node *c;
> + struct property *p;
> + struct label *l;
> +
> + /* if if there are labels */
> + if (node->labels) {
> + /* now add the label in the node */
> + for_each_label(node->labels, l) {
> + /* check whether the label already exists */
> + p = get_property(an, l->label);
> + if (p) {
> + fprintf(stderr, "WARNING: label %s already"
> + " exists in /%s", l->label,
> + an->name);
> + continue;
> + }
> +
> + /* insert it */
> + p = build_property(l->label,
> + data_copy_escape_string(node->fullpath,
> + strlen(node->fullpath)));
Um.. what? The node path should absolutely not be an escape string.
It shouldn't contain escapes to begin with, and if it does, we
absolutely shouldn't be turning them into special characters here.
> + add_property(an, p);
> + }
> +
> + /* force allocation of a phandle for this node */
> + if (allocph)
> + (void)get_node_phandle(dt, node);
> + }
> +
> + for_each_child(node, c)
> + generate_label_tree_internal(dt, c, an, allocph);
> +}
> +
> +void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph)
> +{
> + struct node *an;
> +
> + for_each_child(dt, an)
> + if (streq(gen_node_name, an->name))
> + break;
> +
> + if (!an)
> + an = build_and_name_child_node(dt, gen_node_name);
> + if (!an)
> + die("Could not build label node /%s\n", gen_node_name);
> +
> + generate_label_tree_internal(dt, dt, an, allocph);
> +}
> +
> +static char *fixups_name = "__fixups__";
> +static char *local_fixups_name = "__local_fixups__";
I'd actually prefer #defines for these, and all-caps names, so it's
more obvious when they're used that these are global constants.
> +
> +static void add_fixup_entry(struct node *dt, struct node *node,
> + struct property *prop, struct marker *m)
> +{
> + struct node *fn; /* fixup node */
> + char *entry;
> +
> + /* m->ref can only be a REF_PHANDLE, but check anyway */
> + assert(m->type == REF_PHANDLE);
> +
> + /* fn is the node we're putting entries in */
> + fn = get_subnode(dt, fixups_name);
> + assert(fn != NULL);
> +
> + /* there shouldn't be any ':' in the arguments */
> + if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
> + die("arguments should not contain ':'\n");
> +
> + xasprintf(&entry, "%s:%s:%u",
> + node->fullpath, prop->name, m->offset);
> + append_to_property(fn, m->ref, entry, strlen(entry) + 1);
> +}
> +
> +static void add_local_fixup_entry(struct node *dt, struct node *node,
> + struct property *prop, struct marker *m,
> + struct node *refnode)
> +{
> + struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */
> + uint32_t value_32;
> + char *s, *e, *comp;
> + int len;
> +
> + /* fn is the node we're putting entries in */
> + lfn = get_subnode(dt, local_fixups_name);
> + assert(lfn != NULL);
> +
> + /* walk the path components creating nodes if they don't exist */
> + comp = xmalloc(strlen(node->fullpath) + 1);
> + /* start skipping the first / */
> + s = node->fullpath + 1;
> + wn = lfn;
> + while (*s) {
> + /* retrieve path component */
> + e = strchr(s, '/');
> + if (e == NULL)
> + e = s + strlen(s);
> + len = e - s;
> + memcpy(comp, s, len);
> + comp[len] = '\0';
> +
> + /* if no node exists, create it */
> + nwn = get_subnode(wn, comp);
> + if (!nwn)
> + nwn = build_and_name_child_node(wn, comp);
> + wn = nwn;
> +
> + /* last path component */
> + if (!*e)
> + break;
> +
> + /* next path component */
> + s = e + 1;
> + }
> + free(comp);
> +
> + value_32 = cpu_to_fdt32(m->offset);
> + append_to_property(wn, prop->name, &value_32, sizeof(value_32));
> +}
> +
> +static void generate_fixups_tree_internal(struct node *dt, struct node *node)
> +{
> + struct node *c;
> + struct property *prop;
> + struct marker *m;
> + struct node *refnode;
> +
> + for_each_property(node, prop) {
> + m = prop->val.markers;
> + for_each_marker_of_type(m, REF_PHANDLE) {
> + refnode = get_node_by_ref(dt, m->ref);
> + if (!refnode)
> + add_fixup_entry(dt, node, prop, m);
> + else
> + add_local_fixup_entry(dt, node, prop, m,
> + refnode);
> + }
> + }
> +
> + for_each_child(node, c)
> + generate_fixups_tree_internal(dt, c);
> +}
> +
> +void generate_fixups_tree(struct node *dt)
> +{
> + struct node *an;
> +
> + for_each_child(dt, an)
> + if (streq(fixups_name, an->name))
> + break;
> +
> + if (!an)
> + build_and_name_child_node(dt, fixups_name);
> +
> + for_each_child(dt, an)
> + if (streq(local_fixups_name, an->name))
> + break;
> +
> + if (!an)
> + build_and_name_child_node(dt, local_fixups_name);
> +
> + generate_fixups_tree_internal(dt, dt);
> +}
> diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c
> index a76e51e..d29ebc6 100644
> --- a/tests/mangle-layout.c
> +++ b/tests/mangle-layout.c
> @@ -42,7 +42,8 @@ static void expand_buf(struct bufstate *buf, int newsize)
> buf->size = newsize;
> }
>
> -static void new_header(struct bufstate *buf, int version, const void *fdt)
> +static void new_header(struct bufstate *buf, fdt32_t magic, int version,
> + const void *fdt)
> {
> int hdrsize;
>
> @@ -56,7 +57,7 @@ static void new_header(struct bufstate *buf, int version, const void *fdt)
> expand_buf(buf, hdrsize);
> memset(buf->buf, 0, hdrsize);
>
> - fdt_set_magic(buf->buf, FDT_MAGIC);
> + fdt_set_magic(buf->buf, magic);
> fdt_set_version(buf->buf, version);
> fdt_set_last_comp_version(buf->buf, 16);
> fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
> @@ -145,7 +146,7 @@ int main(int argc, char *argv[])
> if (fdt_version(fdt) < 17)
> CONFIG("Input tree must be v17");
>
> - new_header(&buf, version, fdt);
> + new_header(&buf, FDT_MAGIC, version, fdt);
>
> while (*blockorder) {
> add_block(&buf, version, *blockorder, fdt);
> diff --git a/treesource.c b/treesource.c
> index a55d1d1..75e920d 100644
> --- a/treesource.c
> +++ b/treesource.c
> @@ -267,7 +267,12 @@ void dt_to_source(FILE *f, struct boot_info *bi)
> {
> struct reserve_info *re;
>
> - fprintf(f, "/dts-v1/;\n\n");
> + fprintf(f, "/dts-v1/");
> +
> + if (bi->versionflags & VF_PLUGIN)
> + fprintf(f, " /plugin/");
> +
> + fprintf(f, ";\n\n");
I'm not sure this really makes sense. The /plugin/ tag triggers the
fixup construction and encoding of overlay fragments. But in an
incoming dtb, that processing has already been done once, doing it
again would not make sense. So I think the output should not have the
/plugin/ tag, even if the input did.
Unless, of course, you parsed the input into an explicit list of
overlays, then output it here again as a list of overlays, not the
encoded fragments. i.e. if this was the original tree:
/dts-v1/ /plugin/;
&somwhere {
name = "value";
};
then legitimately the output of -I dts -O dts could be either:
/dts-v1/ /plugin/;
&somwhere {
name = "value";
};
OR
/dts-v1/;
/ {
fragment@0 {
target = <0xffffffff>;
__overlay__{
name = "value";
};
};
__fixups__ {
somewhere = "/fragment@0:target:0";
};
};
But it doesn't make sense to combine the two: the second structure
with the "/plugin/" tag.
Another advantage of moving the overlay application out of the parser
is you can sanely produce either output, both of which could be useful
in the right circumstances. You can potentially even produce the
first output (or something close) from dtb input, with correct parsing
of the overlay structure on dtb input.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* GOOD DAY FRIEND
From: Mr. Piyush Gupta @ 2016-11-25 3:51 UTC (permalink / raw)
--
Dear Friend,
Good Day, I am Mr. Piyush Gupta as a (DBSHK) banker, I have funds worth
of $25.500,000.00 to secretly secure and transfer in to your account of
my late client who dead with next of kin, which i will like to invest in
profitable business in your country.
Please if you are interested to help me without betrayed me, do and
write me for more details. Here is my Email: infopiyushg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Regards,
Mr. Piyush Gupta.
(DBSHK)
Hong Kong.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 1/6] arm64: arch_timer: Add device tree binding for hisilicon-161601 erratum
From: Ding Tianhong @ 2016-11-25 3:18 UTC (permalink / raw)
To: Hanjun Guo, John Garry, catalin.marinas, will.deacon,
marc.zyngier, mark.rutland, oss, devicetree, shawnguo,
stuart.yoder, linux-arm-kernel, linuxarm
In-Reply-To: <58379AA4.6030401@linaro.org>
OK
On 2016/11/25 9:57, Hanjun Guo wrote:
> Hi John,
>
> On 11/24/2016 08:12 PM, John Garry wrote:
>> On 21/11/2016 12:49, Ding Tianhong wrote:
>>> Ping....
>>
>> Hi,
>>
>> was there a cover letter for 0/6? I never saw it.
>
> There isn't a cover letter, do we need to add it and
> resend (to make thing clear)?
>
> Thanks
> Hanjun
>
> .
>
^ permalink raw reply
* Re: [RFC v2: PATCH 1/2] dt-bindings: Document the hi3660 reset bindings
From: zhangfei @ 2016-11-25 3:04 UTC (permalink / raw)
To: Philipp Zabel
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1479979605.2472.4.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 2016年11月24日 17:26, Philipp Zabel wrote:
> Am Mittwoch, den 23.11.2016, 16:07 +0800 schrieb Zhangfei Gao:
>> Add DT bindings documentation for hi3660 SoC reset controller.
>>
>> Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> ---
>> .../bindings/reset/hisilicon,hi3660-reset.txt | 51 ++++++++++++++++++++++
>> 1 file changed, 51 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>> new file mode 100644
>> index 0000000..250daf2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>> @@ -0,0 +1,51 @@
>> +Hisilicon System Reset Controller
>> +======================================
>> +
>> +Please also refer to reset.txt in this directory for common reset
>> +controller binding usage.
>> +
>> +The reset controller registers are part of the system-ctl block on
>> +hi3660 SoC.
>> +
>> +Required properties:
>> +- compatible: should be
>> + "hisilicon,hi3660-reset"
>> +- #reset-cells: 1, see below
>> +- hisi,rst-syscon: phandle of the reset's syscon.
>> +- hisi,reset-bits: Contains the reset control register information
>> + Should contain 2 cells for each reset exposed to
>> + consumers, defined as:
>> + Cell #1 : offset from the syscon register base
>> + Cell #2 : bits position of the control register
>> +
>> +Example:
>> + iomcu: iomcu@ffd7e000 {
>> + compatible = "hisilicon,hi3660-iomcu", "syscon";
>> + reg = <0x0 0xffd7e000 0x0 0x1000>;
>> + };
>> +
>> + iomcu_rst: iomcu_rst_controller {
> This should be
> iomcu_rst: reset-controller {
By the way, could I keep the original name?
Since there will be build error if several nodes use the same name.
like:
- iomcu_rst: iomcu_rst_controller {
+ iomcu_rst: reset-controller {
- crg_rst: crg_rst_controller {
+ crg_rst: reset-controller {
Thanks
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Question regarding clocks in the DW-HDMI DT bindings
From: Andy Yan @ 2016-11-25 2:56 UTC (permalink / raw)
To: Laurent Pinchart, Vladimir Zapolskiy, Fabio Estevam
Cc: DRI mailing list, devicetree-u79uwXL29TY76Z2rM5mHXA,
Mike Turquette, Stephen Boyd, nickey.yang-TNX95d0MmH7DzftRWevZcw
In-Reply-To: <4461318.dYHS3nW9CP@avalon>
Hi:
On 2016年11月25日 07:26, Laurent Pinchart wrote:
> Hello Fabio and Vladimir,
>
> Thank you for your quick responses.
>
> On Friday 25 Nov 2016 00:16:00 Vladimir Zapolskiy wrote:
>> On 11/25/2016 12:07 AM, Fabio Estevam wrote:
>>> On Thu, Nov 24, 2016 at 7:16 PM, Laurent Pinchart wrote:
>>>> Hi Andy,
>>>>
>>>> As the author of the DW-HDMI DT bindings this question is addressed to
>>>> you, but information from anyone is more than welcome.
>>>>
>>>> The DT bindings specify two clocks named "iahb" and "isfr" but don't
>>>> describe them. While I assume that the "isfr" clock corresponds to the
>>>> "isfrclk" input signal of the DW HDMI, there is no "iahb" clock
>>>> described in the IP core datasheet.
>>> i.MX6Q has a DW-HDMI IP block.
>>>
>>> The names in the devicetree binding matches the ones listed at the
>>> i.MX6Q Reference Manual - Table 33-1. HDMI Clocks
>> correct, for your convenience the table is copied below:
>>
>> Clock name | Clock Root | Description
>> -----------+--------------------+---------------------------------------
>> iahbclk | ahb_clk_root | Bus clock
>> icecclk | ckil_sync_clk_root | CEC low-frequency clock (32kHZ)
>> ihclk | ahb_clk_root | Module clock
>> isfrclk | video_27m_clk_root | Internal SFR clock (video clock 27MHz)
>>
>> Here AHB stands for ARM Advanced High-performance Bus.
> That's what I suspected. I believe the "iahb" name is wrong, as the DW HDMI TX
> IP core clearly documents the bus clock as being called "iapbclk". We could
> rename that in the DT bindings (with compatibility code in the driver to keep
> supporting the old name) but it might not be worth it. The bindings should
> however document that the "iahb" clock is the IP core's "iapbclk" bus clock.
I got the clock name from I.MX6Q TRM, I also checked the name again
with Rockchip IC design team now, hope to get some new information soon.
>
> Another question I have about the bus clock (CC'ing the devicetree mailing
> list as well as the clock maintainers) is whether it should be made optional.
> The clock is obviously mandatory from a hardware point of view (given that APB
> is a synchronous bus and thus requires a clock), but in some SoCs
> (specifically for the Renesas SoCs) that clock is always on and can't be
> controlled. We already omit bus clocks in DT for most IP cores when the clock
> can never be controlled (and we also omit a bunch of other clocks that we
> don't even know exist), so it could make sense to make the clock optional.
> Otherwise there would be runtime overhead trying to handle a clock that can't
> be controlled.
If this is the case on Renesas SOCs, we can consider make the clock
as optional. Or move all the clock operations to platform specific
code(dw_hdmi-rockchip.c/dw_hdmi-imx.c)?
>> By the way while we're discussing DW HDMI bindings specific to iMX,
>> I would recommend to remove utterly hackish and iMX only "gpr"
>> property from the example in bindings/display/bridge/dw_hdmi.txt
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC v2: PATCH 1/2] dt-bindings: Document the hi3660 reset bindings
From: Zhangfei Gao @ 2016-11-25 2:38 UTC (permalink / raw)
To: Zhangfei Gao, Arnd Bergmann, Rob Herring, Haojian Zhuang,
Jiancheng Xue
Cc: Philipp Zabel, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel
In-Reply-To: <1479888476-13138-2-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Wed, Nov 23, 2016 at 4:07 PM, Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> Add DT bindings documentation for hi3660 SoC reset controller.
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> .../bindings/reset/hisilicon,hi3660-reset.txt | 51 ++++++++++++++++++++++
> 1 file changed, 51 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
>
> diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
> new file mode 100644
> index 0000000..250daf2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
> @@ -0,0 +1,51 @@
> +Hisilicon System Reset Controller
> +======================================
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +The reset controller registers are part of the system-ctl block on
> +hi3660 SoC.
> +
> +Required properties:
> +- compatible: should be
> + "hisilicon,hi3660-reset"
> +- #reset-cells: 1, see below
> +- hisi,rst-syscon: phandle of the reset's syscon.
> +- hisi,reset-bits: Contains the reset control register information
> + Should contain 2 cells for each reset exposed to
> + consumers, defined as:
> + Cell #1 : offset from the syscon register base
> + Cell #2 : bits position of the control register
> +
> +Example:
> + iomcu: iomcu@ffd7e000 {
> + compatible = "hisilicon,hi3660-iomcu", "syscon";
> + reg = <0x0 0xffd7e000 0x0 0x1000>;
> + };
> +
> + iomcu_rst: iomcu_rst_controller {
> + compatible = "hisilicon,hi3660-reset";
> + #reset-cells = <1>;
> + hisi,rst-syscon = <&iomcu>;
> + hisi,reset-bits = <0x20 0x8 /* 0: i2c0 */
> + 0x20 0x10 /* 1: i2c1 */
> + 0x20 0x20 /* 2: i2c2 */
> + 0x20 0x8000000>; /* 3: i2c6 */
> + };
> +
> +Specifying reset lines connected to IP modules
> +==============================================
> +example:
> +
> + i2c0: i2c@..... {
> + ...
> + resets = <&iomcu_rst 0>;
> + ...
> + };
> +
> + i2c1: i2c@..... {
> + ...
> + resets = <&iomcu_rst 1>;
> + ...
> + };
> --
> 2.7.4
Sorry, missing cc when send-email.
Help take a look.
Thanks
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 1/6] arm64: arch_timer: Add device tree binding for hisilicon-161601 erratum
From: Hanjun Guo @ 2016-11-25 1:57 UTC (permalink / raw)
To: John Garry, Ding Tianhong, catalin.marinas-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, marc.zyngier-5wv7dgnIgG8,
mark.rutland-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
devicetree-u79uwXL29TY76Z2rM5mHXA,
shawnguo-DgEjT+Ai2ygdnm+yROfE0A, stuart.yoder-3arQi8VN3Tc,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linuxarm-hv44wF8Li93QT0dZR+AlfA
In-Reply-To: <624c1751-9b66-1d10-78ae-8cb4edea6109-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Hi John,
On 11/24/2016 08:12 PM, John Garry wrote:
> On 21/11/2016 12:49, Ding Tianhong wrote:
>> Ping....
>
> Hi,
>
> was there a cover letter for 0/6? I never saw it.
There isn't a cover letter, do we need to add it and
resend (to make thing clear)?
Thanks
Hanjun
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [net-next PATCH v1 0/2] stmmac: dwmac-meson8b: configurable RGMII TX delay
From: Martin Blumenstingl @ 2016-11-25 0:41 UTC (permalink / raw)
To: Florian Fainelli
Cc: Jerome Brunet, Sebastian Frias, linux-amlogic, devicetree, netdev,
davem, khilman, mark.rutland, robh+dt, linux-arm-kernel,
alexandre.torgue, peppe.cavallaro, carlo, Mans Rullgard,
Andrew Lunn
In-Reply-To: <e6ca0941-e2e3-dd93-d4d3-8fbd76b60e17@gmail.com>
On Thu, Nov 24, 2016 at 7:55 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> Le 24/11/2016 à 09:05, Martin Blumenstingl a écrit :
>> On Thu, Nov 24, 2016 at 4:56 PM, Jerome Brunet <jbrunet@baylibre.com> wrote:
>>> On Thu, 2016-11-24 at 15:34 +0100, Martin Blumenstingl wrote:
>>>> Currently the dwmac-meson8b stmmac glue driver uses a hardcoded 1/4
>>>> cycle TX clock delay. This seems to work fine for many boards (for
>>>> example Odroid-C2 or Amlogic's reference boards) but there are some
>>>> others where TX traffic is simply broken.
>>>> There are probably multiple reasons why it's working on some boards
>>>> while it's broken on others:
>>>> - some of Amlogic's reference boards are using a Micrel PHY
>>>> - hardware circuit design
>>>> - maybe more...
>>>>
>>>> This raises a question though:
>>>> Which device is supposed to enable the TX delay when both MAC and PHY
>>>> support it? And should we implement it for each PHY / MAC separately
>>>> or should we think about a more generic solution (currently it's not
>>>> possible to disable the TX delay generated by the RTL8211F PHY via
>>>> devicetree when using phy-mode "rgmii")?
>>>
>>> Actually you can skip the part which activate the Tx-delay on the phy
>>> by setting "phy-mode = "rgmii-id" instead of "rgmii"
>>>
>>> phy->interface will no longer be PHY_INTERFACE_MODE_RGMII
>>> but PHY_INTERFACE_MODE_RGMII_ID.
>> unfortunately this is not true for RTL8211F (I did my previous tests
>> with the same expectation in mind)!
>> the code seems to suggest that TX-delay is disabled whenever mode !=
>> PHY_INTERFACE_MODE_RGMII.
>> BUT: on my device RTL8211F_TX_DELAY is set even before
>> "phy_write(phydev, 0x11, reg);"!
>
> (Adding Sebastian (and Mans, and Andrew) since he raised the same
> question a while ago. I think I now understand a bit better what
> Sebastian was after a couple of weeks ago)
>
>>
>> Based on what I found it seems that rgmii-id, rgmii-txid and
>> rgmii-rxid are supposed to be handled by the PHY.
>
> Correct, the meaning of PHY_INTERFACE_MODE should be from the
> perspective of the PHY device:
>
> - PHY_INTERFACE_MODE_RGMII_TXID means that the PHY is responsible for
> adding a delay when the MAC transmits (TX MAC -> PHY (delay) -> wire)
> - PHY_INTERFACE_MODE_RGMII_RXID means that the PHY is responsible for
> adding a delay when the MAC receives (RX MAC <- (delay) PHY) <- wire)
and PHY_INTERFACE_MODE_RGMII_ID is basically _TXID and _RXID combined
(meaning that the PHY is responsible for the TX and RX delays)
>> That would mean that we have two problems here:
>> 1) drivers/net/phy/realtek.c:rtl8211f_config_init should check for
>> PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_TXID and
>> enable the TX-delay in that case - otherwise explicitly disable it
>
> Agreed.
(on a side-not: it seems that the RTL8211F's TX-delay setting is
either untouched by a hardware reset via GPIO or enabled automatically
during hardware reset via GPIO)
>> 2) dwmac-meson8b.c should only use the configured TX-delay for
>> PHY_INTERFACE_MODE_RGMII
>> @Florian: could you please share your thoughts on this (who handles
>> the TX delay in which case)?
>
> This also seems reasonable to do, provided that the PHY is also properly
> configured not to add delays in both directions, and therefore assumes
> that the MAC does it.
on Amlogic Meson systems (at least on the ARM64 ones) all customer
devices with Gbit ethernet are using the RTL8211F PHY. The only
exception are some development/reference boards from Amlogic
themselves, which seem to be using a Micrel RGMII PHY.
> We have a fairly large problem with how RGMII delays are done in PHYLIB
> and Ethernet MAC drivers (or just in general), where we can't really
> intersect properly what a PHY is supporting (in terms of internal
> delays), and what the MAC supports either. One possible approach could
> be to update PHY drivers a list of PHY_INTERFACE_MODE_* that they
> support (ideally, even with normalized nanosecond delay values), and
> then intersect that with the requested phy_interface_t during
> phy_{attach,connect} time, and feed this back to the MAC with a special
> error code/callback, so we could gracefully try to choose another
> PHY_INTERFACE_MODE_* value that the MAC supports....
>
> A larger problem is that a number of drivers have been deployed, and
> Device Trees, possibly with the meaning of "phy-mode" and
> "phy-connection-type" being from the MAC perspective, and not the PHY
> perspective *sigh*, good luck auditing those.
>
> So from there, here is possibly what we could do
>
> - submit a series of patches that update the PHYLIB documentation (there
> are other things missing here) and make it clear from which entity (PHY
> or MAC) does the delay apply to, document the "intersection" problem here
sounds like a good idea, maybe we should move this to a separate thread (I guess
this is the part which is especially interesting for Sebastian, Mans
and Andrew)?
> - have you document the configured behavior for dwmac-meson8b that we
> just discussed here in v2 of this patch series
I would add something like "...using the phy-modes rgmii-id or
rgmii-txid means that the TX-delay will be added by the PHY, thus no
TX-delay should be configured for the MAC/dwmac-meson8b glue" (I'll
improve this, I just want a quick confirmation that I get your idea
right)
Thanks for the quick and helpful answer Florian!
Regards,
Martin
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox