Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
February 2015
- 124 participants
- 244 discussions
25 Feb '15
I am having a problem getting this card working in Mint 17.1 (64bit). I
have found reports from others around the net claiming to have this card
working (around 2010/2011 mostly). I also tried xubuntu with the same
results. On a fresh distro when I install the card, it is recognized but
isn't associated with any driver, if I install the 3.16 kernel or the
alsa-daily repo it becomes associated with a driver but I get the
following errors from dmesg...
[ 3.713183] snd_hda_intel 0000:06:00.0: Probing card using HDA DKMS, version 0.201502151246~ubuntu14.04.1
[ 3.720010] snd_hda_intel 0000:06:00.0: CORB reset timeout#1, CORBRP = 0
[ 4.744035] snd_hda_intel 0000:06:00.0: Codec #1 probe error; disabling it...
[ 4.748009] snd_hda_intel 0000:06:00.0: CORB reset timeout#1, CORBRP = 0
[ 9.772075] snd_hda_intel 0000:06:00.0: no AFG or MFG node found
[ 9.772100] snd_hda_intel 0000:06:00.0: no codecs initialized
and here is my lspci output...
05:00.0 PCI bridge: Creative Labs [SB X-Fi Xtreme Audio] CA0110-IBG PCI to PCIe Bridge (prog-if 00 [Normal decode])
Physical Slot: 3
Flags: bus master, fast devsel, latency 0
Bus: primary=05, secondary=06, subordinate=0c, sec-latency=36
Memory behind bridge: f4300000-f43fffff
Capabilities: [50] Power Management version 3
Capabilities: [60] MSI: Enable- Count=1/16 Maskable- 64bit+
Capabilities: [80] Subsystem: Creative Labs Device 0040
Capabilities: [90] Express PCI-Express to PCI/PCI-X Bridge, MSI 00
Capabilities: [100] Advanced Error Reporting
06:00.0 Audio device: Creative Labs [SB X-Fi Xtreme Audio] CA0110-IBG
Subsystem: Creative Labs SB1040
Flags: bus master, fast Back2Back, medium devsel, latency 32, IRQ 19
Memory at f4300000 (32-bit, non-prefetchable) [size=16K]
Capabilities: [dc] Power Management version 3
Kernel driver in use: snd_hda_intel
thank you for any advice & feedback on this.
2
18
[alsa-devel] [Patch V6 00/10] ASoC: QCOM: Add support for ipq806x SOC
by Kenneth Westfield 25 Feb '15
by Kenneth Westfield 25 Feb '15
25 Feb '15
From: Kenneth Westfield <kwestfie(a)codeaurora.org>
This patch series adds support for I2S audio playback on the Storm board, which
contains a Qualcomm Technologies ipq806x SOC and a Maxim max98357a DAC/amp.
The ipq806x SOC has audio-related hardware blocks in its low-power audio
subsystem (or LPASS). One of the relevant blocks in the LPASS is its low-power
audio interface (or LPAIF). This contains an MI2S port, which is what these
drivers are configured to use. The LPAIF also contains a DMA engine that is
dedicated to moving audio samples into the transmit FIFO of the MI2S port.
One bus from the MI2S port of the SOC is connected to the DAC/amp for stereo
playback. This bus is configured so that the SOC is bus master and consists of
DATA, LRCLK, and BCLK. The DAC/amp does not need MCLK to operate. In addition,
a single GPIO pin from the SOC is connected to the same DAC/amp, which gives
enable/disable control over the DAC/amp.
The specific drivers added are:
* a CPU DAI driver for controlling the MI2S port
* a platform driver for controlling the LPAIF DMA engine
* a machine driver that instantiates a dai-link for playback
The LPASS also contains clocks that need to be controlled. Those drivers have
been submitted as a separate patch series:
[PATCH v3 0/8] qcom audio clock control drivers
http://lkml.org/lkml/2015/1/19/656
Even though the ipq806x LPASS does not contain an audio DSP, other SOCs do have
one. For those SOCs, the audio DSP typically controls the hardware blocks in
the LPASS. Hence, different CPU DAI driver(s) would need to be used in order to
facilitate audio with the DSP. As such, the LPASS DT contains an adsp subnode,
which is disabled for this SOC. The same subnode should be enabled and
populated for other SOCs that do contain an audio DSP. Not using the audio DSP
would require different CPU DAI driver(s), in addition to possible bootloader
and/or firmware changes.
Corresponding additions to the device tree for the ipq806x SOC and its
documentation has also been added. Also, as this is a new directory, the
MAINTAINERS file has been updated as well.
= Changes since V5
[Patch V5 00/12] ASoC: QCOM: Add support for ipq806x SOC
http://mailman.alsa-project.org/pipermail/alsa-devel/2015-February/087832.h…
* Correctly use Storm as the build target label and DT binding label.
* Added audio DSP sub-node to the LPASS device tree, disabled for this SOC.
* Added logic to CPU DAI driver to fail the probe() if a DSP is present.
* Use the standard naming convention for the DAI link properties.
* General code cleanup.
= Changes since V4
[Patch V4 00/10] ASoC: QCOM: Add support for ipq806x SOC
http://mailman.alsa-project.org/pipermail/alsa-devel/2015-February/087499.h…
* Replaced simple-card with a machine driver to resolve the system clock
configuration, rather than having the CPU DAI driver do it.
* Added header files to avoid indirect header dependencies and implicit
forward declarations.
* Tweaked the ISR to match the conventions of the surrounding code.
* Removed the usage of the low-power memory as it is not needed.
* Removed the use of the DRV_NAME constant.
* Added explicit dependency on gpiolib for the codec driver.
* Moved the MODULE_DEVICE_TABLE macro inside the CONFIG_OF conditional.
* Modified the documentation to reflect the changes.
* General code cleanup.
= Changes since V3
[Patch V3 00/10] ASoC: QCOM: Add support for ipq806x SOC
http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085694.h…
* Placed the content of the inline functions into the callbacks.
* Replaced use of readl/writel register access functions with regmap access
functions. Notable exception is the ISR, which uses ioread32/iowrite32.
* Rearranged the sequencing of the hardware block enables to fit within the
ASoC framework callbacks, while remaining functional.
REQ 1: The hardware requires the enable sequence to be:
LPAIF-DMA[enable],then LPAIF-MI2S[enable], then DAC-GPIO[enable]
REQ 2: The hardware requires the disable sequence to be:
DAC-GPIO[disable], then LPAIF-MI2S[disable]
* Corrected the implementation of the pointer callback.
* Utilize the LPM to buffer audio samples, rather than memory external to
LPASS.
* Corrected the interrupt clearing in the ISR.
* Implemented a default system clock (defined by the simple-card DT node), and
optional LPASS DT node modifiers that can alter the system clock in order to
expand the range of available bit clock frequencies.
* Addressed all of the remaining issues raised by Mark Brown.
* General code cleanup.
= Changes since V2
[Patch v2 00/11] ASoC: QCOM: Add support for ipq806x SOC
http://mailman.alsa-project.org/pipermail/alsa-devel/2014-December/085186.h…
* Removed the PCM platform driver from the DTS platform and tied it to the CPU
DAI driver.
* Changed I2S pinctrl to use generic naming convention and moved control to
CPU DAI driver. It should be controlled now by soc-core's pinctrl_pm_*
functionality.
* Added stub DAPM support in codec driver. As the DAC GPIO needs to be
enabled last when starting playback, and disabled first when stopping
playback, it seems as though the trigger function may be the place for this.
Suggestions are welcome for a better place to put this.
* Removed machine driver and tied DAI drivers to simple-audio-card.
* Packaged the build files and Maxim codec files together in one change.
* Removed QCOM as vendor from Maxim code and documentation.
* Separated the SOC and board definitions into the correct DTS files.
* Update device tree documentation to reflect changes.
* General code cleanup.
= Changes since V1
[PATCH 0/9] ASoC: QCOM: Add support for ipq806x SOC
http://mailman.alsa-project.org/pipermail/alsa-devel/2014-November/084322.h…
* Remove the native LPAIF driver, and move its functionality to the CPU DAI
driver.
* Add a codec driver to manage the pins going to the external DAC (previously
managed by the machine driver).
* Use devm_* and dev_* where possible.
* ISR only handles relevant DMA channel now.
* Update device tree documentation to reflect changes.
* General code cleanup.
Kenneth Westfield (10):
MAINTAINERS: Add QCOM audio ASoC maintainer
ASoC: qcom: Document LPASS CPU bindings
ASoC: qcom: Document Storm bindings
ASoC: qcom: add LPASS header files
ASoC: qcom: Add LPASS CPU DAI driver
ASoC: qcom: Add LPASS platform driver
ASoC: qcom: Add Storm machine driver
ASoC: qcom: Add ability to build QCOM drivers
ASoC: Allow for building QCOM drivers
ARM: dts: Model IPQ LPASS audio hardware
.../devicetree/bindings/sound/qcom,lpass-cpu.txt | 49 ++
Documentation/devicetree/bindings/sound/storm.txt | 23 +
MAINTAINERS | 7 +
arch/arm/boot/dts/qcom-ipq8064.dtsi | 26 +
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/qcom/Kconfig | 23 +
sound/soc/qcom/Makefile | 11 +
sound/soc/qcom/lpass-cpu.c | 508 ++++++++++++++++++++
sound/soc/qcom/lpass-lpaif-ipq806x.h | 172 +++++++
sound/soc/qcom/lpass-platform.c | 526 +++++++++++++++++++++
sound/soc/qcom/lpass.h | 51 ++
sound/soc/qcom/storm.c | 162 +++++++
13 files changed, 1560 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
create mode 100644 Documentation/devicetree/bindings/sound/storm.txt
create mode 100644 sound/soc/qcom/Kconfig
create mode 100644 sound/soc/qcom/Makefile
create mode 100644 sound/soc/qcom/lpass-cpu.c
create mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
create mode 100644 sound/soc/qcom/lpass-platform.c
create mode 100644 sound/soc/qcom/lpass.h
create mode 100644 sound/soc/qcom/storm.c
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
1
9
Re: [alsa-devel] Ask for help. ARM:mvebu (CM-A510), add sound support using TLV320AIC23 audio-codec
by Sebastian Hesselbarth 24 Feb '15
by Sebastian Hesselbarth 24 Feb '15
24 Feb '15
[adding alsa-devel and Jean-Francois]
Gabriel,
you should try to add people and lists you expect help from.
On 23.02.2015 21:27, Gabriel Dobato wrote:
> I am trying to set the sound system using "simple-audio-card" and
> TLV320AIC23B audio codec in Compulab CM-510 SoM.
>
> This is my structure in DT, according to
> ./KERNEL/Documentation/devicetree/bindings/sound/simple-card.txt,
> /KERNEL/Documentation/devicetree/bindings/sound/widgets.txt and the
> source code of the audio-codec ./KERNEL/sound/soc/codecs/tlv320aic23.c :
>
> sound {
> compatible = "simple-audio-card";
> simple-audio-card,name = "OnboardTLV320AIC23B";
> simple-audio-card,format = "i2s";
> simple-audio-card,bitclock-master = <&dailink_master>;
> simple-audio-card,frame-master = <&dailink_master>;
> simple-audio-card,widgets =
> "Microphone", "Mic Input",
> "Line", "Line Input",
> "Line", "Line Out",
> "Speaker", "Speaker",
> "Headphone", "Headphone Jack";
>
> simple-audio-card,routing =
> "Line Out", "LOUT",
> "Line Out", "ROUT",
> "Line Out", "RHPOUT",
> "Line Out", "LHPOUT",
> "LLINEIN","Line Input",
> "RLINEIN","Line Input",
> "MICIN","Mic Input";
> simple-audio-card,cpu {
> sound-dai = <&audio0 0>;
> };
> dailink_master: simple-audio-card,codec {
> sound-dai = <&opt_audio>;
> };
> };
> };
>
> /* TLV320AIC23 */
> &opt_audio {
> status = "okay";
> #sound-dai-cells= <0>;
> };
The full node looks like:
opt_audio: audio@1a {
compatible = "ti,tlv320aic23";
reg = <0x1a>;
#sound-dai-cells= <0>;
status = "okay";
};
> And this is the kernel trace:
>
> ...
> tlv320aic23-codec 0-001a: Control not supported for path LLINEIN ->
> [NULL] -> Line Input
> tlv320aic23-codec 0-001a: ASoC: no dapm match for LLINEIN --> NULL -->
> Line Input
> tlv320aic23-codec 0-001a: ASoC: Failed to add route LLINEIN -> NULL ->
> Line Input
> tlv320aic23-codec 0-001a: Control not supported for path RLINEIN ->
> [NULL] -> Line Input
> tlv320aic23-codec 0-001a: ASoC: no dapm match for RLINEIN --> NULL -->
> Line Input
> tlv320aic23-codec 0-001a: ASoC: Failed to add route RLINEIN -> NULL ->
> Line Input
> tlv320aic23-codec 0-001a: Control not supported for path MICIN -> [NULL]
> -> Mic Input
> tlv320aic23-codec 0-001a: ASoC: no dapm match for MICIN --> NULL --> Mic
> Input
> tlv320aic23-codec 0-001a: ASoC: Failed to add route MICIN -> NULL -> Mic
> Input
> usb 2-1.2: new high-speed USB device number 3 using orion-ehci
> asoc-simple-card sound: tlv320aic23-hifi <-> i2s mapping ok
> ...
>
> ALSA device list:
> #0: OnboardTLV320AIC23B
> ...
>
> [....] Setting up ALSA...amixer: Invalid command!
It doesn't help much without knowing what amixer is trying to do.
> I think I have written the node according to the documentation, but
> probably I miss something.
Looking at sound/soc/codecs/tlv320aic23.c:
static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
/* Output Mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "Playback Switch", "DAC"},
{"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
/* Outputs */
{"RHPOUT", NULL, "Output Mixer"},
{"LHPOUT", NULL, "Output Mixer"},
{"LOUT", NULL, "Output Mixer"},
{"ROUT", NULL, "Output Mixer"},
/* Inputs */
{"Line Input", "NULL", "LLINEIN"},
{"Line Input", "NULL", "RLINEIN"},
{"Mic Input", "NULL", "MICIN"},
/* input mux */
{"Capture Source", "Line", "Line Input"},
{"Capture Source", "Mic", "Mic Input"},
{"ADC", NULL, "Capture Source"},
};
The lines with the failing routes really look suspicious, i.e.
there is strings "NULL" where I'd expect plain NULL.
What happens if you amend the three lines and replace the "NULL"
with NULL?
Sebastian
2
2
Re: [alsa-devel] No sound and systemd journal filling when inserting headphones when power-saving is enabled
by Takashi Iwai 24 Feb '15
by Takashi Iwai 24 Feb '15
24 Feb '15
At Tue, 24 Feb 2015 20:11:58 +0000,
Dang Sananikone wrote:
>
> Thanks, in that case I'll simply attach the files to this post. There are
> two files:
>
> * alsa-info-notworking.txt: This is the alsa info generated when
> power-saving is enabled and after "speaker-test" has been invoked.
> * alsa-info-working.txt: This is the alsa info generated when power-saving
> is disabled and after "speaker-test" has been invoked.
>
>
> To reproduce the problem:
>
> Prerequisite:
> Set "options snd_hda_intel power_save=1"
>
> Instructions:
> 1. Boot up laptop.
> 2. Insert headphone socket into jack.
> 3. In terminal, type "speaker-test -c 2".
>
> Expected Result:
> The speaker-test program hangs, and the systemd journal starts filling up
> with "sound hdaudioC0D0: hda-codec: out of range cmd 0:1:716:ffffffff"
> messages.
OK, then try to pass power_save_controller=0 option to snd-hda-intel
module. It might be that the controller gets screwed up by some
reason by power-saving.
If this still doesn't help, we need more logs. Build the kernel with
tracing support, and get the HD-audio verb traces as
Documentation/sound/alsa/HD-Audio.txt, section Tracepoints.
Takashi
1
0
Signed-off-by: Anish Kumar <yesanishhere(a)gmail.com>
---
sound/soc/codecs/Kconfig | 10 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98925.c | 1229 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/max98925.h | 845 +++++++++++++++++++++++++++++
4 files changed, 2086 insertions(+)
create mode 100644 sound/soc/codecs/max98925.c
create mode 100644 sound/soc/codecs/max98925.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 45b7256..a4ccae9 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -47,6 +47,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
+ select SND_SOC_MAX98925 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
@@ -285,6 +286,15 @@ config SND_SOC_MAX9850
config SND_SOC_OMAP_HDMI_CODEC
tristate
+config SND_SOC_MAX98925
+ bool "Support MAX98925 stereo system"
+ depends on I2C
+ help
+ MAX98925 is a high-efficiency mono
+ Class DG audio amplifier. Use this
+ option to enable the system consisting
+ of left and right power amplifier.
+
config SND_SOC_PCM3008
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6a3b3c3..313a7c4 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -37,6 +37,7 @@ snd-soc-max9768-objs := max9768.o
snd-soc-max98088-objs := max98088.o
snd-soc-max98090-objs := max98090.o
snd-soc-max98095-objs := max98095.o
+snd-soc-max98925-objs := max98925.o
snd-soc-max9850-objs := max9850.o
snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
@@ -162,6 +163,7 @@ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
+obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
new file mode 100644
index 0000000..e3a1984
--- /dev/null
+++ b/sound/soc/codecs/max98925.c
@@ -0,0 +1,1229 @@
+/*
+ * max98925.c -- ALSA SoC Stereo MAX98925 driver
+ * Copyright 2013-15 Maxim Integrated Products
+ * 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.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98925.h"
+
+#define VCC_I2C_MIN_UV 1800000
+#define VCC_I2C_MAX_UV 1800000
+#define I2C_LOAD_UA 300000
+
+enum max98925_type {
+ MAX98925L,
+ MAX98925R,
+};
+
+static int max98925_hpf_l;
+static int max98925_hpf_r;
+static int max98925_dai_sel_l;
+static int max98925_dai_sel_r;
+static struct max98925_priv *max98925;
+
+static const char *const dai_text[] = {
+ "L_Data", "R_Data", "LR_Data", "LR_Data_Div2",
+};
+
+static const char *const hpf_text[] = {
+ "hpf_disable", "hpf_dc_block", "hpf_enable_100",
+ "hpf_enable_200", "hpf_enable_400", "hpf_enable_800",
+};
+
+static const struct soc_enum max98925_dai_l_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dai_text), dai_text),
+};
+
+static const struct soc_enum max98925_dai_r_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dai_text), dai_text),
+};
+
+static const struct soc_enum max98925_hpfout_r_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hpf_text), hpf_text),
+};
+
+static const struct soc_enum max98925_hpfout_l_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hpf_text), hpf_text),
+};
+
+static struct reg_default max98925_reg[] = {
+ { 0x00, 0x00 }, /* Battery Voltage Data */
+ { 0x01, 0x00 }, /* Boost Voltage Data */
+ { 0x02, 0x00 }, /* Live Status0 */
+ { 0x03, 0x00 }, /* Live Status1 */
+ { 0x04, 0x00 }, /* Live Status2 */
+ { 0x05, 0x00 }, /* State0 */
+ { 0x06, 0x00 }, /* State1 */
+ { 0x07, 0x00 }, /* State2 */
+ { 0x08, 0x00 }, /* Flag0 */
+ { 0x09, 0x00 }, /* Flag1 */
+ { 0x0A, 0x00 }, /* Flag2 */
+ { 0x0B, 0x00 }, /* IRQ Enable0 */
+ { 0x0C, 0x00 }, /* IRQ Enable1 */
+ { 0x0D, 0x00 }, /* IRQ Enable2 */
+ { 0x0E, 0x00 }, /* IRQ Clear0 */
+ { 0x0F, 0x00 }, /* IRQ Clear1 */
+ { 0x10, 0x00 }, /* IRQ Clear2 */
+ { 0x11, 0xC0 }, /* Map0 */
+ { 0x12, 0x00 }, /* Map1 */
+ { 0x13, 0x00 }, /* Map2 */
+ { 0x14, 0xF0 }, /* Map3 */
+ { 0x15, 0x00 }, /* Map4 */
+ { 0x16, 0xAB }, /* Map5 */
+ { 0x17, 0x89 }, /* Map6 */
+ { 0x18, 0x00 }, /* Map7 */
+ { 0x19, 0x00 }, /* Map8 */
+ { 0x1A, 0x06 }, /* DAI Clock Mode 1 */
+ { 0x1B, 0xC0 }, /* DAI Clock Mode 2 */
+ { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */
+ { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */
+ { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */
+ { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */
+ { 0x20, 0x50 }, /* Format */
+ { 0x21, 0x00 }, /* TDM Slot Select */
+ { 0x22, 0x00 }, /* DOUT Configuration VMON */
+ { 0x23, 0x00 }, /* DOUT Configuration IMON */
+ { 0x24, 0x00 }, /* DOUT Configuration VBAT */
+ { 0x25, 0x00 }, /* DOUT Configuration VBST */
+ { 0x26, 0x00 }, /* DOUT Configuration FLAG */
+ { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */
+ { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */
+ { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */
+ { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */
+ { 0x2B, 0x02 }, /* DOUT Drive Strength */
+ { 0x2C, 0x90 }, /* Filters */
+ { 0x2D, 0x00 }, /* Gain */
+ { 0x2E, 0x02 }, /* Gain Ramping */
+ { 0x2F, 0x00 }, /* Speaker Amplifier */
+ { 0x30, 0x0A }, /* Threshold */
+ { 0x31, 0x00 }, /* ALC Attack */
+ { 0x32, 0x80 }, /* ALC Atten and Release */
+ { 0x33, 0x00 }, /* ALC Infinite Hold Release */
+ { 0x34, 0x92 }, /* ALC Configuration */
+ { 0x35, 0x01 }, /* Boost Converter */
+ { 0x36, 0x00 }, /* Block Enable */
+ { 0x37, 0x00 }, /* Configuration */
+ { 0x38, 0x00 }, /* Global Enable */
+ { 0x3A, 0x00 }, /* Boost Limiter */
+ { 0xFF, 0x50 }, /* Revision ID */
+};
+
+void max98925_regmap_update_bits_stereo(struct max98925_priv *max98925,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ regmap_update_bits(max98925->regmap_l, reg, mask, val);
+ regmap_update_bits(max98925->regmap_r, reg, mask, val);
+}
+
+static int max98925_get_hpf_l(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = max98925_hpf_l;
+ return 0;
+}
+
+static int max98925_put_hpf_l(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update update;
+ unsigned int reg = MAX98925_R02C_FILTERS;
+ unsigned int mask = M98925_DAC_HPF_MASK;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ regmap_update_bits(max98925->regmap_l, reg, mask,
+ M98925_DAC_HPF_DISABLE);
+ break;
+ case 1:
+ regmap_update_bits(max98925->regmap_l, reg, mask,
+ M98925_DAC_HPF_DC_BLOCK);
+ break;
+ case 2:
+ regmap_update_bits(max98925->regmap_l, reg, mask,
+ M98925_DAC_HPF_EN_100);
+ break;
+ case 3:
+ regmap_update_bits(max98925->regmap_l, reg, mask,
+ M98925_DAC_HPF_EN_200);
+ break;
+ case 4:
+ regmap_update_bits(max98925->regmap_l, reg, mask,
+ M98925_DAC_HPF_EN_400);
+ break;
+ case 5:
+ regmap_update_bits(max98925->regmap_l, reg, mask,
+ M98925_DAC_HPF_EN_800);
+ break;
+ default:
+ return -EINVAL;
+ }
+ update.kcontrol = kcontrol;
+ update.reg = SND_SOC_NOPM;
+ max98925_hpf_l = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mux_update_power(&codec->dapm,
+ kcontrol, max98925_hpf_l, e, &update);
+ return 0;
+}
+
+static int max98925_get_hpf_r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = max98925_hpf_r;
+ return 0;
+}
+
+static int max98925_put_hpf_r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update update;
+ unsigned int reg = MAX98925_R02C_FILTERS;
+ unsigned int mask = M98925_DAC_HPF_MASK;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ regmap_update_bits(max98925->regmap_r, reg, mask,
+ M98925_DAC_HPF_DISABLE);
+ break;
+ case 1:
+ regmap_update_bits(max98925->regmap_r, reg, mask,
+ M98925_DAC_HPF_DC_BLOCK);
+ break;
+ case 2:
+ regmap_update_bits(max98925->regmap_r, reg, mask,
+ M98925_DAC_HPF_EN_100);
+ break;
+ case 3:
+ regmap_update_bits(max98925->regmap_r, reg, mask,
+ M98925_DAC_HPF_EN_200);
+ break;
+ case 4:
+ regmap_update_bits(max98925->regmap_r, reg, mask,
+ M98925_DAC_HPF_EN_400);
+ break;
+ case 5:
+ regmap_update_bits(max98925->regmap_r, reg, mask,
+ M98925_DAC_HPF_EN_800);
+ break;
+ default:
+ return -EINVAL;
+ }
+ max98925_hpf_r = ucontrol->value.integer.value[0];
+ update.kcontrol = kcontrol;
+ update.reg = SND_SOC_NOPM;
+ snd_soc_dapm_mux_update_power(&codec->dapm,
+ kcontrol, max98925_hpf_r, e, &update);
+ return 0;
+}
+
+static int max98925_get_dai_sel_l(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = max98925_dai_sel_l;
+ return 0;
+}
+
+static int max98925_put_dai_sel_l(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update update;
+ unsigned int reg = MAX98925_R02D_GAIN;
+ unsigned int mask = M98925_DAC_IN_SEL_MASK;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ regmap_update_bits(max98925->regmap_l,
+ reg, mask, M98925_DAC_IN_SEL_LEFT_DAI);
+ break;
+ case 1:
+ regmap_update_bits(max98925->regmap_l,
+ reg, mask, M98925_DAC_IN_SEL_RIGHT_DAI);
+ break;
+ case 2:
+ regmap_update_bits(max98925->regmap_l,
+ reg, mask, M98925_DAC_IN_SEL_SUMMED_DAI);
+ break;
+ case 3:
+ regmap_update_bits(max98925->regmap_l,
+ reg, mask, M98925_DAC_IN_SEL_DIV2_SUMMED_DAI);
+ break;
+ default:
+ return -EINVAL;
+ }
+ max98925_dai_sel_l = ucontrol->value.integer.value[0];
+ update.kcontrol = kcontrol;
+ update.reg = SND_SOC_NOPM;
+ snd_soc_dapm_mux_update_power(&codec->dapm,
+ kcontrol, max98925_dai_sel_l, e, &update);
+ return 0;
+}
+
+static int max98925_get_dai_sel_r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = max98925_dai_sel_r;
+ return 0;
+}
+
+static int max98925_put_dai_sel_r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update update;
+ unsigned int reg = MAX98925_R02D_GAIN;
+ unsigned int mask = M98925_DAC_IN_SEL_MASK;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ regmap_update_bits(max98925->regmap_r,
+ reg, mask, M98925_DAC_IN_SEL_LEFT_DAI);
+ break;
+ case 1:
+ regmap_update_bits(max98925->regmap_r,
+ reg, mask, M98925_DAC_IN_SEL_RIGHT_DAI);
+ break;
+ case 2:
+ regmap_update_bits(max98925->regmap_r,
+ reg, mask, M98925_DAC_IN_SEL_SUMMED_DAI);
+ break;
+ case 3:
+ regmap_update_bits(max98925->regmap_r,
+ reg, mask, M98925_DAC_IN_SEL_DIV2_SUMMED_DAI);
+ break;
+ default:
+ return -EINVAL;
+ }
+ max98925_dai_sel_r = ucontrol->value.integer.value[0];
+ update.kcontrol = kcontrol;
+ update.reg = SND_SOC_NOPM;
+ snd_soc_dapm_mux_update_power(&codec->dapm,
+ kcontrol, max98925_dai_sel_r, e, &update);
+ return 0;
+}
+
+static int max98925_reg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, unsigned int reg,
+ unsigned int mask, unsigned int shift)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ max98925_regmap_update_bits_stereo(max98925, reg, mask, sel << shift);
+ dev_dbg(codec->dev, "%s: register 0x%02X, value 0x%02X\n",
+ __func__, reg, sel);
+ return 0;
+}
+
+static int max98925_dac_ev_l(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(max98925->regmap_l, MAX98925_R036_BLOCK_ENABLE,
+ M98925_SPK_EN_MASK, M98925_SPK_EN_MASK);
+ return 0;
+}
+
+static int max98925_dac_ev_r(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(max98925->regmap_r, MAX98925_R036_BLOCK_ENABLE,
+ M98925_SPK_EN_MASK, M98925_SPK_EN_MASK);
+ return 0;
+}
+
+static const struct snd_kcontrol_new dai_sel_mux[2] = {
+ SOC_DAPM_ENUM_EXT("DAI_IN_MUX_L Mux", max98925_dai_l_enum,
+ max98925_get_dai_sel_l, max98925_put_dai_sel_l),
+ SOC_DAPM_ENUM_EXT("DAI_IN_MUX_R Mux", max98925_dai_r_enum,
+ max98925_get_dai_sel_r, max98925_put_dai_sel_r),
+};
+
+static const struct snd_kcontrol_new hpf_mux[2] = {
+ SOC_ENUM_EXT("R02C_FILTER_R Mux", max98925_hpfout_r_enum,
+ max98925_get_hpf_r, max98925_put_hpf_r),
+ SOC_ENUM_EXT("R02C_FILTER_L Mux", max98925_hpfout_l_enum,
+ max98925_get_hpf_l, max98925_put_hpf_l),
+};
+
+static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("DAI_IN_MUX_L MUX", SND_SOC_NOPM, 0, 0,
+ &dai_sel_mux[0]),
+ SND_SOC_DAPM_MUX("DAI_IN_MUX_R MUX", SND_SOC_NOPM, 0, 0,
+ &dai_sel_mux[1]),
+ SND_SOC_DAPM_MUX("R02C_FILTER_L MUX", SND_SOC_NOPM, 0, 0,
+ &hpf_mux[0]),
+ SND_SOC_DAPM_MUX("R02C_FILTER_R MUX", SND_SOC_NOPM, 0, 0,
+ &hpf_mux[1]),
+ SND_SOC_DAPM_DAC_E("amp_enable_l", NULL,
+ SND_SOC_NOPM, 0, 0,
+ max98925_dac_ev_l, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_DAC_E("amp_enable_r", NULL,
+ SND_SOC_NOPM, 0, 0,
+ max98925_dac_ev_r, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98925_audio_map[] = {
+ {"DAI_IN_MUX_L MUX", "L_Data", "DAI_OUT"},
+ {"DAI_IN_MUX_L MUX", "R_Data", "DAI_OUT"},
+ {"DAI_IN_MUX_L MUX", "LR_Data", "DAI_OUT"},
+ {"DAI_IN_MUX_L MUX", "LR_Data_Div2", "DAI_OUT"},
+ {"R02C_FILTER_L MUX", "hpf_disable", "DAI_IN_MUX_L MUX"},
+ {"R02C_FILTER_L MUX", "hpf_dc_block", "DAI_IN_MUX_L MUX"},
+ {"R02C_FILTER_L MUX", "hpf_enable_100", "DAI_IN_MUX_L MUX"},
+ {"R02C_FILTER_L MUX", "hpf_enable_200", "DAI_IN_MUX_L MUX"},
+ {"R02C_FILTER_L MUX", "hpf_enable_400", "DAI_IN_MUX_L MUX"},
+ {"R02C_FILTER_L MUX", "hpf_enable_800", "DAI_IN_MUX_L MUX"},
+ {"amp_enable_l", NULL, "R02C_FILTER_L MUX"},
+ {"BE_OUT", NULL, "amp_enable_l"},
+
+ {"DAI_IN_MUX_R MUX", "L_Data", "DAI_OUT"},
+ {"DAI_IN_MUX_R MUX", "R_Data", "DAI_OUT"},
+ {"DAI_IN_MUX_R MUX", "LR_Data", "DAI_OUT"},
+ {"DAI_IN_MUX_R MUX", "LR_Data_Div2", "DAI_OUT"},
+ {"R02C_FILTER_R MUX", "hpf_disable", "DAI_IN_MUX_R MUX"},
+ {"R02C_FILTER_R MUX", "hpf_dc_block", "DAI_IN_MUX_R MUX"},
+ {"R02C_FILTER_R MUX", "hpf_enable_100", "DAI_IN_MUX_R MUX"},
+ {"R02C_FILTER_R MUX", "hpf_enable_200", "DAI_IN_MUX_R MUX"},
+ {"R02C_FILTER_R MUX", "hpf_enable_400", "DAI_IN_MUX_R MUX"},
+ {"R02C_FILTER_R MUX", "hpf_enable_800", "DAI_IN_MUX_R MUX"},
+ {"amp_enable_r", NULL, "R02C_FILTER_R MUX"},
+ {"BE_OUT", NULL, "amp_enable_r"},
+};
+
+void max98925_regmap_write_stereo(struct max98925_priv *max98925,
+ unsigned int reg, unsigned int val)
+{
+ regmap_write(max98925->regmap_l, reg, val);
+ regmap_write(max98925->regmap_r, reg, val);
+}
+
+static bool max98925_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98925_R000_VBAT_DATA:
+ case MAX98925_R001_VBST_DATA:
+ case MAX98925_R002_LIVE_STATUS0:
+ case MAX98925_R003_LIVE_STATUS1:
+ case MAX98925_R004_LIVE_STATUS2:
+ case MAX98925_R005_STATE0:
+ case MAX98925_R006_STATE1:
+ case MAX98925_R007_STATE2:
+ case MAX98925_R008_FLAG0:
+ case MAX98925_R009_FLAG1:
+ case MAX98925_R00A_FLAG2:
+ case MAX98925_R0FF_VERSION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool max98925_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98925_R00E_IRQ_CLEAR0:
+ case MAX98925_R00F_IRQ_CLEAR1:
+ case MAX98925_R010_IRQ_CLEAR2:
+ case MAX98925_R033_ALC_HOLD_RLS:
+ return false;
+ default:
+ return true;
+ }
+};
+
+DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0);
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_ua)
+{
+ return (regulator_count_voltages(reg) > 0) ?
+ regulator_set_optimum_mode(reg, load_ua) : 0;
+}
+
+static int max98925_regulator_config(struct i2c_client *i2c,
+ bool pullup, bool on)
+{
+ struct regulator *max98925_vcc_i2c;
+ int rc;
+
+ if (pullup) {
+ pr_info("%s: i2c pull up\n", __func__);
+ max98925_vcc_i2c = regulator_get(&i2c->dev, "vcc_i2c");
+ if (IS_ERR(max98925_vcc_i2c)) {
+ rc = PTR_ERR(max98925_vcc_i2c);
+ pr_err("%s: regulator get failed rc=%d\n",
+ __func__, rc);
+ goto error_get_vtg_i2c;
+ }
+ if (regulator_count_voltages(max98925_vcc_i2c) > 0) {
+ rc = regulator_set_voltage(max98925_vcc_i2c,
+ VCC_I2C_MIN_UV, VCC_I2C_MAX_UV);
+ if (rc) {
+ pr_err("%s: regulator set_vtg failed rc=%d\n",
+ __func__, rc);
+ goto error_set_vtg_i2c;
+ }
+ }
+
+ rc = reg_set_optimum_mode_check(max98925_vcc_i2c, I2C_LOAD_UA);
+ if (rc < 0) {
+ pr_err("%s: regulator vcc_i2c set_opt failed rc=%d\n",
+ __func__, rc);
+ goto error_reg_opt_i2c;
+ }
+
+ rc = regulator_enable(max98925_vcc_i2c);
+ if (rc) {
+ pr_err("%s: regulator vcc_i2c enable failed rc=%d\n",
+ __func__, rc);
+ goto error_reg_en_vcc_i2c;
+ }
+
+ }
+ return 0;
+error_set_vtg_i2c:
+ regulator_put(max98925_vcc_i2c);
+error_get_vtg_i2c:
+ if (regulator_count_voltages(max98925_vcc_i2c) > 0)
+ regulator_set_voltage(max98925_vcc_i2c, 0,
+ VCC_I2C_MAX_UV);
+error_reg_en_vcc_i2c:
+ if (pullup)
+ reg_set_optimum_mode_check(max98925_vcc_i2c, 0);
+error_reg_opt_i2c:
+ regulator_disable(max98925_vcc_i2c);
+ return rc;
+}
+
+static int max98925_spk_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = max98925->spk_gain;
+ dev_dbg(codec->dev, "%s: spk_gain setting returned %d\n", __func__,
+ (int) ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int max98925_spk_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ if (sel < ((1 << M98925_SPK_GAIN_WIDTH) - 1)) {
+ max98925_regmap_update_bits_stereo(max98925, MAX98925_R02D_GAIN,
+ M98925_SPK_GAIN_MASK, sel << M98925_SPK_GAIN_SHIFT);
+ max98925->spk_gain = sel;
+
+ dev_dbg(codec->dev, "%s: spk_gain set to %d\n", __func__, sel);
+ } else {
+ dev_dbg(codec->dev, "%s: valid speaker gain settings: %d to %d\n",
+ __func__, 0,
+ ((1 << M98925_SPK_GAIN_WIDTH) - 1));
+ }
+ return 0;
+}
+
+static int max98925_reg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, unsigned int reg,
+ unsigned int mask, unsigned int shift)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ int data;
+
+ regmap_read(max98925->regmap_l, reg, &data);
+ ucontrol->value.integer.value[0] =
+ (data & mask) >> shift;
+ return 0;
+}
+
+static int max98925_spk_ramp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_RMP_EN_MASK, M98925_SPK_RMP_EN_SHIFT);
+}
+
+static int max98925_spk_ramp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_RMP_EN_MASK, M98925_SPK_RMP_EN_SHIFT);
+}
+
+static int max98925_spk_zcd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_ZCD_EN_MASK, M98925_SPK_ZCD_EN_SHIFT);
+}
+
+static int max98925_spk_zcd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_ZCD_EN_MASK, M98925_SPK_ZCD_EN_SHIFT);
+}
+
+static int max98925_alc_en_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_EN_MASK, M98925_ALC_EN_SHIFT);
+}
+
+static int max98925_alc_en_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_EN_MASK, M98925_ALC_EN_SHIFT);
+}
+
+static int max98925_alc_threshold_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_TH_MASK, M98925_ALC_TH_SHIFT);
+}
+
+static int max98925_alc_threshold_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_TH_MASK, M98925_ALC_TH_SHIFT);
+}
+
+static const char * const max98925_boost_voltage_text[] = {"8.5V", "8.25V",
+ "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V",
+ "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V",
+ "6.5V", "6.5V"};
+
+static const struct soc_enum max98925_boost_voltage_enum =
+ SOC_ENUM_SINGLE(MAX98925_R037_CONFIGURATION, M98925_BST_VOUT_SHIFT, 15,
+ max98925_boost_voltage_text);
+
+static int max98925_boost_voltage_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R037_CONFIGURATION,
+ M98925_BST_VOUT_MASK, M98925_BST_VOUT_SHIFT);
+}
+
+static int max98925_boost_voltage_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R037_CONFIGURATION,
+ M98925_BST_VOUT_MASK, M98925_BST_VOUT_SHIFT);
+}
+
+static const struct snd_kcontrol_new max98925_snd_controls[] = {
+
+ SOC_SINGLE_EXT_TLV("Speaker Gain", MAX98925_R02D_GAIN,
+ M98925_SPK_GAIN_SHIFT, (1<<M98925_SPK_GAIN_WIDTH)-1, 0,
+ max98925_spk_gain_get, max98925_spk_gain_put, max98925_spk_tlv),
+
+ SOC_SINGLE_EXT("Speaker Ramp", 0, 0, 1, 0,
+ max98925_spk_ramp_get, max98925_spk_ramp_put),
+
+ SOC_SINGLE_EXT("Speaker ZCD", 0, 0, 1, 0,
+ max98925_spk_zcd_get, max98925_spk_zcd_put),
+
+ SOC_SINGLE_EXT("ALC Enable", 0, 0, 1, 0,
+ max98925_alc_en_get, max98925_alc_en_put),
+
+ SOC_SINGLE_EXT("ALC Threshold", 0, 0, (1<<M98925_ALC_TH_WIDTH)-1, 0,
+ max98925_alc_threshold_get, max98925_alc_threshold_put),
+
+ SOC_ENUM_EXT("Boost Output Voltage", max98925_boost_voltage_enum,
+ max98925_boost_voltage_get, max98925_boost_voltage_put),
+};
+
+/* codec sample rate and n/m dividers parameter table */
+static const struct {
+ int rate;
+ int sr;
+ int divisors[3][2];
+} rate_table[] = {
+ {
+ .rate = 8000,
+ .sr = 0,
+ .divisors = { {1, 375}, {5, 1764}, {1, 384} }
+ },
+ {
+ .rate = 11025,
+ .sr = 1,
+ .divisors = { {147, 40000}, {1, 256}, {147, 40960} }
+ },
+ {
+ .rate = 12000,
+ .sr = 2,
+ .divisors = { {1, 250}, {5, 1176}, {1, 256} }
+ },
+ {
+ .rate = 16000,
+ .sr = 3,
+ .divisors = { {2, 375}, {5, 882}, {1, 192} }
+ },
+ {
+ .rate = 22050,
+ .sr = 4,
+ .divisors = { {147, 20000}, {1, 128}, {147, 20480} }
+ },
+ {
+ .rate = 24000,
+ .sr = 5,
+ .divisors = { {1, 125}, {5, 588}, {1, 128} }
+ },
+ {
+ .rate = 32000,
+ .sr = 6,
+ .divisors = { {4, 375}, {5, 441}, {1, 96} }
+ },
+ {
+ .rate = 44100,
+ .sr = 7,
+ .divisors = { {147, 10000}, {1, 64}, {147, 10240} }
+ },
+ {
+ .rate = 48000,
+ .sr = 8,
+ .divisors = { {2, 125}, {5, 294}, {1, 64} }
+ },
+};
+
+static inline int max98925_rate_value(int rate,
+ int clock, int *value, int *n, int *m)
+{
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i].rate >= rate) {
+ *value = rate_table[i].sr;
+ *n = rate_table[i].divisors[clock][0];
+ *m = rate_table[i].divisors[clock][1];
+ ret = 0;
+ break;
+ }
+ }
+ pr_debug("%s: sample rate is %d, returning %d\n",
+ __func__, rate_table[i].rate, *value);
+ return ret;
+}
+
+static void max98925_set_sense_data(struct max98925_priv *max98925)
+{
+ /*
+ * 1. set VMON slots
+ */
+ regmap_update_bits(max98925->regmap_l,
+ MAX98925_R022_DOUT_CFG_VMON,
+ M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK);
+ regmap_update_bits(max98925->regmap_l,
+ MAX98925_R022_DOUT_CFG_VMON,
+ M98925_DAI_VMON_SLOT_MASK, M98925_DAI_VMON_SLOT_00_01);
+ /*
+ * 2. set IMON slots
+ */
+ regmap_update_bits(max98925->regmap_l,
+ MAX98925_R023_DOUT_CFG_IMON,
+ M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK);
+ regmap_update_bits(max98925->regmap_l,
+ MAX98925_R023_DOUT_CFG_IMON,
+ M98925_DAI_IMON_SLOT_MASK, M98925_DAI_IMON_SLOT_02_03);
+}
+
+static void max98925_set_slave(struct max98925_priv *max98925)
+{
+ /*
+ * 1. use BCLK instead of MCLK
+ */
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_DAI_CLK_SOURCE_MASK, M98925_DAI_CLK_SOURCE_MASK);
+ /*
+ * 2. set DAI to slave mode
+ */
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_MAS_MASK, 0);
+ /*
+ * 3. set BLCKs to LRCLKs to 64
+ */
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64);
+
+ max98925_set_sense_data(max98925);
+}
+
+static void max98925_set_master(struct max98925_priv *max98925)
+{
+ /*
+ * 1. use MCLK for Left channel, right channel always BCLK
+ */
+ regmap_update_bits(max98925->regmap_l,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_DAI_CLK_SOURCE_MASK, 0);
+ regmap_update_bits(max98925->regmap_r,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_DAI_CLK_SOURCE_MASK,
+ M98925_DAI_CLK_SOURCE_MASK);
+ /*
+ * 2. set left channel DAI to master mode, right channel always slave
+ */
+ regmap_update_bits(max98925->regmap_l,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK);
+ regmap_update_bits(max98925->regmap_r,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_MAS_MASK, 0);
+}
+
+static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct max98925_cdata *cdata;
+ unsigned int invert = 0;
+
+ dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+ cdata = &max98925->dai[0];
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ max98925_set_slave(max98925);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ max98925_set_master(max98925);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "DAI clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ default:
+ dev_err(codec->dev, "DAI format unsupported, fmt:0x%x", fmt);
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "DAI format supported, fmt:0x%x", fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ invert = M98925_DAI_WCI_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ invert = M98925_DAI_BCI_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "DAI invert mode unsupported");
+ return -EINVAL;
+ }
+
+ max98925_regmap_update_bits_stereo(max98925, MAX98925_R020_FORMAT,
+ M98925_DAI_BCI_MASK | M98925_DAI_BCI_MASK, invert);
+ return 0;
+}
+
+static int max98925_set_clock(struct max98925_priv *max98925,
+ unsigned int rate)
+{
+ unsigned int dai_sr = 0;
+ unsigned int clock;
+ unsigned int mdll;
+ unsigned int n;
+ unsigned int m;
+
+ switch (max98925->sysclk) {
+ case 6000000:
+ clock = 0;
+ mdll = M98925_MDLL_MULT_MCLKx16;
+ break;
+ case 11289600:
+ clock = 1;
+ mdll = M98925_MDLL_MULT_MCLKx8;
+ break;
+ case 12000000:
+ clock = 0;
+ mdll = M98925_MDLL_MULT_MCLKx8;
+ break;
+ case 12288000:
+ clock = 2;
+ mdll = M98925_MDLL_MULT_MCLKx8;
+ break;
+ default:
+ dev_info(max98925->codec->dev, "unsupported sysclk %d\n",
+ max98925->sysclk);
+ return -EINVAL;
+ }
+
+ if (max98925_rate_value(rate, clock, &dai_sr, &n, &m))
+ return -EINVAL;
+
+ /*
+ * 1. set DAI_SR to correct LRCLK frequency
+ */
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_SR_MASK, dai_sr << M98925_DAI_SR_SHIFT);
+ /*
+ * 2. set DAI m divider
+ */
+ regmap_write(max98925->regmap_l,
+ MAX98925_R01C_DAI_CLK_DIV_M_MSBS, m >> 8);
+ regmap_write(max98925->regmap_l,
+ MAX98925_R01D_DAI_CLK_DIV_M_LSBS, m & 0xFF);
+ /*
+ * 3. set DAI n divider
+ */
+ regmap_write(max98925->regmap_l,
+ MAX98925_R01E_DAI_CLK_DIV_N_MSBS, n >> 8);
+ regmap_write(max98925->regmap_l,
+ MAX98925_R01F_DAI_CLK_DIV_N_LSBS, n & 0xFF);
+ /*
+ * 4. set MDLL
+ */
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_MDLL_MULT_MASK, mdll << M98925_MDLL_MULT_SHIFT);
+ return 0;
+}
+
+static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct max98925_cdata *cdata;
+ unsigned int rate;
+
+ cdata = &max98925->dai[0];
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R020_FORMAT,
+ M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R020_FORMAT,
+ M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32);
+ dev_dbg(codec->dev, "%s: (really set to 32 bits)\n", __func__);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R020_FORMAT,
+ M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32);
+ break;
+ default:
+ pr_err("%s: format unsupported %d",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "%s: format supported %d",
+ __func__, params_format(params));
+ return max98925_set_clock(max98925, rate);
+}
+
+static int max98925_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: clk_id %d, freq %d, dir %d\n",
+ __func__, clk_id, freq, dir);
+ max98925->sysclk = freq;
+ return 0;
+}
+
+static int max98925_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct max98925_priv *max98925 =
+ snd_soc_codec_get_drvdata(codec_dai->codec);
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ dev_dbg(codec->dev, "%s: mute %d\n", __func__, mute);
+ if (mute) {
+ max98925_regmap_update_bits_stereo(max98925, MAX98925_R02D_GAIN,
+ M98925_SPK_GAIN_MASK, 0x00);
+
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R038_GLOBAL_ENABLE,
+ M98925_EN_MASK, 0x0);
+ } else {
+ max98925_regmap_update_bits_stereo(max98925,
+ MAX98925_R036_BLOCK_ENABLE,
+ M98925_BST_EN_MASK |
+ M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK,
+ M98925_BST_EN_MASK |
+ M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK);
+
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R038_GLOBAL_ENABLE, M98925_EN_MASK);
+ }
+ return 0;
+}
+
+#define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops max98925_dai_ops = {
+ .set_sysclk = max98925_dai_set_sysclk,
+ .set_fmt = max98925_dai_set_fmt,
+ .hw_params = max98925_dai_hw_params,
+ .digital_mute = max98925_dai_digital_mute,
+};
+
+static struct snd_soc_dai_driver max98925_dai[] = {
+ {
+ .name = "max98925-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = MAX98925_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = MAX98925_FORMATS,
+ },
+ .ops = &max98925_dai_ops,
+ }
+};
+
+static int max98925_probe(struct snd_soc_codec *codec)
+{
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ struct max98925_cdata *cdata;
+ int ret = 0;
+ int reg = 0;
+
+ dev_info(codec->dev, "build number %s\n", MAX98925_REVISION);
+
+ max98925->codec = codec;
+ codec->control_data = max98925->regmap_l;
+ /* can be configured to any other value supported by this chip */
+ max98925->sysclk = 12288000;
+ max98925->spk_gain = 0x14;
+ cdata = &max98925->dai[0];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+
+ reg = 0;
+ ret = regmap_read(max98925->regmap_l,
+ MAX98925_R0FF_VERSION, ®);
+ if ((ret < 0) ||
+ ((reg != MAX98925_VERSION) &&
+ (reg != MAX98925_VERSION1))) {
+ dev_err(codec->dev,
+ "L device initialization error (%d 0x%02X)\n",
+ ret, reg);
+ goto err_access;
+ }
+ dev_info(codec->dev, "L device version 0x%02X\n", reg);
+
+ reg = 0;
+ ret = regmap_read(max98925->regmap_r,
+ MAX98925_R0FF_VERSION, ®);
+ if ((ret < 0) || ((reg != MAX98925_VERSION)
+ && (reg != MAX98925_VERSION1))) {
+ dev_err(codec->dev,
+ "R device initialization error (%d 0x%02X)\n",
+ ret, reg);
+ goto err_access;
+ }
+ dev_info(codec->dev, "R device version 0x%02X\n", reg);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R038_GLOBAL_ENABLE, 0x00);
+
+ /* It's not the default but we need to set DAI_DLY */
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R020_FORMAT, M98925_DAI_DLY_MASK);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R021_TDM_SLOT_SELECT, 0xC8);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R027_DOUT_HIZ_CFG1, 0xFF);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R028_DOUT_HIZ_CFG2, 0xFF);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R029_DOUT_HIZ_CFG3, 0xFF);
+ regmap_write(max98925->regmap_l,
+ MAX98925_R02A_DOUT_HIZ_CFG4, 0xF0);
+ regmap_write(max98925->regmap_r,
+ MAX98925_R02A_DOUT_HIZ_CFG4, 0x0F);
+
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R02C_FILTERS, 0xD8);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R034_ALC_CONFIGURATION, 0xF8);
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R037_CONFIGURATION, 0xF0);
+
+ /* Disable ALC muting */
+ max98925_regmap_write_stereo(max98925,
+ MAX98925_R03A_BOOST_LIMITER, 0xF8);
+
+ regmap_update_bits(max98925->regmap_l, MAX98925_R02D_GAIN,
+ M98925_DAC_IN_SEL_MASK, M98925_DAC_IN_SEL_LEFT_DAI);
+ regmap_update_bits(max98925->regmap_r, MAX98925_R02D_GAIN,
+ M98925_DAC_IN_SEL_MASK, M98925_DAC_IN_SEL_RIGHT_DAI);
+
+err_access:
+ return ret;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98925 = {
+ .probe = max98925_probe,
+ .controls = max98925_snd_controls,
+ .num_controls = ARRAY_SIZE(max98925_snd_controls),
+ .dapm_routes = max98925_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98925_audio_map),
+ .dapm_widgets = max98925_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets),
+};
+
+static struct regmap_config max98925_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX98925_R0FF_VERSION,
+ .reg_defaults = max98925_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98925_reg),
+ .volatile_reg = max98925_volatile_register,
+ .readable_reg = max98925_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int max98925_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+
+ dev_info(&i2c->dev, "%s: enter, device '%s'\n", __func__, id->name);
+ if (!max98925) {
+ max98925 = devm_kzalloc(&i2c->dev,
+ sizeof(*max98925), GFP_KERNEL);
+ if (!max98925)
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(i2c, max98925);
+ if (id->driver_data == MAX98925L) {
+ max98925->regmap_l =
+ devm_regmap_init_i2c(i2c, &max98925_regmap);
+ if (IS_ERR(max98925->regmap_l)) {
+ ret = PTR_ERR(max98925->regmap_l);
+ dev_err(&i2c->dev,
+ "Failed to allocate regmap_l: %d\n", ret);
+ goto err_out;
+ }
+ }
+
+ /* Check for second MAX98925 */
+ if (id->driver_data == MAX98925R) {
+ max98925->regmap_r =
+ devm_regmap_init_i2c(i2c, &max98925_regmap);
+ if (IS_ERR(max98925->regmap_r)) {
+ ret = PTR_ERR(max98925->regmap_r);
+ dev_err(&i2c->dev,
+ "Failed to allocate regmap_r: %d\n", ret);
+ goto err_out;
+ }
+ }
+ if (max98925->regmap_r && max98925->regmap_l) {
+ max98925_regulator_config(i2c,
+ of_property_read_bool(i2c->dev.of_node,
+ "max98925,i2c-pull-up"), 1);
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925,
+ max98925_dai, ARRAY_SIZE(max98925_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev,
+ "Failed to register codec: %d\n", ret);
+ }
+err_out:
+ return ret;
+}
+
+static int max98925_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max98925_i2c_id[] = {
+ { "max98925L", MAX98925L },
+ { "max98925R", MAX98925R },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
+
+static struct i2c_driver max98925_i2c_driver = {
+ .driver = {
+ .name = "max98925",
+ .owner = THIS_MODULE,
+ .pm = NULL,
+ },
+ .probe = max98925_i2c_probe,
+ .remove = max98925_i2c_remove,
+ .id_table = max98925_i2c_id,
+};
+
+module_i2c_driver(max98925_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98925 Stereo driver");
+MODULE_AUTHOR("Ralph Birt <rdbirt(a)gmail.com>, Anish kumar <anish.kumar(a)maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h
new file mode 100644
index 0000000..36b42d4
--- /dev/null
+++ b/sound/soc/codecs/max98925.h
@@ -0,0 +1,845 @@
+/*
+ * max98925.h -- MAX98925 ALSA SoC Audio driver
+ *
+ * Copyright 2013-2015 Maxim Integrated Products
+ *
+ * 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.
+ */
+
+#ifndef _MAX98925_H
+#define _MAX98925_H
+
+/* Maximum number of MAX98925 devices in the system this driver can support */
+#define MAX_NUM_MAX98925 2
+#define MAX98925_VERSION 0x51
+#define MAX98925_VERSION1 0x80
+
+#define MAX98925_REVISION "0.00.0333"
+
+/*
+ * MAX98925 Register Definitions
+ */
+#define MAX98925_R000_VBAT_DATA 0x00
+#define MAX98925_R001_VBST_DATA 0x01
+#define MAX98925_R002_LIVE_STATUS0 0x02
+#define MAX98925_R003_LIVE_STATUS1 0x03
+#define MAX98925_R004_LIVE_STATUS2 0x04
+#define MAX98925_R005_STATE0 0x05
+#define MAX98925_R006_STATE1 0x06
+#define MAX98925_R007_STATE2 0x07
+#define MAX98925_R008_FLAG0 0x08
+#define MAX98925_R009_FLAG1 0x09
+#define MAX98925_R00A_FLAG2 0x0A
+#define MAX98925_R00B_IRQ_ENABLE0 0x0B
+#define MAX98925_R00C_IRQ_ENABLE1 0x0C
+#define MAX98925_R00D_IRQ_ENABLE2 0x0D
+#define MAX98925_R00E_IRQ_CLEAR0 0x0E
+#define MAX98925_R00F_IRQ_CLEAR1 0x0F
+#define MAX98925_R010_IRQ_CLEAR2 0x10
+#define MAX98925_R011_MAP0 0x11
+#define MAX98925_R012_MAP1 0x12
+#define MAX98925_R013_MAP2 0x13
+#define MAX98925_R014_MAP3 0x14
+#define MAX98925_R015_MAP4 0x15
+#define MAX98925_R016_MAP5 0x16
+#define MAX98925_R017_MAP6 0x17
+#define MAX98925_R018_MAP7 0x18
+#define MAX98925_R019_MAP8 0x19
+#define MAX98925_R01A_DAI_CLK_MODE1 0x1A
+#define MAX98925_R01B_DAI_CLK_MODE2 0x1B
+#define MAX98925_R01C_DAI_CLK_DIV_M_MSBS 0x1C
+#define MAX98925_R01D_DAI_CLK_DIV_M_LSBS 0x1D
+#define MAX98925_R01E_DAI_CLK_DIV_N_MSBS 0x1E
+#define MAX98925_R01F_DAI_CLK_DIV_N_LSBS 0x1F
+#define MAX98925_R020_FORMAT 0x20
+#define MAX98925_R021_TDM_SLOT_SELECT 0x21
+#define MAX98925_R022_DOUT_CFG_VMON 0x22
+#define MAX98925_R023_DOUT_CFG_IMON 0x23
+#define MAX98925_R024_DOUT_CFG_VBAT 0x24
+#define MAX98925_R025_DOUT_CFG_VBST 0x25
+#define MAX98925_R026_DOUT_CFG_FLAG 0x26
+#define MAX98925_R027_DOUT_HIZ_CFG1 0x27
+#define MAX98925_R028_DOUT_HIZ_CFG2 0x28
+#define MAX98925_R029_DOUT_HIZ_CFG3 0x29
+#define MAX98925_R02A_DOUT_HIZ_CFG4 0x2A
+#define MAX98925_R02B_DOUT_DRV_STRENGTH 0x2B
+#define MAX98925_R02C_FILTERS 0x2C
+#define MAX98925_R02D_GAIN 0x2D
+#define MAX98925_R02E_GAIN_RAMPING 0x2E
+#define MAX98925_R02F_SPK_AMP 0x2F
+#define MAX98925_R030_THRESHOLD 0x30
+#define MAX98925_R031_ALC_ATTACK 0x31
+#define MAX98925_R032_ALC_ATTEN_RLS 0x32
+#define MAX98925_R033_ALC_HOLD_RLS 0x33
+#define MAX98925_R034_ALC_CONFIGURATION 0x34
+#define MAX98925_R035_BOOST_CONVERTER 0x35
+#define MAX98925_R036_BLOCK_ENABLE 0x36
+#define MAX98925_R037_CONFIGURATION 0x37
+#define MAX98925_R038_GLOBAL_ENABLE 0x38
+#define MAX98925_R03A_BOOST_LIMITER 0x3A
+#define MAX98925_R0FF_VERSION 0xFF
+
+#define MAX98925_REG_CNT (MAX98925_R03A_BOOST_LIMITER+1)
+
+/* MAX98925 Register Bit Fields */
+
+/* MAX98925_R002_LIVE_STATUS0 */
+#define M98925_THERMWARN_STATUS_MASK (1<<3)
+#define M98925_THERMWARN_STATUS_SHIFT 3
+#define M98925_THERMWARN_STATUS_WIDTH 1
+#define M98925_THERMSHDN_STATUS_MASK (1<<1)
+#define M98925_THERMSHDN_STATUS_SHIFT 1
+#define M98925_THERMSHDN_STATUS_WIDTH 1
+
+/* MAX98925_R003_LIVE_STATUS1 */
+#define M98925_SPKCURNT_STATUS_MASK (1<<5)
+#define M98925_SPKCURNT_STATUS_SHIFT 5
+#define M98925_SPKCURNT_STATUS_WIDTH 1
+#define M98925_WATCHFAIL_STATUS_MASK (1<<4)
+#define M98925_WATCHFAIL_STATUS_SHIFT 4
+#define M98925_WATCHFAIL_STATUS_WIDTH 1
+#define M98925_ALCINFH_STATUS_MASK (1<<3)
+#define M98925_ALCINFH_STATUS_SHIFT 3
+#define M98925_ALCINFH_STATUS_WIDTH 1
+#define M98925_ALCACT_STATUS_MASK (1<<2)
+#define M98925_ALCACT_STATUS_SHIFT 2
+#define M98925_ALCACT_STATUS_WIDTH 1
+#define M98925_ALCMUT_STATUS_MASK (1<<1)
+#define M98925_ALCMUT_STATUS_SHIFT 1
+#define M98925_ALCMUT_STATUS_WIDTH 1
+#define M98925_ACLP_STATUS_MASK (1<<0)
+#define M98925_ACLP_STATUS_SHIFT 0
+#define M98925_ACLP_STATUS_WIDTH 1
+
+/* MAX98925_R004_LIVE_STATUS2 */
+#define M98925_SLOTOVRN_STATUS_MASK (1<<6)
+#define M98925_SLOTOVRN_STATUS_SHIFT 6
+#define M98925_SLOTOVRN_STATUS_WIDTH 1
+#define M98925_INVALSLOT_STATUS_MASK (1<<5)
+#define M98925_INVALSLOT_STATUS_SHIFT 5
+#define M98925_INVALSLOT_STATUS_WIDTH 1
+#define M98925_SLOTCNFLT_STATUS_MASK (1<<4)
+#define M98925_SLOTCNFLT_STATUS_SHIFT 4
+#define M98925_SLOTCNFLT_STATUS_WIDTH 1
+#define M98925_VBSTOVFL_STATUS_MASK (1<<3)
+#define M98925_VBSTOVFL_STATUS_SHIFT 3
+#define M98925_VBSTOVFL_STATUS_WIDTH 1
+#define M98925_VBATOVFL_STATUS_MASK (1<<2)
+#define M98925_VBATOVFL_STATUS_SHIFT 2
+#define M98925_VBATOVFL_STATUS_WIDTH 1
+#define M98925_IMONOVFL_STATUS_MASK (1<<1)
+#define M98925_IMONOVFL_STATUS_SHIFT 1
+#define M98925_IMONOVFL_STATUS_WIDTH 1
+#define M98925_VMONOVFL_STATUS_MASK (1<<0)
+#define M98925_VMONOVFL_STATUS_SHIFT 0
+#define M98925_VMONOVFL_STATUS_WIDTH 1
+
+/* MAX98925_R005_STATE0 */
+#define M98925_THERMWARN_END_STATE_MASK (1<<3)
+#define M98925_THERMWARN_END_STATE_SHIFT 3
+#define M98925_THERMWARN_END_STATE_WIDTH 1
+#define M98925_THERMWARN_BGN_STATE_MASK (1<<2)
+#define M98925_THERMWARN_BGN_STATE_SHIFT 1
+#define M98925_THERMWARN_BGN_STATE_WIDTH 1
+#define M98925_THERMSHDN_END_STATE_MASK (1<<1)
+#define M98925_THERMSHDN_END_STATE_SHIFT 1
+#define M98925_THERMSHDN_END_STATE_WIDTH 1
+#define M98925_THERMSHDN_BGN_STATE_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_STATE_SHIFT 0
+#define M98925_THERMSHDN_BGN_STATE_WIDTH 1
+
+/* MAX98925_R006_STATE1 */
+#define M98925_SPRCURNT_STATE_MASK (1<<5)
+#define M98925_SPRCURNT_STATE_SHIFT 5
+#define M98925_SPRCURNT_STATE_WIDTH 1
+#define M98925_WATCHFAIL_STATE_MASK (1<<4)
+#define M98925_WATCHFAIL_STATE_SHIFT 4
+#define M98925_WATCHFAIL_STATE_WIDTH 1
+#define M98925_ALCINFH_STATE_MASK (1<<3)
+#define M98925_ALCINFH_STATE_SHIFT 3
+#define M98925_ALCINFH_STATE_WIDTH 1
+#define M98925_ALCACT_STATE_MASK (1<<2)
+#define M98925_ALCACT_STATE_SHIFT 2
+#define M98925_ALCACT_STATE_WIDTH 1
+#define M98925_ALCMUT_STATE_MASK (1<<1)
+#define M98925_ALCMUT_STATE_SHIFT 1
+#define M98925_ALCMUT_STATE_WIDTH 1
+#define M98925_ALCP_STATE_MASK (1<<0)
+#define M98925_ALCP_STATE_SHIFT 0
+#define M98925_ALCP_STATE_WIDTH 1
+
+/* MAX98925_R007_STATE2 */
+#define M98925_SLOTOVRN_STATE_MASK (1<<6)
+#define M98925_SLOTOVRN_STATE_SHIFT 6
+#define M98925_SLOTOVRN_STATE_WIDTH 1
+#define M98925_INVALSLOT_STATE_MASK (1<<5)
+#define M98925_INVALSLOT_STATE_SHIFT 5
+#define M98925_INVALSLOT_STATE_WIDTH 1
+#define M98925_SLOTCNFLT_STATE_MASK (1<<4)
+#define M98925_SLOTCNFLT_STATE_SHIFT 4
+#define M98925_SLOTCNFLT_STATE_WIDTH 1
+#define M98925_VBSTOVFL_STATE_MASK (1<<3)
+#define M98925_VBSTOVFL_STATE_SHIFT 3
+#define M98925_VBSTOVFL_STATE_WIDTH 1
+#define M98925_VBATOVFL_STATE_MASK (1<<2)
+#define M98925_VBATOVFL_STATE_SHIFT 2
+#define M98925_VBATOVFL_STATE_WIDTH 1
+#define M98925_IMONOVFL_STATE_MASK (1<<1)
+#define M98925_IMONOVFL_STATE_SHIFT 1
+#define M98925_IMONOVFL_STATE_WIDTH 1
+#define M98925_VMONOVFL_STATE_MASK (1<<0)
+#define M98925_VMONOVFL_STATE_SHIFT 0
+#define M98925_VMONOVFL_STATE_WIDTH 1
+
+/* MAX98925_R008_FLAG0 */
+#define M98925_THERMWARN_END_FLAG_MASK (1<<3)
+#define M98925_THERMWARN_END_FLAG_SHIFT 3
+#define M98925_THERMWARN_END_FLAG_WIDTH 1
+#define M98925_THERMWARN_BGN_FLAG_MASK (1<<2)
+#define M98925_THERMWARN_BGN_FLAG_SHIFT 2
+#define M98925_THERMWARN_BGN_FLAG_WIDTH 1
+#define M98925_THERMSHDN_END_FLAG_MASK (1<<1)
+#define M98925_THERMSHDN_END_FLAG_SHIFT 1
+#define M98925_THERMSHDN_END_FLAG_WIDTH 1
+#define M98925_THERMSHDN_BGN_FLAG_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_FLAG_SHIFT 0
+#define M98925_THERMSHDN_BGN_FLAG_WIDTH 1
+
+/* MAX98925_R009_FLAG1 */
+#define M98925_SPKCURNT_FLAG_MASK (1<<5)
+#define M98925_SPKCURNT_FLAG_SHIFT 5
+#define M98925_SPKCURNT_FLAG_WIDTH 1
+#define M98925_WATCHFAIL_FLAG_MASK (1<<4)
+#define M98925_WATCHFAIL_FLAG_SHIFT 4
+#define M98925_WATCHFAIL_FLAG_WIDTH 1
+#define M98925_ALCINFH_FLAG_MASK (1<<3)
+#define M98925_ALCINFH_FLAG_SHIFT 3
+#define M98925_ALCINFH_FLAG_WIDTH 1
+#define M98925_ALCACT_FLAG_MASK (1<<2)
+#define M98925_ALCACT_FLAG_SHIFT 2
+#define M98925_ALCACT_FLAG_WIDTH 1
+#define M98925_ALCMUT_FLAG_MASK (1<<1)
+#define M98925_ALCMUT_FLAG_SHIFT 1
+#define M98925_ALCMUT_FLAG_WIDTH 1
+#define M98925_ALCP_FLAG_MASK (1<<0)
+#define M98925_ALCP_FLAG_SHIFT 0
+#define M98925_ALCP_FLAG_WIDTH 1
+
+/* MAX98925_R00A_FLAG2 */
+#define M98925_SLOTOVRN_FLAG_MASK (1<<6)
+#define M98925_SLOTOVRN_FLAG_SHIFT 6
+#define M98925_SLOTOVRN_FLAG_WIDTH 1
+#define M98925_INVALSLOT_FLAG_MASK (1<<5)
+#define M98925_INVALSLOT_FLAG_SHIFT 5
+#define M98925_INVALSLOT_FLAG_WIDTH 1
+#define M98925_SLOTCNFLT_FLAG_MASK (1<<4)
+#define M98925_SLOTCNFLT_FLAG_SHIFT 4
+#define M98925_SLOTCNFLT_FLAG_WIDTH 1
+#define M98925_VBSTOVFL_FLAG_MASK (1<<3)
+#define M98925_VBSTOVFL_FLAG_SHIFT 3
+#define M98925_VBSTOVFL_FLAG_WIDTH 1
+#define M98925_VBATOVFL_FLAG_MASK (1<<2)
+#define M98925_VBATOVFL_FLAG_SHIFT 2
+#define M98925_VBATOVFL_FLAG_WIDTH 1
+#define M98925_IMONOVFL_FLAG_MASK (1<<1)
+#define M98925_IMONOVFL_FLAG_SHIFT 1
+#define M98925_IMONOVFL_FLAG_WIDTH 1
+#define M98925_VMONOVFL_FLAG_MASK (1<<0)
+#define M98925_VMONOVFL_FLAG_SHIFT 0
+#define M98925_VMONOVFL_FLAG_WIDTH 1
+
+/* MAX98925_R00B_IRQ_ENABLE0 */
+#define M98925_THERMWARN_END_EN_MASK (1<<3)
+#define M98925_THERMWARN_END_EN_SHIFT 3
+#define M98925_THERMWARN_END_EN_WIDTH 1
+#define M98925_THERMWARN_BGN_EN_MASK (1<<2)
+#define M98925_THERMWARN_BGN_EN_SHIFT 2
+#define M98925_THERMWARN_BGN_EN_WIDTH 1
+#define M98925_THERMSHDN_END_EN_MASK (1<<1)
+#define M98925_THERMSHDN_END_EN_SHIFT 1
+#define M98925_THERMSHDN_END_EN_WIDTH 1
+#define M98925_THERMSHDN_BGN_EN_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_EN_SHIFT 0
+#define M98925_THERMSHDN_BGN_EN_WIDTH 1
+
+/* MAX98925_R00C_IRQ_ENABLE1 */
+#define M98925_SPKCURNT_EN_MASK (1<<5)
+#define M98925_SPKCURNT_EN_SHIFT 5
+#define M98925_SPKCURNT_EN_WIDTH 1
+#define M98925_WATCHFAIL_EN_MASK (1<<4)
+#define M98925_WATCHFAIL_EN_SHIFT 4
+#define M98925_WATCHFAIL_EN_WIDTH 1
+#define M98925_ALCINFH_EN_MASK (1<<3)
+#define M98925_ALCINFH_EN_SHIFT 3
+#define M98925_ALCINFH_EN_WIDTH 1
+#define M98925_ALCACT_EN_MASK (1<<2)
+#define M98925_ALCACT_EN_SHIFT 2
+#define M98925_ALCACT_EN_WIDTH 1
+#define M98925_ALCMUT_EN_MASK (1<<1)
+#define M98925_ALCMUT_EN_SHIFT 1
+#define M98925_ALCMUT_EN_WIDTH 1
+#define M98925_ALCP_EN_MASK (1<<0)
+#define M98925_ALCP_EN_SHIFT 0
+#define M98925_ALCP_EN_WIDTH 1
+
+/* MAX98925_R00D_IRQ_ENABLE2 */
+#define M98925_SLOTOVRN_EN_MASK (1<<6)
+#define M98925_SLOTOVRN_EN_SHIFT 6
+#define M98925_SLOTOVRN_EN_WIDTH 1
+#define M98925_INVALSLOT_EN_MASK (1<<5)
+#define M98925_INVALSLOT_EN_SHIFT 5
+#define M98925_INVALSLOT_EN_WIDTH 1
+#define M98925_SLOTCNFLT_EN_MASK (1<<4)
+#define M98925_SLOTCNFLT_EN_SHIFT 4
+#define M98925_SLOTCNFLT_EN_WIDTH 1
+#define M98925_VBSTOVFL_EN_MASK (1<<3)
+#define M98925_VBSTOVFL_EN_SHIFT 3
+#define M98925_VBSTOVFL_EN_WIDTH 1
+#define M98925_VBATOVFL_EN_MASK (1<<2)
+#define M98925_VBATOVFL_EN_SHIFT 2
+#define M98925_VBATOVFL_EN_WIDTH 1
+#define M98925_IMONOVFL_EN_MASK (1<<1)
+#define M98925_IMONOVFL_EN_SHIFT 1
+#define M98925_IMONOVFL_EN_WIDTH 1
+#define M98925_VMONOVFL_EN_MASK (1<<0)
+#define M98925_VMONOVFL_EN_SHIFT 0
+#define M98925_VMONOVFL_EN_WIDTH 1
+
+/* MAX98925_R00E_IRQ_CLEAR0 */
+#define M98925_THERMWARN_END_CLR_MASK (1<<3)
+#define M98925_THERMWARN_END_CLR_SHIFT 3
+#define M98925_THERMWARN_END_CLR_WIDTH 1
+#define M98925_THERMWARN_BGN_CLR_MASK (1<<2)
+#define M98925_THERMWARN_BGN_CLR_SHIFT 2
+#define M98925_THERMWARN_BGN_CLR_WIDTH 1
+#define M98925_THERMSHDN_END_CLR_MASK (1<<1)
+#define M98925_THERMSHDN_END_CLR_SHIFT 1
+#define M98925_THERMSHDN_END_CLR_WIDTH 1
+#define M98925_THERMSHDN_BGN_CLR_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_CLR_SHIFT 0
+#define M98925_THERMSHDN_BGN_CLR_WIDTH 1
+
+/* MAX98925_R00F_IRQ_CLEAR1 */
+#define M98925_SPKCURNT_CLR_MASK (1<<5)
+#define M98925_SPKCURNT_CLR_SHIFT 5
+#define M98925_SPKCURNT_CLR_WIDTH 1
+#define M98925_WATCHFAIL_CLR_MASK (1<<4)
+#define M98925_WATCHFAIL_CLR_SHIFT 4
+#define M98925_WATCHFAIL_CLR_WIDTH 1
+#define M98925_ALCINFH_CLR_MASK (1<<3)
+#define M98925_ALCINFH_CLR_SHIFT 3
+#define M98925_ALCINFH_CLR_WIDTH 1
+#define M98925_ALCACT_CLR_MASK (1<<2)
+#define M98925_ALCACT_CLR_SHIFT 2
+#define M98925_ALCACT_CLR_WIDTH 1
+#define M98925_ALCMUT_CLR_MASK (1<<1)
+#define M98925_ALCMUT_CLR_SHIFT 1
+#define M98925_ALCMUT_CLR_WIDTH 1
+#define M98925_ALCP_CLR_MASK (1<<0)
+#define M98925_ALCP_CLR_SHIFT 0
+#define M98925_ALCP_CLR_WIDTH 1
+
+/* MAX98925_R010_IRQ_CLEAR2 */
+#define M98925_SLOTOVRN_CLR_MASK (1<<6)
+#define M98925_SLOTOVRN_CLR_SHIFT 6
+#define M98925_SLOTOVRN_CLR_WIDTH 1
+#define M98925_INVALSLOT_CLR_MASK (1<<5)
+#define M98925_INVALSLOT_CLR_SHIFT 5
+#define M98925_INVALSLOT_CLR_WIDTH 1
+#define M98925_SLOTCNFLT_CLR_MASK (1<<4)
+#define M98925_SLOTCNFLT_CLR_SHIFT 4
+#define M98925_SLOTCNFLT_CLR_WIDTH 1
+#define M98925_VBSTOVFL_CLR_MASK (1<<3)
+#define M98925_VBSTOVFL_CLR_SHIFT 3
+#define M98925_VBSTOVFL_CLR_WIDTH 1
+#define M98925_VBATOVFL_CLR_MASK (1<<2)
+#define M98925_VBATOVFL_CLR_SHIFT 2
+#define M98925_VBATOVFL_CLR_WIDTH 1
+#define M98925_IMONOVFL_CLR_MASK (1<<1)
+#define M98925_IMONOVFL_CLR_SHIFT 1
+#define M98925_IMONOVFL_CLR_WIDTH 1
+#define M98925_VMONOVFL_CLR_MASK (1<<0)
+#define M98925_VMONOVFL_CLR_SHIFT 0
+#define M98925_VMONOVFL_CLR_WIDTH 1
+
+/* MAX98925_R011_MAP0 */
+#define M98925_ER_THERMWARN_EN_MASK (1<<7)
+#define M98925_ER_THERMWARN_EN_SHIFT 7
+#define M98925_ER_THERMWARN_EN_WIDTH 1
+#define M98925_ER_THERMWARN_MAP_MASK (0x07<<4)
+#define M98925_ER_THERMWARN_MAP_SHIFT 4
+#define M98925_ER_THERMWARN_MAP_WIDTH 3
+
+/* MAX98925_R012_MAP1 */
+#define M98925_ER_ALCMUT_EN_MASK (1<<7)
+#define M98925_ER_ALCMUT_EN_SHIFT 7
+#define M98925_ER_ALCMUT_EN_WIDTH 1
+#define M98925_ER_ALCMUT_MAP_MASK (0x07<<4)
+#define M98925_ER_ALCMUT_MAP_SHIFT 4
+#define M98925_ER_ALCMUT_MAP_WIDTH 3
+#define M98925_ER_ALCP_EN_MASK (1<<3)
+#define M98925_ER_ALCP_EN_SHIFT 3
+#define M98925_ER_ALCP_EN_WIDTH 1
+#define M98925_ER_ALCP_MAP_MASK (0x07<<0)
+#define M98925_ER_ALCP_MAP_SHIFT 0
+#define M98925_ER_ALCP_MAP_WIDTH 3
+
+/* MAX98925_R013_MAP2 */
+#define M98925_ER_ALCINFH_EN_MASK (1<<7)
+#define M98925_ER_ALCINFH_EN_SHIFT 7
+#define M98925_ER_ALCINFH_EN_WIDTH 1
+#define M98925_ER_ALCINFH_MAP_MASK (0x07<<4)
+#define M98925_ER_ALCINFH_MAP_SHIFT 4
+#define M98925_ER_ALCINFH_MAP_WIDTH 3
+#define M98925_ER_ALCACT_EN_MASK (1<<3)
+#define M98925_ER_ALCACT_EN_SHIFT 3
+#define M98925_ER_ALCACT_EN_WIDTH 1
+#define M98925_ER_ALCACT_MAP_MASK (0x07<<0)
+#define M98925_ER_ALCACT_MAP_SHIFT 0
+#define M98925_ER_ALCACT_MAP_WIDTH 3
+
+/* MAX98925_R014_MAP3 */
+#define M98925_ER_SPKCURNT_EN_MASK (1<<7)
+#define M98925_ER_SPKCURNT_EN_SHIFT 7
+#define M98925_ER_SPKCURNT_EN_WIDTH 1
+#define M98925_ER_SPKCURNT_MAP_MASK (0x07<<4)
+#define M98925_ER_SPKCURNT_MAP_SHIFT 4
+#define M98925_ER_SPKCURNT_MAP_WIDTH 3
+
+/* MAX98925_R015_MAP4 */
+/* RESERVED */
+
+/* MAX98925_R016_MAP5 */
+#define M98925_ER_IMONOVFL_EN_MASK (1<<7)
+#define M98925_ER_IMONOVFL_EN_SHIFT 7
+#define M98925_ER_IMONOVFL_EN_WIDTH 1
+#define M98925_ER_IMONOVFL_MAP_MASK (0x07<<4)
+#define M98925_ER_IMONOVFL_MAP_SHIFT 4
+#define M98925_ER_IMONOVFL_MAP_WIDTH 3
+#define M98925_ER_VMONOVFL_EN_MASK (1<<3)
+#define M98925_ER_VMONOVFL_EN_SHIFT 3
+#define M98925_ER_VMONOVFL_EN_WIDTH 1
+#define M98925_ER_VMONOVFL_MAP_MASK (0x07<<0)
+#define M98925_ER_VMONOVFL_MAP_SHIFT 0
+#define M98925_ER_VMONOVFL_MAP_WIDTH 3
+
+/* MAX98925_R017_MAP6 */
+#define M98925_ER_VBSTOVFL_EN_MASK (1<<7)
+#define M98925_ER_VBSTOVFL_EN_SHIFT 7
+#define M98925_ER_VBSTOVFL_EN_WIDTH 1
+#define M98925_ER_VBSTOVFL_MAP_MASK (0x07<<4)
+#define M98925_ER_VBSTOVFL_MAP_SHIFT 4
+#define M98925_ER_VBSTOVFL_MAP_WIDTH 3
+#define M98925_ER_VBATOVFL_EN_MASK (1<<3)
+#define M98925_ER_VBATOVFL_EN_SHIFT 3
+#define M98925_ER_VBATOVFL_EN_WIDTH 1
+#define M98925_ER_VBATOVFL_MAP_MASK (0x07<<0)
+#define M98925_ER_VBATOVFL_MAP_SHIFT 0
+#define M98925_ER_VBATOVFL_MAP_WIDTH 3
+
+/* MAX98925_R018_MAP7 */
+#define M98925_ER_INVALSLOT_EN_MASK (1<<7)
+#define M98925_ER_INVALSLOT_EN_SHIFT 7
+#define M98925_ER_INVALSLOT_EN_WIDTH 1
+#define M98925_ER_INVALSLOT_MAP_MASK (0x07<<4)
+#define M98925_ER_INVALSLOT_MAP_SHIFT 4
+#define M98925_ER_INVALSLOT_MAP_WIDTH 3
+#define M98925_ER_SLOTCNFLT_EN_MASK (1<<3)
+#define M98925_ER_SLOTCNFLT_EN_SHIFT 3
+#define M98925_ER_SLOTCNFLT_EN_WIDTH 1
+#define M98925_ER_SLOTCNFLT_MAP_MASK (0x07<<0)
+#define M98925_ER_SLOTCNFLT_MAP_SHIFT 0
+#define M98925_ER_SLOTCNFLT_MAP_WIDTH 3
+
+/* MAX98925_R019_MAP8 */
+#define M98925_ER_SLOTOVRN_EN_MASK (1<<3)
+#define M98925_ER_SLOTOVRN_EN_SHIFT 3
+#define M98925_ER_SLOTOVRN_EN_WIDTH 1
+#define M98925_ER_SLOTOVRN_MAP_MASK (0x07<<0)
+#define M98925_ER_SLOTOVRN_MAP_SHIFT 0
+#define M98925_ER_SLOTOVRN_MAP_WIDTH 3
+
+/* MAX98925_R01A_DAI_CLK_MODE1 */
+#define M98925_DAI_CLK_SOURCE_MASK (1<<6)
+#define M98925_DAI_CLK_SOURCE_SHIFT 6
+#define M98925_DAI_CLK_SOURCE_WIDTH 1
+#define M98925_MDLL_MULT_MASK (0x0F<<0)
+#define M98925_MDLL_MULT_SHIFT 0
+#define M98925_MDLL_MULT_WIDTH 4
+
+#define M98925_MDLL_MULT_MCLKx8 6
+#define M98925_MDLL_MULT_MCLKx16 8
+
+/* MAX98925_R01B_DAI_CLK_MODE2 */
+#define M98925_DAI_SR_MASK (0x0F<<4)
+#define M98925_DAI_SR_SHIFT 4
+#define M98925_DAI_SR_WIDTH 4
+#define M98925_DAI_MAS_MASK (1<<3)
+#define M98925_DAI_MAS_SHIFT 3
+#define M98925_DAI_MAS_WIDTH 1
+#define M98925_DAI_BSEL_MASK (0x07<<0)
+#define M98925_DAI_BSEL_SHIFT 0
+#define M98925_DAI_BSEL_WIDTH 3
+
+#define M98925_DAI_BSEL_32 (0 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_48 (1 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_64 (2 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_256 (6 << M98925_DAI_BSEL_SHIFT)
+
+/* MAX98925_R01C_DAI_CLK_DIV_M_MSBS */
+#define M98925_DAI_M_MSBS_MASK (0xFF<<0)
+#define M98925_DAI_M_MSBS_SHIFT 0
+#define M98925_DAI_M_MSBS_WIDTH 8
+
+/* MAX98925_R01D_DAI_CLK_DIV_M_LSBS */
+#define M98925_DAI_M_LSBS_MASK (0xFF<<0)
+#define M98925_DAI_M_LSBS_SHIFT 0
+#define M98925_DAI_M_LSBS_WIDTH 8
+
+/* MAX98925_R01E_DAI_CLK_DIV_N_MSBS */
+#define M98925_DAI_N_MSBS_MASK (0x7F<<0)
+#define M98925_DAI_N_MSBS_SHIFT 0
+#define M98925_DAI_N_MSBS_WIDTH 7
+
+/* MAX98925_R01F_DAI_CLK_DIV_N_LSBS */
+#define M98925_DAI_N_LSBS_MASK (0xFF<<0)
+#define M98925_DAI_N_LSBS_SHIFT 0
+#define M98925_DAI_N_LSBS_WIDTH 8
+
+/* MAX98925_R020_FORMAT */
+#define M98925_DAI_CHANSZ_MASK (0x03<<6)
+#define M98925_DAI_CHANSZ_SHIFT 6
+#define M98925_DAI_CHANSZ_WIDTH 2
+#define M98925_DAI_EXTBCLK_HIZ_MASK (1<<4)
+#define M98925_DAI_EXTBCLK_HIZ_SHIFT 4
+#define M98925_DAI_EXTBCLK_HIZ_WIDTH 1
+#define M98925_DAI_WCI_MASK (1<<3)
+#define M98925_DAI_WCI_SHIFT 3
+#define M98925_DAI_WCI_WIDTH 1
+#define M98925_DAI_BCI_MASK (1<<2)
+#define M98925_DAI_BCI_SHIFT 2
+#define M98925_DAI_BCI_WIDTH 1
+#define M98925_DAI_DLY_MASK (1<<1)
+#define M98925_DAI_DLY_SHIFT 1
+#define M98925_DAI_DLY_WIDTH 1
+#define M98925_DAI_TDM_MASK (1<<0)
+#define M98925_DAI_TDM_SHIFT 0
+#define M98925_DAI_TDM_WIDTH 1
+
+#define M98925_DAI_CHANSZ_16 (1 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_24 (2 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_32 (3 << M98925_DAI_CHANSZ_SHIFT)
+
+/* MAX98925_R021_TDM_SLOT_SELECT */
+#define M98925_DAI_DO_EN_MASK (1<<7)
+#define M98925_DAI_DO_EN_SHIFT 7
+#define M98925_DAI_DO_EN_WIDTH 1
+#define M98925_DAI_DIN_EN_MASK (1<<6)
+#define M98925_DAI_DIN_EN_SHIFT 6
+#define M98925_DAI_DIN_EN_WIDTH 1
+#define M98925_DAI_INR_SOURCE_MASK (0x07<<3)
+#define M98925_DAI_INR_SOURCE_SHIFT 3
+#define M98925_DAI_INR_SOURCE_WIDTH 3
+#define M98925_DAI_INL_SOURCE_MASK (0x07<<0)
+#define M98925_DAI_INL_SOURCE_SHIFT 0
+#define M98925_DAI_INL_SOURCE_WIDTH 3
+
+/* MAX98925_R022_DOUT_CFG_VMON */
+#define M98925_DAI_VMON_EN_MASK (1<<5)
+#define M98925_DAI_VMON_EN_SHIFT 5
+#define M98925_DAI_VMON_EN_WIDTH 1
+#define M98925_DAI_VMON_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_VMON_SLOT_SHIFT 0
+#define M98925_DAI_VMON_SLOT_WIDTH 5
+
+#define M98925_DAI_VMON_SLOT_00_01 (0 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_01_02 (1 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_02_03 (2 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_03_04 (3 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_04_05 (4 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_05_06 (5 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_06_07 (6 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_07_08 (7 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_08_09 (8 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_09_0A (9 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0A_0B (10 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0B_0C (11 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0C_0D (12 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0D_0E (13 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0E_0F (14 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0F_10 (15 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_10_11 (16 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_11_12 (17 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_12_13 (18 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_13_14 (19 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_14_15 (20 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_15_16 (21 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_16_17 (22 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_17_18 (23 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_18_19 (24 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_19_1A (25 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1A_1B (26 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1B_1C (27 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1C_1D (28 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1D_1E (29 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1E_1F (30 << M98925_DAI_VMON_SLOT_SHIFT)
+
+/* MAX98925_R023_DOUT_CFG_IMON */
+#define M98925_DAI_IMON_EN_MASK (1<<5)
+#define M98925_DAI_IMON_EN_SHIFT 5
+#define M98925_DAI_IMON_EN_WIDTH 1
+#define M98925_DAI_IMON_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_IMON_SLOT_SHIFT 0
+#define M98925_DAI_IMON_SLOT_WIDTH 5
+
+#define M98925_DAI_IMON_SLOT_00_01 (0 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_01_02 (1 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_02_03 (2 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_03_04 (3 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_04_05 (4 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_05_06 (5 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_06_07 (6 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_07_08 (7 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_08_09 (8 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_09_0A (9 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0A_0B (10 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0B_0C (11 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0C_0D (12 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0D_0E (13 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0E_0F (14 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0F_10 (15 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_10_11 (16 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_11_12 (17 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_12_13 (18 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_13_14 (19 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_14_15 (20 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_15_16 (21 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_16_17 (22 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_17_18 (23 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_18_19 (24 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_19_1A (25 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1A_1B (26 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1B_1C (27 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1C_1D (28 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1D_1E (29 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1E_1F (30 << M98925_DAI_IMON_SLOT_SHIFT)
+
+/* MAX98925_R024_DOUT_CFG_VBAT */
+#define M98925_DAI_VBAT_EN_MASK (1<<5)
+#define M98925_DAI_VBAT_EN_SHIFT 5
+#define M98925_DAI_VBAT_EN_WIDTH 1
+#define M98925_DAI_VBAT_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_VBAT_SLOT_SHIFT 0
+#define M98925_DAI_VBAT_SLOT_WIDTH 5
+
+/* MAX98925_R025_DOUT_CFG_VBST */
+#define M98925_DAI_VBST_EN_MASK (1<<5)
+#define M98925_DAI_VBST_EN_SHIFT 5
+#define M98925_DAI_VBST_EN_WIDTH 1
+#define M98925_DAI_VBST_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_VBST_SLOT_SHIFT 0
+#define M98925_DAI_VBST_SLOT_WIDTH 5
+
+/* MAX98925_R026_DOUT_CFG_FLAG */
+#define M98925_DAI_FLAG_EN_MASK (1<<5)
+#define M98925_DAI_FLAG_EN_SHIFT 5
+#define M98925_DAI_FLAG_EN_WIDTH 1
+#define M98925_DAI_FLAG_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_FLAG_SLOT_SHIFT 0
+#define M98925_DAI_FLAG_SLOT_WIDTH 5
+
+/* MAX98925_R027_DOUT_HIZ_CFG1 */
+#define M98925_DAI_SLOT_HIZ_CFG1_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG1_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG1_WIDTH 8
+
+/* MAX98925_R028_DOUT_HIZ_CFG2 */
+#define M98925_DAI_SLOT_HIZ_CFG2_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG2_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG2_WIDTH 8
+
+/* MAX98925_R029_DOUT_HIZ_CFG3 */
+#define M98925_DAI_SLOT_HIZ_CFG3_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG3_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG3_WIDTH 8
+
+/* MAX98925_R02A_DOUT_HIZ_CFG4 */
+#define M98925_DAI_SLOT_HIZ_CFG4_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG4_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG4_WIDTH 8
+
+/* MAX98925_R02B_DOUT_DRV_STRENGTH */
+#define M98925_DAI_OUT_DRIVE_MASK (0x03<<0)
+#define M98925_DAI_OUT_DRIVE_SHIFT 0
+#define M98925_DAI_OUT_DRIVE_WIDTH 2
+
+/* MAX98925_R02C_FILTERS */
+#define M98925_ADC_DITHER_EN_MASK (1<<7)
+#define M98925_ADC_DITHER_EN_SHIFT 7
+#define M98925_ADC_DITHER_EN_WIDTH 1
+#define M98925_IV_DCB_EN_MASK (1<<6)
+#define M98925_IV_DCB_EN_SHIFT 6
+#define M98925_IV_DCB_EN_WIDTH 1
+#define M98925_DAC_DITHER_EN_MASK (1<<4)
+#define M98925_DAC_DITHER_EN_SHIFT 4
+#define M98925_DAC_DITHER_EN_WIDTH 1
+#define M98925_DAC_FILTER_MODE_MASK (1<<3)
+#define M98925_DAC_FILTER_MODE_SHIFT 3
+#define M98925_DAC_FILTER_MODE_WIDTH 1
+#define M98925_DAC_HPF_MASK (0x07<<0)
+#define M98925_DAC_HPF_SHIFT 0
+#define M98925_DAC_HPF_WIDTH 3
+#define M98925_DAC_HPF_DISABLE (0 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_DC_BLOCK (1 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_100 (2 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_200 (3 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_400 (4 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_800 (5 << M98925_DAC_HPF_SHIFT)
+
+/* MAX98925_R02D_GAIN */
+#define M98925_DAC_IN_SEL_MASK (0x03<<5)
+#define M98925_DAC_IN_SEL_SHIFT 5
+#define M98925_DAC_IN_SEL_WIDTH 2
+#define M98925_SPK_GAIN_MASK (0x1F<<0)
+#define M98925_SPK_GAIN_SHIFT 0
+#define M98925_SPK_GAIN_WIDTH 5
+
+#define M98925_DAC_IN_SEL_LEFT_DAI (0 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_RIGHT_DAI (1 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_SUMMED_DAI (2 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << M98925_DAC_IN_SEL_SHIFT)
+
+/* MAX98925_R02E_GAIN_RAMPING */
+#define M98925_SPK_RMP_EN_MASK (1<<1)
+#define M98925_SPK_RMP_EN_SHIFT 1
+#define M98925_SPK_RMP_EN_WIDTH 1
+#define M98925_SPK_ZCD_EN_MASK (1<<0)
+#define M98925_SPK_ZCD_EN_SHIFT 0
+#define M98925_SPK_ZCD_EN_WIDTH 1
+
+/* MAX98925_R02F_SPK_AMP */
+#define M98925_SPK_MODE_MASK (1<<0)
+#define M98925_SPK_MODE_SHIFT 0
+#define M98925_SPK_MODE_WIDTH 1
+
+/* MAX98925_R030_THRESHOLD */
+#define M98925_ALC_EN_MASK (1<<5)
+#define M98925_ALC_EN_SHIFT 5
+#define M98925_ALC_EN_WIDTH 1
+#define M98925_ALC_TH_MASK (0x1F<<0)
+#define M98925_ALC_TH_SHIFT 0
+#define M98925_ALC_TH_WIDTH 5
+
+/* MAX98925_R031_ALC_ATTACK */
+#define M98925_ALC_ATK_STEP_MASK (0x0F<<4)
+#define M98925_ALC_ATK_STEP_SHIFT 4
+#define M98925_ALC_ATK_STEP_WIDTH 4
+#define M98925_ALC_ATK_RATE_MASK (0x7<<0)
+#define M98925_ALC_ATK_RATE_SHIFT 0
+#define M98925_ALC_ATK_RATE_WIDTH 3
+
+/* MAX98925_R032_ALC_ATTEN_RLS */
+#define M98925_ALC_MAX_ATTEN_MASK (0x0F<<4)
+#define M98925_ALC_MAX_ATTEN_SHIFT 4
+#define M98925_ALC_MAX_ATTEN_WIDTH 4
+#define M98925_ALC_RLS_RATE_MASK (0x7<<0)
+#define M98925_ALC_RLS_RATE_SHIFT 0
+#define M98925_ALC_RLS_RATE_WIDTH 3
+
+/* MAX98925_R033_ALC_HOLD_RLS */
+#define M98925_ALC_RLS_TGR_MASK (1<<0)
+#define M98925_ALC_RLS_TGR_SHIFT 0
+#define M98925_ALC_RLS_TGR_WIDTH 1
+
+/* MAX98925_R034_ALC_CONFIGURATION */
+#define M98925_ALC_MUTE_EN_MASK (1<<7)
+#define M98925_ALC_MUTE_EN_SHIFT 7
+#define M98925_ALC_MUTE_EN_WIDTH 1
+#define M98925_ALC_MUTE_DLY_MASK (0x07<<4)
+#define M98925_ALC_MUTE_DLY_SHIFT 4
+#define M98925_ALC_MUTE_DLY_WIDTH 3
+#define M98925_ALC_RLS_DBT_MASK (0x07<<0)
+#define M98925_ALC_RLS_DBT_SHIFT 0
+#define M98925_ALC_RLS_DBT_WIDTH 3
+
+/* MAX98925_R035_BOOST_CONVERTER */
+#define M98925_BST_SYNC_MASK (1<<7)
+#define M98925_BST_SYNC_SHIFT 7
+#define M98925_BST_SYNC_WIDTH 1
+#define M98925_BST_PHASE_MASK (0x03<<4)
+#define M98925_BST_PHASE_SHIFT 4
+#define M98925_BST_PHASE_WIDTH 2
+#define M98925_BST_SKIP_MODE_MASK (0x03<<0)
+#define M98925_BST_SKIP_MODE_SHIFT 0
+#define M98925_BST_SKIP_MODE_WIDTH 2
+
+/* MAX98925_R036_BLOCK_ENABLE */
+#define M98925_BST_EN_MASK (1<<7)
+#define M98925_BST_EN_SHIFT 7
+#define M98925_BST_EN_WIDTH 1
+#define M98925_WATCH_EN_MASK (1<<6)
+#define M98925_WATCH_EN_SHIFT 6
+#define M98925_WATCH_EN_WIDTH 1
+#define M98925_CLKMON_EN_MASK (1<<5)
+#define M98925_CLKMON_EN_SHIFT 5
+#define M98925_CLKMON_EN_WIDTH 1
+#define M98925_SPK_EN_MASK (1<<4)
+#define M98925_SPK_EN_SHIFT 4
+#define M98925_SPK_EN_WIDTH 1
+#define M98925_ADC_VBST_EN_MASK (1<<3)
+#define M98925_ADC_VBST_EN_SHIFT 3
+#define M98925_ADC_VBST_EN_WIDTH 1
+#define M98925_ADC_VBAT_EN_MASK (1<<2)
+#define M98925_ADC_VBAT_EN_SHIFT 2
+#define M98925_ADC_VBAT_EN_WIDTH 1
+#define M98925_ADC_IMON_EN_MASK (1<<1)
+#define M98925_ADC_IMON_EN_SHIFT 1
+#define M98925_ADC_IMON_EN_WIDTH 1
+#define M98925_ADC_VMON_EN_MASK (1<<0)
+#define M98925_ADC_VMON_EN_SHIFT 0
+#define M98925_ADC_VMON_EN_WIDTH 1
+
+/* MAX98925_R037_CONFIGURATION */
+#define M98925_BST_VOUT_MASK (0x0F<<4)
+#define M98925_BST_VOUT_SHIFT 4
+#define M98925_BST_VOUT_WIDTH 4
+#define M98925_THERMWARN_LEVEL_MASK (0x03<<2)
+#define M98925_THERMWARN_LEVEL_SHIFT 2
+#define M98925_THERMWARN_LEVEL_WIDTH 2
+#define M98925_WATCH_TIME_MASK (0x03<<0)
+#define M98925_WATCH_TIME_SHIFT 0
+#define M98925_WATCH_TIME_WIDTH 2
+
+/* MAX98925_R038_GLOBAL_ENABLE */
+#define M98925_EN_MASK (1<<7)
+#define M98925_EN_SHIFT 7
+#define M98925_EN_WIDTH 1
+
+/* MAX98925_R03A_BOOST_LIMITER */
+#define M98925_BST_ILIM_MASK (0x1F<<3)
+#define M98925_BST_ILIM_SHIFT 3
+#define M98925_BST_ILIM_WIDTH 5
+
+/* MAX98925_R0FF_VERSION */
+#define M98925_REV_ID_MASK (0xFF<<0)
+#define M98925_REV_ID_SHIFT 0
+#define M98925_REV_ID_WIDTH 8
+
+struct max98925_cdata {
+ unsigned int rate;
+ unsigned int fmt;
+};
+
+struct max98925_priv {
+ struct regmap *regmap_l;
+ struct regmap *regmap_r;
+ struct snd_soc_codec *codec;
+ struct max98925_pdata *pdata;
+ unsigned int spk_gain;
+ unsigned int sysclk;
+ unsigned int iv_status;
+ struct max98925_cdata dai[1];
+};
+#endif
--
1.9.3
3
4
Signed-off-by: Anish Kumar <yesanishhere(a)gmail.com>
---
sound/soc/codecs/Kconfig | 9 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98925.c | 843 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/max98925.h | 845 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1699 insertions(+)
create mode 100644 sound/soc/codecs/max98925.c
create mode 100644 sound/soc/codecs/max98925.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 45b7256..7d9002c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -47,6 +47,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
+ select SND_SOC_MAX98925 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
@@ -285,6 +286,14 @@ config SND_SOC_MAX9850
config SND_SOC_OMAP_HDMI_CODEC
tristate
+config SND_SOC_MAX98925
+ tristate "Support MAX98925 audio codec"
+ depends on I2C
+ help
+ MAX98925 is a high-efficiency mono
+ Class DG audio amplifier. Use this
+ option to enable the codec.
+
config SND_SOC_PCM3008
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6a3b3c3..d439d47 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -38,6 +38,7 @@ snd-soc-max98088-objs := max98088.o
snd-soc-max98090-objs := max98090.o
snd-soc-max98095-objs := max98095.o
snd-soc-max9850-objs := max9850.o
+snd-soc-max98925-objs := max98925.o
snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
@@ -233,6 +234,7 @@ obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o
+obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
new file mode 100644
index 0000000..35af23b
--- /dev/null
+++ b/sound/soc/codecs/max98925.c
@@ -0,0 +1,843 @@
+/*
+ * max98925.c -- ALSA SoC Stereo MAX98925 driver
+ * Copyright 2013-15 Maxim Integrated Products
+ * 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.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98925.h"
+
+static const char *const dai_text[] = {
+ "left", "right", "leftright", "leftrightdiv2",
+};
+
+static const char *const hpf_text[] = {
+ "disable", "dc_block", "100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static struct reg_default max98925_reg[] = {
+ { 0x00, 0x00 }, /* Battery Voltage Data */
+ { 0x01, 0x00 }, /* Boost Voltage Data */
+ { 0x02, 0x00 }, /* Live Status0 */
+ { 0x03, 0x00 }, /* Live Status1 */
+ { 0x04, 0x00 }, /* Live Status2 */
+ { 0x05, 0x00 }, /* State0 */
+ { 0x06, 0x00 }, /* State1 */
+ { 0x07, 0x00 }, /* State2 */
+ { 0x08, 0x00 }, /* Flag0 */
+ { 0x09, 0x00 }, /* Flag1 */
+ { 0x0A, 0x00 }, /* Flag2 */
+ { 0x0B, 0x00 }, /* IRQ Enable0 */
+ { 0x0C, 0x00 }, /* IRQ Enable1 */
+ { 0x0D, 0x00 }, /* IRQ Enable2 */
+ { 0x0E, 0x00 }, /* IRQ Clear0 */
+ { 0x0F, 0x00 }, /* IRQ Clear1 */
+ { 0x10, 0x00 }, /* IRQ Clear2 */
+ { 0x11, 0xC0 }, /* Map0 */
+ { 0x12, 0x00 }, /* Map1 */
+ { 0x13, 0x00 }, /* Map2 */
+ { 0x14, 0xF0 }, /* Map3 */
+ { 0x15, 0x00 }, /* Map4 */
+ { 0x16, 0xAB }, /* Map5 */
+ { 0x17, 0x89 }, /* Map6 */
+ { 0x18, 0x00 }, /* Map7 */
+ { 0x19, 0x00 }, /* Map8 */
+ { 0x1A, 0x06 }, /* DAI Clock Mode 1 */
+ { 0x1B, 0xC0 }, /* DAI Clock Mode 2 */
+ { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */
+ { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */
+ { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */
+ { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */
+ { 0x20, 0x50 }, /* Format */
+ { 0x21, 0x00 }, /* TDM Slot Select */
+ { 0x22, 0x00 }, /* DOUT Configuration VMON */
+ { 0x23, 0x00 }, /* DOUT Configuration IMON */
+ { 0x24, 0x00 }, /* DOUT Configuration VBAT */
+ { 0x25, 0x00 }, /* DOUT Configuration VBST */
+ { 0x26, 0x00 }, /* DOUT Configuration FLAG */
+ { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */
+ { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */
+ { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */
+ { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */
+ { 0x2B, 0x02 }, /* DOUT Drive Strength */
+ { 0x2C, 0x90 }, /* Filters */
+ { 0x2D, 0x00 }, /* Gain */
+ { 0x2E, 0x02 }, /* Gain Ramping */
+ { 0x2F, 0x00 }, /* Speaker Amplifier */
+ { 0x30, 0x0A }, /* Threshold */
+ { 0x31, 0x00 }, /* ALC Attack */
+ { 0x32, 0x80 }, /* ALC Atten and Release */
+ { 0x33, 0x00 }, /* ALC Infinite Hold Release */
+ { 0x34, 0x92 }, /* ALC Configuration */
+ { 0x35, 0x01 }, /* Boost Converter */
+ { 0x36, 0x00 }, /* Block Enable */
+ { 0x37, 0x00 }, /* Configuration */
+ { 0x38, 0x00 }, /* Global Enable */
+ { 0x3A, 0x00 }, /* Boost Limiter */
+ { 0xFF, 0x50 }, /* Revision ID */
+};
+
+static int max98925_reg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, unsigned int reg,
+ unsigned int mask, unsigned int shift)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ regmap_update_bits(max98925->regmap, reg, mask, sel<<shift);
+ dev_dbg(codec->dev, "%s: register 0x%02X, value 0x%02X\n",
+ __func__, reg, sel);
+ return 0;
+}
+
+static const struct soc_enum max98925_enum[] = {
+ SOC_ENUM_SINGLE(MAX98925_R02D_GAIN, 5, 4, dai_text),
+ SOC_ENUM_SINGLE(MAX98925_R02C_FILTERS, 0, 6, hpf_text),
+};
+
+static const struct snd_kcontrol_new max98925_dai_sel =
+ SOC_DAPM_ENUM("Route", max98925_enum[0]);
+
+static const struct snd_kcontrol_new max98925_hpf_sel =
+ SOC_DAPM_ENUM("Route", max98925_enum[1]);
+
+static int max98925_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R036_BLOCK_ENABLE,
+ M98925_BST_EN_MASK |
+ M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK,
+ M98925_BST_EN_MASK |
+ M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK);
+ regmap_write(max98925->regmap,
+ MAX98925_R038_GLOBAL_ENABLE, M98925_EN_MASK);
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("DAI_IN_MUX MUX", SND_SOC_NOPM, 0, 0,
+ &max98925_dai_sel),
+ SND_SOC_DAPM_MUX("R02C_FILTER MUX", SND_SOC_NOPM, 0, 0,
+ &max98925_hpf_sel),
+ SND_SOC_DAPM_DAC_E("amp_enable", NULL,
+ MAX98925_R036_BLOCK_ENABLE,
+ M98925_SPK_EN_SHIFT, 0,
+ max98925_dac_event, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98925_audio_map[] = {
+ {"DAI_IN_MUX MUX", "left", "DAI_OUT"},
+ {"DAI_IN_MUX MUX", "right", "DAI_OUT"},
+ {"DAI_IN_MUX MUX", "leftright", "DAI_OUT"},
+ {"DAI_IN_MUX MUX", "leftrightdiv2", "DAI_OUT"},
+ {"R02C_FILTER MUX", "disable", "DAI_IN_MUX MUX"},
+ {"R02C_FILTER MUX", "dc_block", "DAI_IN_MUX MUX"},
+ {"R02C_FILTER MUX", "100Hz", "DAI_IN_MUX MUX"},
+ {"R02C_FILTER MUX", "200Hz", "DAI_IN_MUX MUX"},
+ {"R02C_FILTER MUX", "400Hz", "DAI_IN_MUX MUX"},
+ {"R02C_FILTER MUX", "800Hz", "DAI_IN_MUX MUX"},
+ {"amp_enable", NULL, "R02C_FILTER MUX"},
+ {"BE_OUT", NULL, "amp_enable"},
+};
+
+static bool max98925_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98925_R000_VBAT_DATA:
+ case MAX98925_R001_VBST_DATA:
+ case MAX98925_R002_LIVE_STATUS0:
+ case MAX98925_R003_LIVE_STATUS1:
+ case MAX98925_R004_LIVE_STATUS2:
+ case MAX98925_R005_STATE0:
+ case MAX98925_R006_STATE1:
+ case MAX98925_R007_STATE2:
+ case MAX98925_R008_FLAG0:
+ case MAX98925_R009_FLAG1:
+ case MAX98925_R00A_FLAG2:
+ case MAX98925_R0FF_VERSION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool max98925_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98925_R00E_IRQ_CLEAR0:
+ case MAX98925_R00F_IRQ_CLEAR1:
+ case MAX98925_R010_IRQ_CLEAR2:
+ case MAX98925_R033_ALC_HOLD_RLS:
+ return false;
+ default:
+ return true;
+ }
+}
+
+DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0);
+
+static int max98925_spk_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = max98925->spk_gain;
+ dev_dbg(codec->dev, "%s: spk_gain setting returned %d\n", __func__,
+ (int) ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int max98925_spk_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ if (sel < ((1 << M98925_SPK_GAIN_WIDTH) - 1)) {
+ regmap_update_bits(max98925->regmap, MAX98925_R02D_GAIN,
+ M98925_SPK_GAIN_MASK, sel << M98925_SPK_GAIN_SHIFT);
+ max98925->spk_gain = sel;
+
+ dev_dbg(codec->dev, "%s: spk_gain set to %d\n", __func__, sel);
+ } else {
+ dev_dbg(codec->dev, "%s: valid speaker gain settings: %d to %d\n",
+ __func__, 0,
+ ((1 << M98925_SPK_GAIN_WIDTH) - 1));
+ }
+ return 0;
+}
+
+static int max98925_reg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, unsigned int reg,
+ unsigned int mask, unsigned int shift)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ int data;
+
+ regmap_read(max98925->regmap, reg, &data);
+ ucontrol->value.integer.value[0] =
+ (data & mask) >> shift;
+ return 0;
+}
+
+static int max98925_spk_ramp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_RMP_EN_MASK, M98925_SPK_RMP_EN_SHIFT);
+}
+
+static int max98925_spk_ramp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_RMP_EN_MASK, M98925_SPK_RMP_EN_SHIFT);
+}
+
+static int max98925_spk_zcd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_ZCD_EN_MASK, M98925_SPK_ZCD_EN_SHIFT);
+}
+
+static int max98925_spk_zcd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R02E_GAIN_RAMPING,
+ M98925_SPK_ZCD_EN_MASK, M98925_SPK_ZCD_EN_SHIFT);
+}
+
+static int max98925_alc_en_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_EN_MASK, M98925_ALC_EN_SHIFT);
+}
+
+static int max98925_alc_en_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_EN_MASK, M98925_ALC_EN_SHIFT);
+}
+
+static int max98925_alc_threshold_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_TH_MASK, M98925_ALC_TH_SHIFT);
+}
+
+static int max98925_alc_threshold_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R030_THRESHOLD,
+ M98925_ALC_TH_MASK, M98925_ALC_TH_SHIFT);
+}
+
+static const char * const max98925_boost_voltage_text[] = {
+ "8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V",
+ "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V"
+};
+
+static const struct soc_enum max98925_boost_voltage_enum =
+ SOC_ENUM_SINGLE(MAX98925_R037_CONFIGURATION, M98925_BST_VOUT_SHIFT, 15,
+ max98925_boost_voltage_text);
+
+static int max98925_boost_voltage_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_get(kcontrol, ucontrol, MAX98925_R037_CONFIGURATION,
+ M98925_BST_VOUT_MASK, M98925_BST_VOUT_SHIFT);
+}
+
+static int max98925_boost_voltage_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return max98925_reg_put(kcontrol, ucontrol, MAX98925_R037_CONFIGURATION,
+ M98925_BST_VOUT_MASK, M98925_BST_VOUT_SHIFT);
+}
+
+static const struct snd_kcontrol_new max98925_snd_controls[] = {
+
+ SOC_SINGLE_EXT_TLV("Speaker Gain", MAX98925_R02D_GAIN,
+ M98925_SPK_GAIN_SHIFT, (1<<M98925_SPK_GAIN_WIDTH)-1, 0,
+ max98925_spk_gain_get, max98925_spk_gain_put, max98925_spk_tlv),
+
+ SOC_SINGLE_EXT("Speaker Ramp", 0, 0, 1, 0,
+ max98925_spk_ramp_get, max98925_spk_ramp_put),
+
+ SOC_SINGLE_EXT("Speaker ZCD", 0, 0, 1, 0,
+ max98925_spk_zcd_get, max98925_spk_zcd_put),
+
+ SOC_SINGLE_EXT("ALC Enable", 0, 0, 1, 0,
+ max98925_alc_en_get, max98925_alc_en_put),
+
+ SOC_SINGLE_EXT("ALC Threshold", 0, 0, (1<<M98925_ALC_TH_WIDTH)-1, 0,
+ max98925_alc_threshold_get, max98925_alc_threshold_put),
+
+ SOC_ENUM_EXT("Boost Output Voltage", max98925_boost_voltage_enum,
+ max98925_boost_voltage_get, max98925_boost_voltage_put),
+};
+
+/* codec sample rate and n/m dividers parameter table */
+static const struct {
+ int rate;
+ int sr;
+ int divisors[3][2];
+} rate_table[] = {
+ {
+ .rate = 8000,
+ .sr = 0,
+ .divisors = { {1, 375}, {5, 1764}, {1, 384} }
+ },
+ {
+ .rate = 11025,
+ .sr = 1,
+ .divisors = { {147, 40000}, {1, 256}, {147, 40960} }
+ },
+ {
+ .rate = 12000,
+ .sr = 2,
+ .divisors = { {1, 250}, {5, 1176}, {1, 256} }
+ },
+ {
+ .rate = 16000,
+ .sr = 3,
+ .divisors = { {2, 375}, {5, 882}, {1, 192} }
+ },
+ {
+ .rate = 22050,
+ .sr = 4,
+ .divisors = { {147, 20000}, {1, 128}, {147, 20480} }
+ },
+ {
+ .rate = 24000,
+ .sr = 5,
+ .divisors = { {1, 125}, {5, 588}, {1, 128} }
+ },
+ {
+ .rate = 32000,
+ .sr = 6,
+ .divisors = { {4, 375}, {5, 441}, {1, 96} }
+ },
+ {
+ .rate = 44100,
+ .sr = 7,
+ .divisors = { {147, 10000}, {1, 64}, {147, 10240} }
+ },
+ {
+ .rate = 48000,
+ .sr = 8,
+ .divisors = { {2, 125}, {5, 294}, {1, 64} }
+ },
+};
+
+static inline int max98925_rate_value(int rate,
+ int clock, int *value, int *n, int *m)
+{
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i].rate >= rate) {
+ *value = rate_table[i].sr;
+ *n = rate_table[i].divisors[clock][0];
+ *m = rate_table[i].divisors[clock][1];
+ ret = 0;
+ break;
+ }
+ }
+ pr_debug("%s: sample rate is %d, returning %d\n",
+ __func__, rate_table[i].rate, *value);
+ return ret;
+}
+
+static void max98925_set_sense_data(struct max98925_priv *max98925)
+{
+ /*
+ * 1. set VMON slots
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R022_DOUT_CFG_VMON,
+ M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK);
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R022_DOUT_CFG_VMON,
+ M98925_DAI_VMON_SLOT_MASK, max98925->v_slot);
+ /*
+ * 2. set IMON slots
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R023_DOUT_CFG_IMON,
+ M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK);
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R023_DOUT_CFG_IMON,
+ M98925_DAI_IMON_SLOT_MASK, max98925->i_slot);
+}
+
+static void max98925_set_slave(struct max98925_priv *max98925)
+{
+ /*
+ * 1. set DAI to slave mode
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_MAS_MASK, 0);
+ max98925_set_sense_data(max98925);
+}
+
+static void max98925_set_master(struct max98925_priv *max98925)
+{
+ /*
+ * set left channel DAI to master mode, right channel always slave
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK);
+}
+
+static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ 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:
+ max98925_set_slave(max98925);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ max98925_set_master(max98925);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "DAI clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ invert = M98925_DAI_WCI_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ invert = M98925_DAI_BCI_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "DAI invert mode unsupported");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98925->regmap, MAX98925_R020_FORMAT,
+ M98925_DAI_BCI_MASK | M98925_DAI_BCI_MASK, invert);
+ return 0;
+}
+
+static int max98925_set_clock(struct max98925_priv *max98925,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int dai_sr = 0;
+ unsigned int clock;
+ unsigned int mdll;
+ unsigned int n;
+ unsigned int m;
+ int rate = params_rate(params);
+
+ /* BCLK/LRCLK ratio calculation */
+ int blr_clk_ratio = params_channels(params) * max98925->ch_size;
+ switch (blr_clk_ratio) {
+ case 32:
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_32);
+ break;
+ case 48:
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_48);
+ break;
+ case 64:
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (max98925->sysclk) {
+ case 6000000:
+ clock = 0;
+ mdll = M98925_MDLL_MULT_MCLKx16;
+ break;
+ case 11289600:
+ clock = 1;
+ mdll = M98925_MDLL_MULT_MCLKx8;
+ break;
+ case 12000000:
+ clock = 0;
+ mdll = M98925_MDLL_MULT_MCLKx8;
+ break;
+ case 12288000:
+ clock = 2;
+ mdll = M98925_MDLL_MULT_MCLKx8;
+ break;
+ default:
+ dev_info(max98925->codec->dev, "unsupported sysclk %d\n",
+ max98925->sysclk);
+ return -EINVAL;
+ }
+
+ if (max98925_rate_value(rate, clock, &dai_sr, &n, &m))
+ return -EINVAL;
+
+ /*
+ * 1. set DAI_SR to correct LRCLK frequency
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01B_DAI_CLK_MODE2,
+ M98925_DAI_SR_MASK, dai_sr << M98925_DAI_SR_SHIFT);
+ /*
+ * 2. set DAI m divider
+ */
+ regmap_write(max98925->regmap,
+ MAX98925_R01C_DAI_CLK_DIV_M_MSBS, m >> 8);
+ regmap_write(max98925->regmap,
+ MAX98925_R01D_DAI_CLK_DIV_M_LSBS, m & 0xFF);
+ /*
+ * 3. set DAI n divider
+ */
+ regmap_write(max98925->regmap,
+ MAX98925_R01E_DAI_CLK_DIV_N_MSBS, n >> 8);
+ regmap_write(max98925->regmap,
+ MAX98925_R01F_DAI_CLK_DIV_N_LSBS, n & 0xFF);
+ /*
+ * 4. set MDLL
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_MDLL_MULT_MASK, mdll << M98925_MDLL_MULT_SHIFT);
+ return 0;
+}
+
+static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R020_FORMAT,
+ M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16);
+ max98925->ch_size = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R020_FORMAT,
+ M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32);
+ max98925->ch_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R020_FORMAT,
+ M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32);
+ max98925->ch_size = 32;
+ break;
+ default:
+ pr_err("%s: format unsupported %d",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "%s: format supported %d",
+ __func__, params_format(params));
+ return max98925_set_clock(max98925, params);
+}
+
+static int max98925_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case 0:
+ /*
+ * 1. use MCLK for Left channel, right channel always BCLK
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_DAI_CLK_SOURCE_MASK, 0);
+ break;
+ case 1:
+ /*
+ * configure dai clock source to BCLK instead of MCLK(default)
+ */
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R01A_DAI_CLK_MODE1,
+ M98925_DAI_CLK_SOURCE_MASK,
+ M98925_DAI_CLK_SOURCE_MASK);
+ break;
+ default:
+ return -EINVAL;
+ }
+ max98925->sysclk = freq;
+ return 0;
+}
+
+static int max98925_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct max98925_priv *max98925 =
+ snd_soc_codec_get_drvdata(codec_dai->codec);
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ dev_dbg(codec->dev, "%s: mute %d\n", __func__, mute);
+ if (mute) {
+ regmap_update_bits(max98925->regmap, MAX98925_R02D_GAIN,
+ M98925_SPK_GAIN_MASK, 0x00);
+
+ regmap_update_bits(max98925->regmap,
+ MAX98925_R038_GLOBAL_ENABLE,
+ M98925_EN_MASK, 0x0);
+ }
+ return 0;
+}
+
+#define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops max98925_dai_ops = {
+ .set_sysclk = max98925_dai_set_sysclk,
+ .set_fmt = max98925_dai_set_fmt,
+ .hw_params = max98925_dai_hw_params,
+ .digital_mute = max98925_dai_digital_mute,
+};
+
+static struct snd_soc_dai_driver max98925_dai[] = {
+ {
+ .name = "max98925-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = MAX98925_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = MAX98925_FORMATS,
+ },
+ .ops = &max98925_dai_ops,
+ }
+};
+
+static int max98925_probe(struct snd_soc_codec *codec)
+{
+ struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ int reg = 0;
+
+ dev_info(codec->dev, "build number %s\n", MAX98925_REVISION);
+
+ max98925->codec = codec;
+ codec->control_data = max98925->regmap;
+ ret = regmap_read(max98925->regmap,
+ MAX98925_R0FF_VERSION, ®);
+ if ((ret < 0) ||
+ ((reg != MAX98925_VERSION) &&
+ (reg != MAX98925_VERSION1))) {
+ dev_err(codec->dev,
+ "device initialization error (%d 0x%02X)\n",
+ ret, reg);
+ goto err_access;
+ }
+ regmap_write(max98925->regmap, MAX98925_R038_GLOBAL_ENABLE, 0x00);
+ /* It's not the default but we need to set DAI_DLY */
+ regmap_write(max98925->regmap,
+ MAX98925_R020_FORMAT, M98925_DAI_DLY_MASK);
+ regmap_write(max98925->regmap, MAX98925_R021_TDM_SLOT_SELECT, 0xC8);
+ regmap_write(max98925->regmap, MAX98925_R027_DOUT_HIZ_CFG1, 0xFF);
+ regmap_write(max98925->regmap, MAX98925_R028_DOUT_HIZ_CFG2, 0xFF);
+ regmap_write(max98925->regmap, MAX98925_R029_DOUT_HIZ_CFG3, 0xFF);
+ regmap_write(max98925->regmap, MAX98925_R02A_DOUT_HIZ_CFG4, 0xF0);
+ regmap_write(max98925->regmap, MAX98925_R02C_FILTERS, 0xD8);
+ regmap_write(max98925->regmap, MAX98925_R034_ALC_CONFIGURATION, 0xF8);
+ regmap_write(max98925->regmap, MAX98925_R037_CONFIGURATION, 0xF0);
+
+ /* Disable ALC muting */
+ regmap_write(max98925->regmap, MAX98925_R03A_BOOST_LIMITER, 0xF8);
+ dev_info(codec->dev, "device version 0x%02X\n", reg);
+err_access:
+ return ret;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98925 = {
+ .probe = max98925_probe,
+ .controls = max98925_snd_controls,
+ .num_controls = ARRAY_SIZE(max98925_snd_controls),
+ .dapm_routes = max98925_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98925_audio_map),
+ .dapm_widgets = max98925_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets),
+};
+
+static struct regmap_config max98925_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX98925_R0FF_VERSION,
+ .reg_defaults = max98925_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98925_reg),
+ .volatile_reg = max98925_volatile_register,
+ .readable_reg = max98925_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int max98925_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ u32 value;
+ struct max98925_priv *max98925;
+
+ dev_info(&i2c->dev, "%s: enter, device '%s'\n", __func__, id->name);
+ max98925 = devm_kzalloc(&i2c->dev,
+ sizeof(*max98925), GFP_KERNEL);
+ if (!max98925)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max98925);
+ max98925->regmap = devm_regmap_init_i2c(i2c, &max98925_regmap);
+ if (IS_ERR(max98925->regmap)) {
+ ret = PTR_ERR(max98925->regmap);
+ dev_err(&i2c->dev,
+ "Failed to allocate regmap: %d\n", ret);
+ goto err_out;
+ }
+
+ if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
+ if (value > M98925_DAI_VMON_SLOT_1E_1F) {
+ dev_err(&i2c->dev, "vmon slot number is wrong:\n");
+ return -EINVAL;
+ }
+ max98925->v_slot = value;
+ }
+ if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) {
+ if (value > M98925_DAI_IMON_SLOT_1E_1F) {
+ dev_err(&i2c->dev, "imon slot number is wrong:\n");
+ return -EINVAL;
+ }
+ max98925->i_slot = value;
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925,
+ max98925_dai, ARRAY_SIZE(max98925_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev,
+ "Failed to register codec: %d\n", ret);
+err_out:
+ return ret;
+}
+
+static int max98925_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max98925_i2c_id[] = {
+ { "max98925", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
+
+static struct i2c_driver max98925_i2c_driver = {
+ .driver = {
+ .name = "max98925",
+ .owner = THIS_MODULE,
+ .pm = NULL,
+ },
+ .probe = max98925_i2c_probe,
+ .remove = max98925_i2c_remove,
+ .id_table = max98925_i2c_id,
+};
+
+module_i2c_driver(max98925_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98925 driver");
+MODULE_AUTHOR("Ralph Birt <rdbirt(a)gmail.com>, Anish kumar <anish.kumar(a)maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h
new file mode 100644
index 0000000..1842c15
--- /dev/null
+++ b/sound/soc/codecs/max98925.h
@@ -0,0 +1,845 @@
+/*
+ * max98925.h -- MAX98925 ALSA SoC Audio driver
+ *
+ * Copyright 2013-2015 Maxim Integrated Products
+ *
+ * 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.
+ */
+
+#ifndef _MAX98925_H
+#define _MAX98925_H
+
+/* Maximum number of MAX98925 devices in the system this driver can support */
+#define MAX_NUM_MAX98925 2
+#define MAX98925_VERSION 0x51
+#define MAX98925_VERSION1 0x80
+
+#define MAX98925_REVISION "0.00.0333"
+
+/*
+ * MAX98925 Register Definitions
+ */
+#define MAX98925_R000_VBAT_DATA 0x00
+#define MAX98925_R001_VBST_DATA 0x01
+#define MAX98925_R002_LIVE_STATUS0 0x02
+#define MAX98925_R003_LIVE_STATUS1 0x03
+#define MAX98925_R004_LIVE_STATUS2 0x04
+#define MAX98925_R005_STATE0 0x05
+#define MAX98925_R006_STATE1 0x06
+#define MAX98925_R007_STATE2 0x07
+#define MAX98925_R008_FLAG0 0x08
+#define MAX98925_R009_FLAG1 0x09
+#define MAX98925_R00A_FLAG2 0x0A
+#define MAX98925_R00B_IRQ_ENABLE0 0x0B
+#define MAX98925_R00C_IRQ_ENABLE1 0x0C
+#define MAX98925_R00D_IRQ_ENABLE2 0x0D
+#define MAX98925_R00E_IRQ_CLEAR0 0x0E
+#define MAX98925_R00F_IRQ_CLEAR1 0x0F
+#define MAX98925_R010_IRQ_CLEAR2 0x10
+#define MAX98925_R011_MAP0 0x11
+#define MAX98925_R012_MAP1 0x12
+#define MAX98925_R013_MAP2 0x13
+#define MAX98925_R014_MAP3 0x14
+#define MAX98925_R015_MAP4 0x15
+#define MAX98925_R016_MAP5 0x16
+#define MAX98925_R017_MAP6 0x17
+#define MAX98925_R018_MAP7 0x18
+#define MAX98925_R019_MAP8 0x19
+#define MAX98925_R01A_DAI_CLK_MODE1 0x1A
+#define MAX98925_R01B_DAI_CLK_MODE2 0x1B
+#define MAX98925_R01C_DAI_CLK_DIV_M_MSBS 0x1C
+#define MAX98925_R01D_DAI_CLK_DIV_M_LSBS 0x1D
+#define MAX98925_R01E_DAI_CLK_DIV_N_MSBS 0x1E
+#define MAX98925_R01F_DAI_CLK_DIV_N_LSBS 0x1F
+#define MAX98925_R020_FORMAT 0x20
+#define MAX98925_R021_TDM_SLOT_SELECT 0x21
+#define MAX98925_R022_DOUT_CFG_VMON 0x22
+#define MAX98925_R023_DOUT_CFG_IMON 0x23
+#define MAX98925_R024_DOUT_CFG_VBAT 0x24
+#define MAX98925_R025_DOUT_CFG_VBST 0x25
+#define MAX98925_R026_DOUT_CFG_FLAG 0x26
+#define MAX98925_R027_DOUT_HIZ_CFG1 0x27
+#define MAX98925_R028_DOUT_HIZ_CFG2 0x28
+#define MAX98925_R029_DOUT_HIZ_CFG3 0x29
+#define MAX98925_R02A_DOUT_HIZ_CFG4 0x2A
+#define MAX98925_R02B_DOUT_DRV_STRENGTH 0x2B
+#define MAX98925_R02C_FILTERS 0x2C
+#define MAX98925_R02D_GAIN 0x2D
+#define MAX98925_R02E_GAIN_RAMPING 0x2E
+#define MAX98925_R02F_SPK_AMP 0x2F
+#define MAX98925_R030_THRESHOLD 0x30
+#define MAX98925_R031_ALC_ATTACK 0x31
+#define MAX98925_R032_ALC_ATTEN_RLS 0x32
+#define MAX98925_R033_ALC_HOLD_RLS 0x33
+#define MAX98925_R034_ALC_CONFIGURATION 0x34
+#define MAX98925_R035_BOOST_CONVERTER 0x35
+#define MAX98925_R036_BLOCK_ENABLE 0x36
+#define MAX98925_R037_CONFIGURATION 0x37
+#define MAX98925_R038_GLOBAL_ENABLE 0x38
+#define MAX98925_R03A_BOOST_LIMITER 0x3A
+#define MAX98925_R0FF_VERSION 0xFF
+
+#define MAX98925_REG_CNT (MAX98925_R03A_BOOST_LIMITER+1)
+
+/* MAX98925 Register Bit Fields */
+
+/* MAX98925_R002_LIVE_STATUS0 */
+#define M98925_THERMWARN_STATUS_MASK (1<<3)
+#define M98925_THERMWARN_STATUS_SHIFT 3
+#define M98925_THERMWARN_STATUS_WIDTH 1
+#define M98925_THERMSHDN_STATUS_MASK (1<<1)
+#define M98925_THERMSHDN_STATUS_SHIFT 1
+#define M98925_THERMSHDN_STATUS_WIDTH 1
+
+/* MAX98925_R003_LIVE_STATUS1 */
+#define M98925_SPKCURNT_STATUS_MASK (1<<5)
+#define M98925_SPKCURNT_STATUS_SHIFT 5
+#define M98925_SPKCURNT_STATUS_WIDTH 1
+#define M98925_WATCHFAIL_STATUS_MASK (1<<4)
+#define M98925_WATCHFAIL_STATUS_SHIFT 4
+#define M98925_WATCHFAIL_STATUS_WIDTH 1
+#define M98925_ALCINFH_STATUS_MASK (1<<3)
+#define M98925_ALCINFH_STATUS_SHIFT 3
+#define M98925_ALCINFH_STATUS_WIDTH 1
+#define M98925_ALCACT_STATUS_MASK (1<<2)
+#define M98925_ALCACT_STATUS_SHIFT 2
+#define M98925_ALCACT_STATUS_WIDTH 1
+#define M98925_ALCMUT_STATUS_MASK (1<<1)
+#define M98925_ALCMUT_STATUS_SHIFT 1
+#define M98925_ALCMUT_STATUS_WIDTH 1
+#define M98925_ACLP_STATUS_MASK (1<<0)
+#define M98925_ACLP_STATUS_SHIFT 0
+#define M98925_ACLP_STATUS_WIDTH 1
+
+/* MAX98925_R004_LIVE_STATUS2 */
+#define M98925_SLOTOVRN_STATUS_MASK (1<<6)
+#define M98925_SLOTOVRN_STATUS_SHIFT 6
+#define M98925_SLOTOVRN_STATUS_WIDTH 1
+#define M98925_INVALSLOT_STATUS_MASK (1<<5)
+#define M98925_INVALSLOT_STATUS_SHIFT 5
+#define M98925_INVALSLOT_STATUS_WIDTH 1
+#define M98925_SLOTCNFLT_STATUS_MASK (1<<4)
+#define M98925_SLOTCNFLT_STATUS_SHIFT 4
+#define M98925_SLOTCNFLT_STATUS_WIDTH 1
+#define M98925_VBSTOVFL_STATUS_MASK (1<<3)
+#define M98925_VBSTOVFL_STATUS_SHIFT 3
+#define M98925_VBSTOVFL_STATUS_WIDTH 1
+#define M98925_VBATOVFL_STATUS_MASK (1<<2)
+#define M98925_VBATOVFL_STATUS_SHIFT 2
+#define M98925_VBATOVFL_STATUS_WIDTH 1
+#define M98925_IMONOVFL_STATUS_MASK (1<<1)
+#define M98925_IMONOVFL_STATUS_SHIFT 1
+#define M98925_IMONOVFL_STATUS_WIDTH 1
+#define M98925_VMONOVFL_STATUS_MASK (1<<0)
+#define M98925_VMONOVFL_STATUS_SHIFT 0
+#define M98925_VMONOVFL_STATUS_WIDTH 1
+
+/* MAX98925_R005_STATE0 */
+#define M98925_THERMWARN_END_STATE_MASK (1<<3)
+#define M98925_THERMWARN_END_STATE_SHIFT 3
+#define M98925_THERMWARN_END_STATE_WIDTH 1
+#define M98925_THERMWARN_BGN_STATE_MASK (1<<2)
+#define M98925_THERMWARN_BGN_STATE_SHIFT 1
+#define M98925_THERMWARN_BGN_STATE_WIDTH 1
+#define M98925_THERMSHDN_END_STATE_MASK (1<<1)
+#define M98925_THERMSHDN_END_STATE_SHIFT 1
+#define M98925_THERMSHDN_END_STATE_WIDTH 1
+#define M98925_THERMSHDN_BGN_STATE_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_STATE_SHIFT 0
+#define M98925_THERMSHDN_BGN_STATE_WIDTH 1
+
+/* MAX98925_R006_STATE1 */
+#define M98925_SPRCURNT_STATE_MASK (1<<5)
+#define M98925_SPRCURNT_STATE_SHIFT 5
+#define M98925_SPRCURNT_STATE_WIDTH 1
+#define M98925_WATCHFAIL_STATE_MASK (1<<4)
+#define M98925_WATCHFAIL_STATE_SHIFT 4
+#define M98925_WATCHFAIL_STATE_WIDTH 1
+#define M98925_ALCINFH_STATE_MASK (1<<3)
+#define M98925_ALCINFH_STATE_SHIFT 3
+#define M98925_ALCINFH_STATE_WIDTH 1
+#define M98925_ALCACT_STATE_MASK (1<<2)
+#define M98925_ALCACT_STATE_SHIFT 2
+#define M98925_ALCACT_STATE_WIDTH 1
+#define M98925_ALCMUT_STATE_MASK (1<<1)
+#define M98925_ALCMUT_STATE_SHIFT 1
+#define M98925_ALCMUT_STATE_WIDTH 1
+#define M98925_ALCP_STATE_MASK (1<<0)
+#define M98925_ALCP_STATE_SHIFT 0
+#define M98925_ALCP_STATE_WIDTH 1
+
+/* MAX98925_R007_STATE2 */
+#define M98925_SLOTOVRN_STATE_MASK (1<<6)
+#define M98925_SLOTOVRN_STATE_SHIFT 6
+#define M98925_SLOTOVRN_STATE_WIDTH 1
+#define M98925_INVALSLOT_STATE_MASK (1<<5)
+#define M98925_INVALSLOT_STATE_SHIFT 5
+#define M98925_INVALSLOT_STATE_WIDTH 1
+#define M98925_SLOTCNFLT_STATE_MASK (1<<4)
+#define M98925_SLOTCNFLT_STATE_SHIFT 4
+#define M98925_SLOTCNFLT_STATE_WIDTH 1
+#define M98925_VBSTOVFL_STATE_MASK (1<<3)
+#define M98925_VBSTOVFL_STATE_SHIFT 3
+#define M98925_VBSTOVFL_STATE_WIDTH 1
+#define M98925_VBATOVFL_STATE_MASK (1<<2)
+#define M98925_VBATOVFL_STATE_SHIFT 2
+#define M98925_VBATOVFL_STATE_WIDTH 1
+#define M98925_IMONOVFL_STATE_MASK (1<<1)
+#define M98925_IMONOVFL_STATE_SHIFT 1
+#define M98925_IMONOVFL_STATE_WIDTH 1
+#define M98925_VMONOVFL_STATE_MASK (1<<0)
+#define M98925_VMONOVFL_STATE_SHIFT 0
+#define M98925_VMONOVFL_STATE_WIDTH 1
+
+/* MAX98925_R008_FLAG0 */
+#define M98925_THERMWARN_END_FLAG_MASK (1<<3)
+#define M98925_THERMWARN_END_FLAG_SHIFT 3
+#define M98925_THERMWARN_END_FLAG_WIDTH 1
+#define M98925_THERMWARN_BGN_FLAG_MASK (1<<2)
+#define M98925_THERMWARN_BGN_FLAG_SHIFT 2
+#define M98925_THERMWARN_BGN_FLAG_WIDTH 1
+#define M98925_THERMSHDN_END_FLAG_MASK (1<<1)
+#define M98925_THERMSHDN_END_FLAG_SHIFT 1
+#define M98925_THERMSHDN_END_FLAG_WIDTH 1
+#define M98925_THERMSHDN_BGN_FLAG_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_FLAG_SHIFT 0
+#define M98925_THERMSHDN_BGN_FLAG_WIDTH 1
+
+/* MAX98925_R009_FLAG1 */
+#define M98925_SPKCURNT_FLAG_MASK (1<<5)
+#define M98925_SPKCURNT_FLAG_SHIFT 5
+#define M98925_SPKCURNT_FLAG_WIDTH 1
+#define M98925_WATCHFAIL_FLAG_MASK (1<<4)
+#define M98925_WATCHFAIL_FLAG_SHIFT 4
+#define M98925_WATCHFAIL_FLAG_WIDTH 1
+#define M98925_ALCINFH_FLAG_MASK (1<<3)
+#define M98925_ALCINFH_FLAG_SHIFT 3
+#define M98925_ALCINFH_FLAG_WIDTH 1
+#define M98925_ALCACT_FLAG_MASK (1<<2)
+#define M98925_ALCACT_FLAG_SHIFT 2
+#define M98925_ALCACT_FLAG_WIDTH 1
+#define M98925_ALCMUT_FLAG_MASK (1<<1)
+#define M98925_ALCMUT_FLAG_SHIFT 1
+#define M98925_ALCMUT_FLAG_WIDTH 1
+#define M98925_ALCP_FLAG_MASK (1<<0)
+#define M98925_ALCP_FLAG_SHIFT 0
+#define M98925_ALCP_FLAG_WIDTH 1
+
+/* MAX98925_R00A_FLAG2 */
+#define M98925_SLOTOVRN_FLAG_MASK (1<<6)
+#define M98925_SLOTOVRN_FLAG_SHIFT 6
+#define M98925_SLOTOVRN_FLAG_WIDTH 1
+#define M98925_INVALSLOT_FLAG_MASK (1<<5)
+#define M98925_INVALSLOT_FLAG_SHIFT 5
+#define M98925_INVALSLOT_FLAG_WIDTH 1
+#define M98925_SLOTCNFLT_FLAG_MASK (1<<4)
+#define M98925_SLOTCNFLT_FLAG_SHIFT 4
+#define M98925_SLOTCNFLT_FLAG_WIDTH 1
+#define M98925_VBSTOVFL_FLAG_MASK (1<<3)
+#define M98925_VBSTOVFL_FLAG_SHIFT 3
+#define M98925_VBSTOVFL_FLAG_WIDTH 1
+#define M98925_VBATOVFL_FLAG_MASK (1<<2)
+#define M98925_VBATOVFL_FLAG_SHIFT 2
+#define M98925_VBATOVFL_FLAG_WIDTH 1
+#define M98925_IMONOVFL_FLAG_MASK (1<<1)
+#define M98925_IMONOVFL_FLAG_SHIFT 1
+#define M98925_IMONOVFL_FLAG_WIDTH 1
+#define M98925_VMONOVFL_FLAG_MASK (1<<0)
+#define M98925_VMONOVFL_FLAG_SHIFT 0
+#define M98925_VMONOVFL_FLAG_WIDTH 1
+
+/* MAX98925_R00B_IRQ_ENABLE0 */
+#define M98925_THERMWARN_END_EN_MASK (1<<3)
+#define M98925_THERMWARN_END_EN_SHIFT 3
+#define M98925_THERMWARN_END_EN_WIDTH 1
+#define M98925_THERMWARN_BGN_EN_MASK (1<<2)
+#define M98925_THERMWARN_BGN_EN_SHIFT 2
+#define M98925_THERMWARN_BGN_EN_WIDTH 1
+#define M98925_THERMSHDN_END_EN_MASK (1<<1)
+#define M98925_THERMSHDN_END_EN_SHIFT 1
+#define M98925_THERMSHDN_END_EN_WIDTH 1
+#define M98925_THERMSHDN_BGN_EN_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_EN_SHIFT 0
+#define M98925_THERMSHDN_BGN_EN_WIDTH 1
+
+/* MAX98925_R00C_IRQ_ENABLE1 */
+#define M98925_SPKCURNT_EN_MASK (1<<5)
+#define M98925_SPKCURNT_EN_SHIFT 5
+#define M98925_SPKCURNT_EN_WIDTH 1
+#define M98925_WATCHFAIL_EN_MASK (1<<4)
+#define M98925_WATCHFAIL_EN_SHIFT 4
+#define M98925_WATCHFAIL_EN_WIDTH 1
+#define M98925_ALCINFH_EN_MASK (1<<3)
+#define M98925_ALCINFH_EN_SHIFT 3
+#define M98925_ALCINFH_EN_WIDTH 1
+#define M98925_ALCACT_EN_MASK (1<<2)
+#define M98925_ALCACT_EN_SHIFT 2
+#define M98925_ALCACT_EN_WIDTH 1
+#define M98925_ALCMUT_EN_MASK (1<<1)
+#define M98925_ALCMUT_EN_SHIFT 1
+#define M98925_ALCMUT_EN_WIDTH 1
+#define M98925_ALCP_EN_MASK (1<<0)
+#define M98925_ALCP_EN_SHIFT 0
+#define M98925_ALCP_EN_WIDTH 1
+
+/* MAX98925_R00D_IRQ_ENABLE2 */
+#define M98925_SLOTOVRN_EN_MASK (1<<6)
+#define M98925_SLOTOVRN_EN_SHIFT 6
+#define M98925_SLOTOVRN_EN_WIDTH 1
+#define M98925_INVALSLOT_EN_MASK (1<<5)
+#define M98925_INVALSLOT_EN_SHIFT 5
+#define M98925_INVALSLOT_EN_WIDTH 1
+#define M98925_SLOTCNFLT_EN_MASK (1<<4)
+#define M98925_SLOTCNFLT_EN_SHIFT 4
+#define M98925_SLOTCNFLT_EN_WIDTH 1
+#define M98925_VBSTOVFL_EN_MASK (1<<3)
+#define M98925_VBSTOVFL_EN_SHIFT 3
+#define M98925_VBSTOVFL_EN_WIDTH 1
+#define M98925_VBATOVFL_EN_MASK (1<<2)
+#define M98925_VBATOVFL_EN_SHIFT 2
+#define M98925_VBATOVFL_EN_WIDTH 1
+#define M98925_IMONOVFL_EN_MASK (1<<1)
+#define M98925_IMONOVFL_EN_SHIFT 1
+#define M98925_IMONOVFL_EN_WIDTH 1
+#define M98925_VMONOVFL_EN_MASK (1<<0)
+#define M98925_VMONOVFL_EN_SHIFT 0
+#define M98925_VMONOVFL_EN_WIDTH 1
+
+/* MAX98925_R00E_IRQ_CLEAR0 */
+#define M98925_THERMWARN_END_CLR_MASK (1<<3)
+#define M98925_THERMWARN_END_CLR_SHIFT 3
+#define M98925_THERMWARN_END_CLR_WIDTH 1
+#define M98925_THERMWARN_BGN_CLR_MASK (1<<2)
+#define M98925_THERMWARN_BGN_CLR_SHIFT 2
+#define M98925_THERMWARN_BGN_CLR_WIDTH 1
+#define M98925_THERMSHDN_END_CLR_MASK (1<<1)
+#define M98925_THERMSHDN_END_CLR_SHIFT 1
+#define M98925_THERMSHDN_END_CLR_WIDTH 1
+#define M98925_THERMSHDN_BGN_CLR_MASK (1<<0)
+#define M98925_THERMSHDN_BGN_CLR_SHIFT 0
+#define M98925_THERMSHDN_BGN_CLR_WIDTH 1
+
+/* MAX98925_R00F_IRQ_CLEAR1 */
+#define M98925_SPKCURNT_CLR_MASK (1<<5)
+#define M98925_SPKCURNT_CLR_SHIFT 5
+#define M98925_SPKCURNT_CLR_WIDTH 1
+#define M98925_WATCHFAIL_CLR_MASK (1<<4)
+#define M98925_WATCHFAIL_CLR_SHIFT 4
+#define M98925_WATCHFAIL_CLR_WIDTH 1
+#define M98925_ALCINFH_CLR_MASK (1<<3)
+#define M98925_ALCINFH_CLR_SHIFT 3
+#define M98925_ALCINFH_CLR_WIDTH 1
+#define M98925_ALCACT_CLR_MASK (1<<2)
+#define M98925_ALCACT_CLR_SHIFT 2
+#define M98925_ALCACT_CLR_WIDTH 1
+#define M98925_ALCMUT_CLR_MASK (1<<1)
+#define M98925_ALCMUT_CLR_SHIFT 1
+#define M98925_ALCMUT_CLR_WIDTH 1
+#define M98925_ALCP_CLR_MASK (1<<0)
+#define M98925_ALCP_CLR_SHIFT 0
+#define M98925_ALCP_CLR_WIDTH 1
+
+/* MAX98925_R010_IRQ_CLEAR2 */
+#define M98925_SLOTOVRN_CLR_MASK (1<<6)
+#define M98925_SLOTOVRN_CLR_SHIFT 6
+#define M98925_SLOTOVRN_CLR_WIDTH 1
+#define M98925_INVALSLOT_CLR_MASK (1<<5)
+#define M98925_INVALSLOT_CLR_SHIFT 5
+#define M98925_INVALSLOT_CLR_WIDTH 1
+#define M98925_SLOTCNFLT_CLR_MASK (1<<4)
+#define M98925_SLOTCNFLT_CLR_SHIFT 4
+#define M98925_SLOTCNFLT_CLR_WIDTH 1
+#define M98925_VBSTOVFL_CLR_MASK (1<<3)
+#define M98925_VBSTOVFL_CLR_SHIFT 3
+#define M98925_VBSTOVFL_CLR_WIDTH 1
+#define M98925_VBATOVFL_CLR_MASK (1<<2)
+#define M98925_VBATOVFL_CLR_SHIFT 2
+#define M98925_VBATOVFL_CLR_WIDTH 1
+#define M98925_IMONOVFL_CLR_MASK (1<<1)
+#define M98925_IMONOVFL_CLR_SHIFT 1
+#define M98925_IMONOVFL_CLR_WIDTH 1
+#define M98925_VMONOVFL_CLR_MASK (1<<0)
+#define M98925_VMONOVFL_CLR_SHIFT 0
+#define M98925_VMONOVFL_CLR_WIDTH 1
+
+/* MAX98925_R011_MAP0 */
+#define M98925_ER_THERMWARN_EN_MASK (1<<7)
+#define M98925_ER_THERMWARN_EN_SHIFT 7
+#define M98925_ER_THERMWARN_EN_WIDTH 1
+#define M98925_ER_THERMWARN_MAP_MASK (0x07<<4)
+#define M98925_ER_THERMWARN_MAP_SHIFT 4
+#define M98925_ER_THERMWARN_MAP_WIDTH 3
+
+/* MAX98925_R012_MAP1 */
+#define M98925_ER_ALCMUT_EN_MASK (1<<7)
+#define M98925_ER_ALCMUT_EN_SHIFT 7
+#define M98925_ER_ALCMUT_EN_WIDTH 1
+#define M98925_ER_ALCMUT_MAP_MASK (0x07<<4)
+#define M98925_ER_ALCMUT_MAP_SHIFT 4
+#define M98925_ER_ALCMUT_MAP_WIDTH 3
+#define M98925_ER_ALCP_EN_MASK (1<<3)
+#define M98925_ER_ALCP_EN_SHIFT 3
+#define M98925_ER_ALCP_EN_WIDTH 1
+#define M98925_ER_ALCP_MAP_MASK (0x07<<0)
+#define M98925_ER_ALCP_MAP_SHIFT 0
+#define M98925_ER_ALCP_MAP_WIDTH 3
+
+/* MAX98925_R013_MAP2 */
+#define M98925_ER_ALCINFH_EN_MASK (1<<7)
+#define M98925_ER_ALCINFH_EN_SHIFT 7
+#define M98925_ER_ALCINFH_EN_WIDTH 1
+#define M98925_ER_ALCINFH_MAP_MASK (0x07<<4)
+#define M98925_ER_ALCINFH_MAP_SHIFT 4
+#define M98925_ER_ALCINFH_MAP_WIDTH 3
+#define M98925_ER_ALCACT_EN_MASK (1<<3)
+#define M98925_ER_ALCACT_EN_SHIFT 3
+#define M98925_ER_ALCACT_EN_WIDTH 1
+#define M98925_ER_ALCACT_MAP_MASK (0x07<<0)
+#define M98925_ER_ALCACT_MAP_SHIFT 0
+#define M98925_ER_ALCACT_MAP_WIDTH 3
+
+/* MAX98925_R014_MAP3 */
+#define M98925_ER_SPKCURNT_EN_MASK (1<<7)
+#define M98925_ER_SPKCURNT_EN_SHIFT 7
+#define M98925_ER_SPKCURNT_EN_WIDTH 1
+#define M98925_ER_SPKCURNT_MAP_MASK (0x07<<4)
+#define M98925_ER_SPKCURNT_MAP_SHIFT 4
+#define M98925_ER_SPKCURNT_MAP_WIDTH 3
+
+/* MAX98925_R015_MAP4 */
+/* RESERVED */
+
+/* MAX98925_R016_MAP5 */
+#define M98925_ER_IMONOVFL_EN_MASK (1<<7)
+#define M98925_ER_IMONOVFL_EN_SHIFT 7
+#define M98925_ER_IMONOVFL_EN_WIDTH 1
+#define M98925_ER_IMONOVFL_MAP_MASK (0x07<<4)
+#define M98925_ER_IMONOVFL_MAP_SHIFT 4
+#define M98925_ER_IMONOVFL_MAP_WIDTH 3
+#define M98925_ER_VMONOVFL_EN_MASK (1<<3)
+#define M98925_ER_VMONOVFL_EN_SHIFT 3
+#define M98925_ER_VMONOVFL_EN_WIDTH 1
+#define M98925_ER_VMONOVFL_MAP_MASK (0x07<<0)
+#define M98925_ER_VMONOVFL_MAP_SHIFT 0
+#define M98925_ER_VMONOVFL_MAP_WIDTH 3
+
+/* MAX98925_R017_MAP6 */
+#define M98925_ER_VBSTOVFL_EN_MASK (1<<7)
+#define M98925_ER_VBSTOVFL_EN_SHIFT 7
+#define M98925_ER_VBSTOVFL_EN_WIDTH 1
+#define M98925_ER_VBSTOVFL_MAP_MASK (0x07<<4)
+#define M98925_ER_VBSTOVFL_MAP_SHIFT 4
+#define M98925_ER_VBSTOVFL_MAP_WIDTH 3
+#define M98925_ER_VBATOVFL_EN_MASK (1<<3)
+#define M98925_ER_VBATOVFL_EN_SHIFT 3
+#define M98925_ER_VBATOVFL_EN_WIDTH 1
+#define M98925_ER_VBATOVFL_MAP_MASK (0x07<<0)
+#define M98925_ER_VBATOVFL_MAP_SHIFT 0
+#define M98925_ER_VBATOVFL_MAP_WIDTH 3
+
+/* MAX98925_R018_MAP7 */
+#define M98925_ER_INVALSLOT_EN_MASK (1<<7)
+#define M98925_ER_INVALSLOT_EN_SHIFT 7
+#define M98925_ER_INVALSLOT_EN_WIDTH 1
+#define M98925_ER_INVALSLOT_MAP_MASK (0x07<<4)
+#define M98925_ER_INVALSLOT_MAP_SHIFT 4
+#define M98925_ER_INVALSLOT_MAP_WIDTH 3
+#define M98925_ER_SLOTCNFLT_EN_MASK (1<<3)
+#define M98925_ER_SLOTCNFLT_EN_SHIFT 3
+#define M98925_ER_SLOTCNFLT_EN_WIDTH 1
+#define M98925_ER_SLOTCNFLT_MAP_MASK (0x07<<0)
+#define M98925_ER_SLOTCNFLT_MAP_SHIFT 0
+#define M98925_ER_SLOTCNFLT_MAP_WIDTH 3
+
+/* MAX98925_R019_MAP8 */
+#define M98925_ER_SLOTOVRN_EN_MASK (1<<3)
+#define M98925_ER_SLOTOVRN_EN_SHIFT 3
+#define M98925_ER_SLOTOVRN_EN_WIDTH 1
+#define M98925_ER_SLOTOVRN_MAP_MASK (0x07<<0)
+#define M98925_ER_SLOTOVRN_MAP_SHIFT 0
+#define M98925_ER_SLOTOVRN_MAP_WIDTH 3
+
+/* MAX98925_R01A_DAI_CLK_MODE1 */
+#define M98925_DAI_CLK_SOURCE_MASK (1<<6)
+#define M98925_DAI_CLK_SOURCE_SHIFT 6
+#define M98925_DAI_CLK_SOURCE_WIDTH 1
+#define M98925_MDLL_MULT_MASK (0x0F<<0)
+#define M98925_MDLL_MULT_SHIFT 0
+#define M98925_MDLL_MULT_WIDTH 4
+
+#define M98925_MDLL_MULT_MCLKx8 6
+#define M98925_MDLL_MULT_MCLKx16 8
+
+/* MAX98925_R01B_DAI_CLK_MODE2 */
+#define M98925_DAI_SR_MASK (0x0F<<4)
+#define M98925_DAI_SR_SHIFT 4
+#define M98925_DAI_SR_WIDTH 4
+#define M98925_DAI_MAS_MASK (1<<3)
+#define M98925_DAI_MAS_SHIFT 3
+#define M98925_DAI_MAS_WIDTH 1
+#define M98925_DAI_BSEL_MASK (0x07<<0)
+#define M98925_DAI_BSEL_SHIFT 0
+#define M98925_DAI_BSEL_WIDTH 3
+
+#define M98925_DAI_BSEL_32 (0 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_48 (1 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_64 (2 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_256 (6 << M98925_DAI_BSEL_SHIFT)
+
+/* MAX98925_R01C_DAI_CLK_DIV_M_MSBS */
+#define M98925_DAI_M_MSBS_MASK (0xFF<<0)
+#define M98925_DAI_M_MSBS_SHIFT 0
+#define M98925_DAI_M_MSBS_WIDTH 8
+
+/* MAX98925_R01D_DAI_CLK_DIV_M_LSBS */
+#define M98925_DAI_M_LSBS_MASK (0xFF<<0)
+#define M98925_DAI_M_LSBS_SHIFT 0
+#define M98925_DAI_M_LSBS_WIDTH 8
+
+/* MAX98925_R01E_DAI_CLK_DIV_N_MSBS */
+#define M98925_DAI_N_MSBS_MASK (0x7F<<0)
+#define M98925_DAI_N_MSBS_SHIFT 0
+#define M98925_DAI_N_MSBS_WIDTH 7
+
+/* MAX98925_R01F_DAI_CLK_DIV_N_LSBS */
+#define M98925_DAI_N_LSBS_MASK (0xFF<<0)
+#define M98925_DAI_N_LSBS_SHIFT 0
+#define M98925_DAI_N_LSBS_WIDTH 8
+
+/* MAX98925_R020_FORMAT */
+#define M98925_DAI_CHANSZ_MASK (0x03<<6)
+#define M98925_DAI_CHANSZ_SHIFT 6
+#define M98925_DAI_CHANSZ_WIDTH 2
+#define M98925_DAI_EXTBCLK_HIZ_MASK (1<<4)
+#define M98925_DAI_EXTBCLK_HIZ_SHIFT 4
+#define M98925_DAI_EXTBCLK_HIZ_WIDTH 1
+#define M98925_DAI_WCI_MASK (1<<3)
+#define M98925_DAI_WCI_SHIFT 3
+#define M98925_DAI_WCI_WIDTH 1
+#define M98925_DAI_BCI_MASK (1<<2)
+#define M98925_DAI_BCI_SHIFT 2
+#define M98925_DAI_BCI_WIDTH 1
+#define M98925_DAI_DLY_MASK (1<<1)
+#define M98925_DAI_DLY_SHIFT 1
+#define M98925_DAI_DLY_WIDTH 1
+#define M98925_DAI_TDM_MASK (1<<0)
+#define M98925_DAI_TDM_SHIFT 0
+#define M98925_DAI_TDM_WIDTH 1
+
+#define M98925_DAI_CHANSZ_16 (1 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_24 (2 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_32 (3 << M98925_DAI_CHANSZ_SHIFT)
+
+/* MAX98925_R021_TDM_SLOT_SELECT */
+#define M98925_DAI_DO_EN_MASK (1<<7)
+#define M98925_DAI_DO_EN_SHIFT 7
+#define M98925_DAI_DO_EN_WIDTH 1
+#define M98925_DAI_DIN_EN_MASK (1<<6)
+#define M98925_DAI_DIN_EN_SHIFT 6
+#define M98925_DAI_DIN_EN_WIDTH 1
+#define M98925_DAI_INR_SOURCE_MASK (0x07<<3)
+#define M98925_DAI_INR_SOURCE_SHIFT 3
+#define M98925_DAI_INR_SOURCE_WIDTH 3
+#define M98925_DAI_INL_SOURCE_MASK (0x07<<0)
+#define M98925_DAI_INL_SOURCE_SHIFT 0
+#define M98925_DAI_INL_SOURCE_WIDTH 3
+
+/* MAX98925_R022_DOUT_CFG_VMON */
+#define M98925_DAI_VMON_EN_MASK (1<<5)
+#define M98925_DAI_VMON_EN_SHIFT 5
+#define M98925_DAI_VMON_EN_WIDTH 1
+#define M98925_DAI_VMON_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_VMON_SLOT_SHIFT 0
+#define M98925_DAI_VMON_SLOT_WIDTH 5
+
+#define M98925_DAI_VMON_SLOT_00_01 (0 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_01_02 (1 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_02_03 (2 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_03_04 (3 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_04_05 (4 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_05_06 (5 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_06_07 (6 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_07_08 (7 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_08_09 (8 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_09_0A (9 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0A_0B (10 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0B_0C (11 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0C_0D (12 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0D_0E (13 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0E_0F (14 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0F_10 (15 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_10_11 (16 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_11_12 (17 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_12_13 (18 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_13_14 (19 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_14_15 (20 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_15_16 (21 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_16_17 (22 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_17_18 (23 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_18_19 (24 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_19_1A (25 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1A_1B (26 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1B_1C (27 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1C_1D (28 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1D_1E (29 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1E_1F (30 << M98925_DAI_VMON_SLOT_SHIFT)
+
+/* MAX98925_R023_DOUT_CFG_IMON */
+#define M98925_DAI_IMON_EN_MASK (1<<5)
+#define M98925_DAI_IMON_EN_SHIFT 5
+#define M98925_DAI_IMON_EN_WIDTH 1
+#define M98925_DAI_IMON_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_IMON_SLOT_SHIFT 0
+#define M98925_DAI_IMON_SLOT_WIDTH 5
+
+#define M98925_DAI_IMON_SLOT_00_01 (0 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_01_02 (1 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_02_03 (2 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_03_04 (3 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_04_05 (4 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_05_06 (5 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_06_07 (6 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_07_08 (7 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_08_09 (8 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_09_0A (9 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0A_0B (10 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0B_0C (11 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0C_0D (12 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0D_0E (13 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0E_0F (14 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0F_10 (15 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_10_11 (16 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_11_12 (17 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_12_13 (18 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_13_14 (19 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_14_15 (20 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_15_16 (21 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_16_17 (22 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_17_18 (23 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_18_19 (24 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_19_1A (25 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1A_1B (26 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1B_1C (27 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1C_1D (28 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1D_1E (29 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1E_1F (30 << M98925_DAI_IMON_SLOT_SHIFT)
+
+/* MAX98925_R024_DOUT_CFG_VBAT */
+#define M98925_DAI_VBAT_EN_MASK (1<<5)
+#define M98925_DAI_VBAT_EN_SHIFT 5
+#define M98925_DAI_VBAT_EN_WIDTH 1
+#define M98925_DAI_VBAT_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_VBAT_SLOT_SHIFT 0
+#define M98925_DAI_VBAT_SLOT_WIDTH 5
+
+/* MAX98925_R025_DOUT_CFG_VBST */
+#define M98925_DAI_VBST_EN_MASK (1<<5)
+#define M98925_DAI_VBST_EN_SHIFT 5
+#define M98925_DAI_VBST_EN_WIDTH 1
+#define M98925_DAI_VBST_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_VBST_SLOT_SHIFT 0
+#define M98925_DAI_VBST_SLOT_WIDTH 5
+
+/* MAX98925_R026_DOUT_CFG_FLAG */
+#define M98925_DAI_FLAG_EN_MASK (1<<5)
+#define M98925_DAI_FLAG_EN_SHIFT 5
+#define M98925_DAI_FLAG_EN_WIDTH 1
+#define M98925_DAI_FLAG_SLOT_MASK (0x1F<<0)
+#define M98925_DAI_FLAG_SLOT_SHIFT 0
+#define M98925_DAI_FLAG_SLOT_WIDTH 5
+
+/* MAX98925_R027_DOUT_HIZ_CFG1 */
+#define M98925_DAI_SLOT_HIZ_CFG1_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG1_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG1_WIDTH 8
+
+/* MAX98925_R028_DOUT_HIZ_CFG2 */
+#define M98925_DAI_SLOT_HIZ_CFG2_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG2_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG2_WIDTH 8
+
+/* MAX98925_R029_DOUT_HIZ_CFG3 */
+#define M98925_DAI_SLOT_HIZ_CFG3_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG3_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG3_WIDTH 8
+
+/* MAX98925_R02A_DOUT_HIZ_CFG4 */
+#define M98925_DAI_SLOT_HIZ_CFG4_MASK (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG4_SHIFT 0
+#define M98925_DAI_SLOT_HIZ_CFG4_WIDTH 8
+
+/* MAX98925_R02B_DOUT_DRV_STRENGTH */
+#define M98925_DAI_OUT_DRIVE_MASK (0x03<<0)
+#define M98925_DAI_OUT_DRIVE_SHIFT 0
+#define M98925_DAI_OUT_DRIVE_WIDTH 2
+
+/* MAX98925_R02C_FILTERS */
+#define M98925_ADC_DITHER_EN_MASK (1<<7)
+#define M98925_ADC_DITHER_EN_SHIFT 7
+#define M98925_ADC_DITHER_EN_WIDTH 1
+#define M98925_IV_DCB_EN_MASK (1<<6)
+#define M98925_IV_DCB_EN_SHIFT 6
+#define M98925_IV_DCB_EN_WIDTH 1
+#define M98925_DAC_DITHER_EN_MASK (1<<4)
+#define M98925_DAC_DITHER_EN_SHIFT 4
+#define M98925_DAC_DITHER_EN_WIDTH 1
+#define M98925_DAC_FILTER_MODE_MASK (1<<3)
+#define M98925_DAC_FILTER_MODE_SHIFT 3
+#define M98925_DAC_FILTER_MODE_WIDTH 1
+#define M98925_DAC_HPF_MASK (0x07<<0)
+#define M98925_DAC_HPF_SHIFT 0
+#define M98925_DAC_HPF_WIDTH 3
+#define M98925_DAC_HPF_DISABLE (0 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_DC_BLOCK (1 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_100 (2 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_200 (3 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_400 (4 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_800 (5 << M98925_DAC_HPF_SHIFT)
+
+/* MAX98925_R02D_GAIN */
+#define M98925_DAC_IN_SEL_MASK (0x03<<5)
+#define M98925_DAC_IN_SEL_SHIFT 5
+#define M98925_DAC_IN_SEL_WIDTH 2
+#define M98925_SPK_GAIN_MASK (0x1F<<0)
+#define M98925_SPK_GAIN_SHIFT 0
+#define M98925_SPK_GAIN_WIDTH 5
+
+#define M98925_DAC_IN_SEL_LEFT_DAI (0 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_RIGHT_DAI (1 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_SUMMED_DAI (2 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << M98925_DAC_IN_SEL_SHIFT)
+
+/* MAX98925_R02E_GAIN_RAMPING */
+#define M98925_SPK_RMP_EN_MASK (1<<1)
+#define M98925_SPK_RMP_EN_SHIFT 1
+#define M98925_SPK_RMP_EN_WIDTH 1
+#define M98925_SPK_ZCD_EN_MASK (1<<0)
+#define M98925_SPK_ZCD_EN_SHIFT 0
+#define M98925_SPK_ZCD_EN_WIDTH 1
+
+/* MAX98925_R02F_SPK_AMP */
+#define M98925_SPK_MODE_MASK (1<<0)
+#define M98925_SPK_MODE_SHIFT 0
+#define M98925_SPK_MODE_WIDTH 1
+
+/* MAX98925_R030_THRESHOLD */
+#define M98925_ALC_EN_MASK (1<<5)
+#define M98925_ALC_EN_SHIFT 5
+#define M98925_ALC_EN_WIDTH 1
+#define M98925_ALC_TH_MASK (0x1F<<0)
+#define M98925_ALC_TH_SHIFT 0
+#define M98925_ALC_TH_WIDTH 5
+
+/* MAX98925_R031_ALC_ATTACK */
+#define M98925_ALC_ATK_STEP_MASK (0x0F<<4)
+#define M98925_ALC_ATK_STEP_SHIFT 4
+#define M98925_ALC_ATK_STEP_WIDTH 4
+#define M98925_ALC_ATK_RATE_MASK (0x7<<0)
+#define M98925_ALC_ATK_RATE_SHIFT 0
+#define M98925_ALC_ATK_RATE_WIDTH 3
+
+/* MAX98925_R032_ALC_ATTEN_RLS */
+#define M98925_ALC_MAX_ATTEN_MASK (0x0F<<4)
+#define M98925_ALC_MAX_ATTEN_SHIFT 4
+#define M98925_ALC_MAX_ATTEN_WIDTH 4
+#define M98925_ALC_RLS_RATE_MASK (0x7<<0)
+#define M98925_ALC_RLS_RATE_SHIFT 0
+#define M98925_ALC_RLS_RATE_WIDTH 3
+
+/* MAX98925_R033_ALC_HOLD_RLS */
+#define M98925_ALC_RLS_TGR_MASK (1<<0)
+#define M98925_ALC_RLS_TGR_SHIFT 0
+#define M98925_ALC_RLS_TGR_WIDTH 1
+
+/* MAX98925_R034_ALC_CONFIGURATION */
+#define M98925_ALC_MUTE_EN_MASK (1<<7)
+#define M98925_ALC_MUTE_EN_SHIFT 7
+#define M98925_ALC_MUTE_EN_WIDTH 1
+#define M98925_ALC_MUTE_DLY_MASK (0x07<<4)
+#define M98925_ALC_MUTE_DLY_SHIFT 4
+#define M98925_ALC_MUTE_DLY_WIDTH 3
+#define M98925_ALC_RLS_DBT_MASK (0x07<<0)
+#define M98925_ALC_RLS_DBT_SHIFT 0
+#define M98925_ALC_RLS_DBT_WIDTH 3
+
+/* MAX98925_R035_BOOST_CONVERTER */
+#define M98925_BST_SYNC_MASK (1<<7)
+#define M98925_BST_SYNC_SHIFT 7
+#define M98925_BST_SYNC_WIDTH 1
+#define M98925_BST_PHASE_MASK (0x03<<4)
+#define M98925_BST_PHASE_SHIFT 4
+#define M98925_BST_PHASE_WIDTH 2
+#define M98925_BST_SKIP_MODE_MASK (0x03<<0)
+#define M98925_BST_SKIP_MODE_SHIFT 0
+#define M98925_BST_SKIP_MODE_WIDTH 2
+
+/* MAX98925_R036_BLOCK_ENABLE */
+#define M98925_BST_EN_MASK (1<<7)
+#define M98925_BST_EN_SHIFT 7
+#define M98925_BST_EN_WIDTH 1
+#define M98925_WATCH_EN_MASK (1<<6)
+#define M98925_WATCH_EN_SHIFT 6
+#define M98925_WATCH_EN_WIDTH 1
+#define M98925_CLKMON_EN_MASK (1<<5)
+#define M98925_CLKMON_EN_SHIFT 5
+#define M98925_CLKMON_EN_WIDTH 1
+#define M98925_SPK_EN_MASK (1<<4)
+#define M98925_SPK_EN_SHIFT 4
+#define M98925_SPK_EN_WIDTH 1
+#define M98925_ADC_VBST_EN_MASK (1<<3)
+#define M98925_ADC_VBST_EN_SHIFT 3
+#define M98925_ADC_VBST_EN_WIDTH 1
+#define M98925_ADC_VBAT_EN_MASK (1<<2)
+#define M98925_ADC_VBAT_EN_SHIFT 2
+#define M98925_ADC_VBAT_EN_WIDTH 1
+#define M98925_ADC_IMON_EN_MASK (1<<1)
+#define M98925_ADC_IMON_EN_SHIFT 1
+#define M98925_ADC_IMON_EN_WIDTH 1
+#define M98925_ADC_VMON_EN_MASK (1<<0)
+#define M98925_ADC_VMON_EN_SHIFT 0
+#define M98925_ADC_VMON_EN_WIDTH 1
+
+/* MAX98925_R037_CONFIGURATION */
+#define M98925_BST_VOUT_MASK (0x0F<<4)
+#define M98925_BST_VOUT_SHIFT 4
+#define M98925_BST_VOUT_WIDTH 4
+#define M98925_THERMWARN_LEVEL_MASK (0x03<<2)
+#define M98925_THERMWARN_LEVEL_SHIFT 2
+#define M98925_THERMWARN_LEVEL_WIDTH 2
+#define M98925_WATCH_TIME_MASK (0x03<<0)
+#define M98925_WATCH_TIME_SHIFT 0
+#define M98925_WATCH_TIME_WIDTH 2
+
+/* MAX98925_R038_GLOBAL_ENABLE */
+#define M98925_EN_MASK (1<<7)
+#define M98925_EN_SHIFT 7
+#define M98925_EN_WIDTH 1
+
+/* MAX98925_R03A_BOOST_LIMITER */
+#define M98925_BST_ILIM_MASK (0x1F<<3)
+#define M98925_BST_ILIM_SHIFT 3
+#define M98925_BST_ILIM_WIDTH 5
+
+/* MAX98925_R0FF_VERSION */
+#define M98925_REV_ID_MASK (0xFF<<0)
+#define M98925_REV_ID_SHIFT 0
+#define M98925_REV_ID_WIDTH 8
+
+struct max98925_cdata {
+ unsigned int rate;
+ unsigned int fmt;
+};
+
+struct max98925_priv {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct max98925_pdata *pdata;
+ unsigned int sysclk;
+ unsigned int v_slot;
+ unsigned int i_slot;
+ unsigned int spk_gain;
+ unsigned int ch_size;
+};
+#endif
--
1.9.3
4
5
[alsa-devel] [PATCH v4] ASoC: rt286: add jack detection disable with NULL jack passed
by Jie Yang 24 Feb '15
by Jie Yang 24 Feb '15
24 Feb '15
Some platforms, e.g. WSB, don't need jack detection when
system is in Suspend, for power save reason.
Here add headphone/mic jack detection disable feature with NULL
jack passed in, when disabled, it will disable interrupt, and
disable LDO1, which is used for jack detection when headphone
is plugged in.
Signed-off-by: Jie Yang <yang.jie(a)intel.com>
Reviewed-by: Bard Liao <bardliao(a)realtek.com>
---
sound/soc/codecs/rt286.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index d5cc1bc..c778028 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -394,9 +394,20 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
rt286->jack = jack;
- /* Send an initial empty report */
- snd_soc_jack_report(rt286->jack, 0,
- SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+ if (jack) {
+ /* enable IRQ */
+ if (rt286->jack->status | SND_JACK_HEADPHONE)
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
+ regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
+ /* Send an initial empty report */
+ snd_soc_jack_report(rt286->jack, rt286->jack->status,
+ SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+ } else {
+ /* disable IRQ */
+ regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
+ snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
+ }
+ snd_soc_dapm_sync(&codec->dapm);
return 0;
}
--
1.9.1
2
1
[alsa-devel] No sound and systemd journal filling when inserting headphones when power-saving is enabled
by Dang Sananikone 24 Feb '15
by Dang Sananikone 24 Feb '15
24 Feb '15
Hi,
I previously posted in alsa user mailing list about a problem I was facing
with having no sound and the systemd journal filling when using headphones:
http://article.gmane.org/gmane.linux.alsa.user/38948
I subsequently realised that I had enabled power-saving a few weeks ago and
it was this power-saving that was causing the problem. My response to myself
is here:
http://article.gmane.org/gmane.linux.alsa.user/38953
I am now satisfied that disabling power-saving has resolved my issue, but
there has been a suggestion that I report this issue, so here it is.
Apologies if this is the wrong place (this is my first time on the alsa
mailing list).
Let me know if you want me to create a bug ticket and where it
should be created (the bug tracker URL link in the alsa project page is not
working).
2
1
[alsa-devel] [PATCH 0/20] ASoC: rsnd: add Synchronous SRC and U/O error salvage support
by Kuninori Morimoto 24 Feb '15
by Kuninori Morimoto 24 Feb '15
24 Feb '15
Hi Mark.
These patches adds [1] Synchronous SRC, [2] under/over run error salvage
support to Renesas sound driver.
1) - 16) : prepare cleanup/tidyup for 17) - 19)
17) : Synchronous SRC
18)- 19) : salvage support for under/over run error
20) : cleanup for 18) - 19)
Current Renesas sound can use Asynchronous/Synchronous sampling rate convert.
Asynchronous sampling rate convert is already supported on upstream.
("feature" is supported, "DT" bindings is not yet supported)
17) adds Synchronous sampling rate convert.
Renesas sound has HW bug (?) which switches L/R channel if
under/over run error had occurred.
18) - 19) adds salvage supported for it.
20) is cleanup patch which is based on 18)-19) patch
Kuninori Morimoto (20):
1. ASoC: rsnd: add .fallback callback
2. ASoC: rsnd: add callback status check method
3. ASoC: rsnd: rsnd_src_ssiu_stop() stops SSIU compulsorily
4. ASoC: rsnd: tidyup PIO/DMA mode settings method
5. ASoC: rsnd: tidyup SSI interrupt enable/disable method
6. ASoC: rsnd: care SSIWSR register in rsnd_ssi_hw_start()
7. ASoC: rsnd: clear status register when HW start
8. ASoC: rsnd: synchronize SSI start/stop sequence between PIO/DMA mode
9. ASoC: rsnd: show master clock rate when ADG probe
10. ASoC: rsnd: move snd_kcontrol_new fucntions to core.c
11. ASoC: rsnd: tidyup rsnd_io_to_runtime() macro
12. ASoC: rsnd: use rsnd_src_convert_rate() once on rsnd_src_set_convert_rate_gen2()
13. ASoC: rsnd: initialize SRC on rsnd_src_init()
14. ASoC: rsnd: set SRC_ROUTE_MODE0 on each rsnd_src_set_convert_rate()
15. ASoC: rsnd: share SSI starting method between PIO/DMA mode
16. ASoC: rsnd: remove un-necessary parameter from rsnd_src_start/stop()
17. ASoC: rsnd: add Synchronous SRC mode
18. ASoC: rsnd: add salvage support for under/over flow error on SSI
19. ASoC: rsnd: add salvage support for under/over flow error on SRC
20. ASoC: rsnd: rename SSI function name of PIO
include/sound/rcar_snd.h | 9 +-
sound/soc/sh/rcar/adg.c | 2 +-
sound/soc/sh/rcar/core.c | 166 +++++++++++++++++++-
sound/soc/sh/rcar/dvc.c | 177 ++--------------------
sound/soc/sh/rcar/gen.c | 15 ++
sound/soc/sh/rcar/rsnd.h | 94 +++++++++++-
sound/soc/sh/rcar/src.c | 378 +++++++++++++++++++++++++++++++++++++++-------
sound/soc/sh/rcar/ssi.c | 205 +++++++++++++++----------
8 files changed, 736 insertions(+), 310 deletions(-)
3
40
[alsa-devel] [PATCH 1/2] ASoC: core: Add extra dapm properties for Device Tree
by Nicolin Chen 24 Feb '15
by Nicolin Chen 24 Feb '15
24 Feb '15
The current helper functions, snd_soc_of_parse_audio_simple_widgets()
and snd_soc_of_parse_audio_routing(), set dapm_widgets and dapm_routes
without caring if they are already set by using build-in widgets and
routes in the card driver. So there could be one of them, build-in one
or Device Tree one, overrided by the other depending on which one was
assigned later.
This patch adds an extra pair of dapm_widgets and dapm_routes for DT
use only so as to prevent unexpected overriding.
Signed-off-by: Nicolin Chen <nicoleotsuka(a)gmail.com>
---
include/sound/soc.h | 5 +++++
sound/soc/soc-core.c | 16 ++++++++++++----
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index ac8b333..7443062 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1068,11 +1068,16 @@ struct snd_soc_card {
/*
* Card-specific routes and widgets.
+ * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
*/
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
+ const struct snd_soc_dapm_widget *of_dapm_widgets;
+ int num_of_dapm_widgets;
+ const struct snd_soc_dapm_route *of_dapm_routes;
+ int num_of_dapm_routes;
bool fully_routed;
struct work_struct deferred_resume_work;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c024962..2695a12 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1486,6 +1486,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
card->num_dapm_widgets);
+ if (card->of_dapm_widgets)
+ snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
+ card->num_of_dapm_widgets);
+
/* initialise the sound card only once */
if (card->probe) {
ret = card->probe(card);
@@ -1541,6 +1545,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
+ if (card->of_dapm_routes)
+ snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
+ card->num_of_dapm_routes);
+
for (i = 0; i < card->num_links; i++) {
struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
dai_link = &card->dai_link[i];
@@ -3187,8 +3195,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
widgets[i].name = wname;
}
- card->dapm_widgets = widgets;
- card->num_dapm_widgets = num_widgets;
+ card->of_dapm_widgets = widgets;
+ card->num_of_dapm_widgets = num_widgets;
return 0;
}
@@ -3272,8 +3280,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
}
}
- card->num_dapm_routes = num_routes;
- card->dapm_routes = routes;
+ card->num_of_dapm_routes = num_routes;
+ card->of_dapm_routes = routes;
return 0;
}
--
1.9.1
2
2