ASoC: Initial WM8904 CODEC driver
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Thu, 26 Nov 2009 11:56:07 +0000 (11:56 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Fri, 4 Dec 2009 16:50:53 +0000 (16:50 +0000)
The WM8904 is a high performance ultra-low power stereo CODEC
optimised for portable audio applications, with features including
a class W amplifier, FLL with free running mode, Mobile ReTune and
ground referenced headphone and line outputs.

Support for some features, most particularly the digital microphone
interface, is not yet present.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
include/sound/wm8904.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/wm8904.c [new file with mode: 0644]
sound/soc/codecs/wm8904.h [new file with mode: 0644]

diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h
new file mode 100644 (file)
index 0000000..d66575a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Platform data for WM8904
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __MFD_WM8994_PDATA_H__
+#define __MFD_WM8994_PDATA_H__
+
+#define WM8904_DRC_REGS 4
+#define WM8904_EQ_REGS  25
+
+/**
+ * DRC configurations are specified with a label and a set of register
+ * values to write (the enable bits will be ignored).  At runtime an
+ * enumerated control will be presented for each DRC block allowing
+ * the user to choose the configration to use.
+ *
+ * Configurations may be generated by hand or by using the DRC control
+ * panel provided by the WISCE - see  http://www.wolfsonmicro.com/wisce/
+ * for details.
+ */
+struct wm8904_drc_cfg {
+       const char *name;
+       u16 regs[WM8904_DRC_REGS];
+};
+
+/**
+ * ReTune Mobile configurations are specified with a label, sample
+ * rate and set of values to write (the enable bits will be ignored).
+ *
+ * Configurations are expected to be generated using the ReTune Mobile
+ * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8904_retune_mobile_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 regs[WM8904_EQ_REGS];
+};
+
+struct wm8904_pdata {
+       int num_drc_cfgs;
+       struct wm8904_drc_cfg *drc_cfgs;
+
+       int num_retune_mobile_cfgs;
+       struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
+};
+
+#endif
index 52b005f8fed413ca052c2e1bc3dca9e7155c6ea2..011d3ab7e64adb14899ef7268a706db24416895e 100644 (file)
@@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
+       select SND_SOC_WM8904 if I2C
        select SND_SOC_WM8940 if I2C
        select SND_SOC_WM8960 if I2C
        select SND_SOC_WM8961 if I2C
@@ -203,6 +204,9 @@ config SND_SOC_WM8900
 config SND_SOC_WM8903
        tristate
 
+config SND_SOC_WM8904
+       tristate
+
 config SND_SOC_WM8940
         tristate
 
index dbaecb133ac72da0331e66cd7c33d5605d370862..0471d90442059e8e4f03ae3f6fe4d8756f05e6e6 100644 (file)
@@ -36,6 +36,7 @@ snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8904-objs := wm8904.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8961-objs := wm8961.o
@@ -92,6 +93,7 @@ obj-$(CONFIG_SND_SOC_WM8753)  += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
+obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)   += snd-soc-wm8974.o
 obj-$(CONFIG_SND_SOC_WM8940)   += snd-soc-wm8940.o
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
new file mode 100644 (file)
index 0000000..8310e5d
--- /dev/null
@@ -0,0 +1,2538 @@
+/*
+ * wm8904.c  --  WM8904 ALSA SoC Audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8904.h>
+
+#include "wm8904.h"
+
+static struct snd_soc_codec *wm8904_codec;
+struct snd_soc_codec_device soc_codec_dev_wm8904;
+
+#define WM8904_NUM_DCS_CHANNELS 4
+
+#define WM8904_NUM_SUPPLIES 5
+static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD",
+       "CPVDD",
+       "MICVDD",
+};
+
+/* codec private data */
+struct wm8904_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM8904_MAX_REGISTER + 1];
+
+       struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
+
+       struct wm8904_pdata *pdata;
+
+       int deemph;
+
+       /* Platform provided DRC configuration */
+       const char **drc_texts;
+       int drc_cfg;
+       struct soc_enum drc_enum;
+
+       /* Platform provided ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg;
+       struct soc_enum retune_mobile_enum;
+
+       /* FLL setup */
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       /* Clocking configuration */
+       unsigned int mclk_rate;
+       int sysclk_src;
+       unsigned int sysclk_rate;
+
+       int tdm_width;
+       int tdm_slots;
+       int bclk;
+       int fs;
+
+       /* DC servo configuration - cached offset values */
+       int dcs_state[WM8904_NUM_DCS_CHANNELS];
+};
+
+static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = {
+       0x8904,     /* R0   - SW Reset and ID */
+       0x0000,     /* R1   - Revision */
+       0x0000,     /* R2 */
+       0x0000,     /* R3 */
+       0x0018,     /* R4   - Bias Control 0 */
+       0x0000,     /* R5   - VMID Control 0 */
+       0x0000,     /* R6   - Mic Bias Control 0 */
+       0x0000,     /* R7   - Mic Bias Control 1 */
+       0x0001,     /* R8   - Analogue DAC 0 */
+       0x9696,     /* R9   - mic Filter Control */
+       0x0001,     /* R10  - Analogue ADC 0 */
+       0x0000,     /* R11 */
+       0x0000,     /* R12  - Power Management 0 */
+       0x0000,     /* R13 */
+       0x0000,     /* R14  - Power Management 2 */
+       0x0000,     /* R15  - Power Management 3 */
+       0x0000,     /* R16 */
+       0x0000,     /* R17 */
+       0x0000,     /* R18  - Power Management 6 */
+       0x0000,     /* R19 */
+       0x945E,     /* R20  - Clock Rates 0 */
+       0x0C05,     /* R21  - Clock Rates 1 */
+       0x0006,     /* R22  - Clock Rates 2 */
+       0x0000,     /* R23 */
+       0x0050,     /* R24  - Audio Interface 0 */
+       0x000A,     /* R25  - Audio Interface 1 */
+       0x00E4,     /* R26  - Audio Interface 2 */
+       0x0040,     /* R27  - Audio Interface 3 */
+       0x0000,     /* R28 */
+       0x0000,     /* R29 */
+       0x00C0,     /* R30  - DAC Digital Volume Left */
+       0x00C0,     /* R31  - DAC Digital Volume Right */
+       0x0000,     /* R32  - DAC Digital 0 */
+       0x0008,     /* R33  - DAC Digital 1 */
+       0x0000,     /* R34 */
+       0x0000,     /* R35 */
+       0x00C0,     /* R36  - ADC Digital Volume Left */
+       0x00C0,     /* R37  - ADC Digital Volume Right */
+       0x0010,     /* R38  - ADC Digital 0 */
+       0x0000,     /* R39  - Digital Microphone 0 */
+       0x01AF,     /* R40  - DRC 0 */
+       0x3248,     /* R41  - DRC 1 */
+       0x0000,     /* R42  - DRC 2 */
+       0x0000,     /* R43  - DRC 3 */
+       0x0085,     /* R44  - Analogue Left Input 0 */
+       0x0085,     /* R45  - Analogue Right Input 0 */
+       0x0044,     /* R46  - Analogue Left Input 1 */
+       0x0044,     /* R47  - Analogue Right Input 1 */
+       0x0000,     /* R48 */
+       0x0000,     /* R49 */
+       0x0000,     /* R50 */
+       0x0000,     /* R51 */
+       0x0000,     /* R52 */
+       0x0000,     /* R53 */
+       0x0000,     /* R54 */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x002D,     /* R57  - Analogue OUT1 Left */
+       0x002D,     /* R58  - Analogue OUT1 Right */
+       0x0039,     /* R59  - Analogue OUT2 Left */
+       0x0039,     /* R60  - Analogue OUT2 Right */
+       0x0000,     /* R61  - Analogue OUT12 ZC */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x0000,     /* R64 */
+       0x0000,     /* R65 */
+       0x0000,     /* R66 */
+       0x0000,     /* R67  - DC Servo 0 */
+       0x0000,     /* R68  - DC Servo 1 */
+       0xAAAA,     /* R69  - DC Servo 2 */
+       0x0000,     /* R70 */
+       0xAAAA,     /* R71  - DC Servo 4 */
+       0xAAAA,     /* R72  - DC Servo 5 */
+       0x0000,     /* R73  - DC Servo 6 */
+       0x0000,     /* R74  - DC Servo 7 */
+       0x0000,     /* R75  - DC Servo 8 */
+       0x0000,     /* R76  - DC Servo 9 */
+       0x0000,     /* R77  - DC Servo Readback 0 */
+       0x0000,     /* R78 */
+       0x0000,     /* R79 */
+       0x0000,     /* R80 */
+       0x0000,     /* R81 */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0000,     /* R88 */
+       0x0000,     /* R89 */
+       0x0000,     /* R90  - Analogue HP 0 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92 */
+       0x0000,     /* R93 */
+       0x0000,     /* R94  - Analogue Lineout 0 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96 */
+       0x0000,     /* R97 */
+       0x0000,     /* R98  - Charge Pump 0 */
+       0x0000,     /* R99 */
+       0x0000,     /* R100 */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x0004,     /* R104 - Class W 0 */
+       0x0000,     /* R105 */
+       0x0000,     /* R106 */
+       0x0000,     /* R107 */
+       0x0000,     /* R108 - Write Sequencer 0 */
+       0x0000,     /* R109 - Write Sequencer 1 */
+       0x0000,     /* R110 - Write Sequencer 2 */
+       0x0000,     /* R111 - Write Sequencer 3 */
+       0x0000,     /* R112 - Write Sequencer 4 */
+       0x0000,     /* R113 */
+       0x0000,     /* R114 */
+       0x0000,     /* R115 */
+       0x0000,     /* R116 - FLL Control 1 */
+       0x0007,     /* R117 - FLL Control 2 */
+       0x0000,     /* R118 - FLL Control 3 */
+       0x2EE0,     /* R119 - FLL Control 4 */
+       0x0004,     /* R120 - FLL Control 5 */
+       0x0014,     /* R121 - GPIO Control 1 */
+       0x0010,     /* R122 - GPIO Control 2 */
+       0x0010,     /* R123 - GPIO Control 3 */
+       0x0000,     /* R124 - GPIO Control 4 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 - Digital Pulls */
+       0x0000,     /* R127 - Interrupt Status */
+       0xFFFF,     /* R128 - Interrupt Status Mask */
+       0x0000,     /* R129 - Interrupt Polarity */
+       0x0000,     /* R130 - Interrupt Debounce */
+       0x0000,     /* R131 */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 */
+       0x0000,     /* R134 - EQ1 */
+       0x000C,     /* R135 - EQ2 */
+       0x000C,     /* R136 - EQ3 */
+       0x000C,     /* R137 - EQ4 */
+       0x000C,     /* R138 - EQ5 */
+       0x000C,     /* R139 - EQ6 */
+       0x0FCA,     /* R140 - EQ7 */
+       0x0400,     /* R141 - EQ8 */
+       0x00D8,     /* R142 - EQ9 */
+       0x1EB5,     /* R143 - EQ10 */
+       0xF145,     /* R144 - EQ11 */
+       0x0B75,     /* R145 - EQ12 */
+       0x01C5,     /* R146 - EQ13 */
+       0x1C58,     /* R147 - EQ14 */
+       0xF373,     /* R148 - EQ15 */
+       0x0A54,     /* R149 - EQ16 */
+       0x0558,     /* R150 - EQ17 */
+       0x168E,     /* R151 - EQ18 */
+       0xF829,     /* R152 - EQ19 */
+       0x07AD,     /* R153 - EQ20 */
+       0x1103,     /* R154 - EQ21 */
+       0x0564,     /* R155 - EQ22 */
+       0x0559,     /* R156 - EQ23 */
+       0x4000,     /* R157 - EQ24 */
+       0x0000,     /* R158 */
+       0x0000,     /* R159 */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 - Control Interface Test 1 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 */
+       0x0000,     /* R164 */
+       0x0000,     /* R165 */
+       0x0000,     /* R166 */
+       0x0000,     /* R167 */
+       0x0000,     /* R168 */
+       0x0000,     /* R169 */
+       0x0000,     /* R170 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 */
+       0x0000,     /* R173 */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 */
+       0x0000,     /* R177 */
+       0x0000,     /* R178 */
+       0x0000,     /* R179 */
+       0x0000,     /* R180 */
+       0x0000,     /* R181 */
+       0x0000,     /* R182 */
+       0x0000,     /* R183 */
+       0x0000,     /* R184 */
+       0x0000,     /* R185 */
+       0x0000,     /* R186 */
+       0x0000,     /* R187 */
+       0x0000,     /* R188 */
+       0x0000,     /* R189 */
+       0x0000,     /* R190 */
+       0x0000,     /* R191 */
+       0x0000,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x0000,     /* R195 */
+       0x0000,     /* R196 */
+       0x0000,     /* R197 */
+       0x0000,     /* R198 */
+       0x0000,     /* R199 */
+       0x0000,     /* R200 */
+       0x0000,     /* R201 */
+       0x0000,     /* R202 */
+       0x0000,     /* R203 */
+       0x0000,     /* R204 - Analogue Output Bias 0 */
+       0x0000,     /* R205 */
+       0x0000,     /* R206 */
+       0x0000,     /* R207 */
+       0x0000,     /* R208 */
+       0x0000,     /* R209 */
+       0x0000,     /* R210 */
+       0x0000,     /* R211 */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 */
+       0x0000,     /* R216 */
+       0x0000,     /* R217 */
+       0x0000,     /* R218 */
+       0x0000,     /* R219 */
+       0x0000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0x0000,     /* R230 */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 - FLL NCO Test 0 */
+       0x0019,     /* R248 - FLL NCO Test 1 */
+};
+
+static struct {
+       int readable;
+       int writable;
+       int vol;
+} wm8904_access[] = {
+       { 0xFFFF, 0xFFFF, 1 }, /* R0   - SW Reset and ID */
+       { 0x0000, 0x0000, 0 }, /* R1   - Revision */
+       { 0x0000, 0x0000, 0 }, /* R2 */
+       { 0x0000, 0x0000, 0 }, /* R3 */
+       { 0x001F, 0x001F, 0 }, /* R4   - Bias Control 0 */
+       { 0x0047, 0x0047, 0 }, /* R5   - VMID Control 0 */
+       { 0x007F, 0x007F, 0 }, /* R6   - Mic Bias Control 0 */
+       { 0xC007, 0xC007, 0 }, /* R7   - Mic Bias Control 1 */
+       { 0x001E, 0x001E, 0 }, /* R8   - Analogue DAC 0 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R9   - mic Filter Control */
+       { 0x0001, 0x0001, 0 }, /* R10  - Analogue ADC 0 */
+       { 0x0000, 0x0000, 0 }, /* R11 */
+       { 0x0003, 0x0003, 0 }, /* R12  - Power Management 0 */
+       { 0x0000, 0x0000, 0 }, /* R13 */
+       { 0x0003, 0x0003, 0 }, /* R14  - Power Management 2 */
+       { 0x0003, 0x0003, 0 }, /* R15  - Power Management 3 */
+       { 0x0000, 0x0000, 0 }, /* R16 */
+       { 0x0000, 0x0000, 0 }, /* R17 */
+       { 0x000F, 0x000F, 0 }, /* R18  - Power Management 6 */
+       { 0x0000, 0x0000, 0 }, /* R19 */
+       { 0x7001, 0x7001, 0 }, /* R20  - Clock Rates 0 */
+       { 0x3C07, 0x3C07, 0 }, /* R21  - Clock Rates 1 */
+       { 0xD00F, 0xD00F, 0 }, /* R22  - Clock Rates 2 */
+       { 0x0000, 0x0000, 0 }, /* R23 */
+       { 0x1FFF, 0x1FFF, 0 }, /* R24  - Audio Interface 0 */
+       { 0x3DDF, 0x3DDF, 0 }, /* R25  - Audio Interface 1 */
+       { 0x0F1F, 0x0F1F, 0 }, /* R26  - Audio Interface 2 */
+       { 0x0FFF, 0x0FFF, 0 }, /* R27  - Audio Interface 3 */
+       { 0x0000, 0x0000, 0 }, /* R28 */
+       { 0x0000, 0x0000, 0 }, /* R29 */
+       { 0x00FF, 0x01FF, 0 }, /* R30  - DAC Digital Volume Left */
+       { 0x00FF, 0x01FF, 0 }, /* R31  - DAC Digital Volume Right */
+       { 0x0FFF, 0x0FFF, 0 }, /* R32  - DAC Digital 0 */
+       { 0x1E4E, 0x1E4E, 0 }, /* R33  - DAC Digital 1 */
+       { 0x0000, 0x0000, 0 }, /* R34 */
+       { 0x0000, 0x0000, 0 }, /* R35 */
+       { 0x00FF, 0x01FF, 0 }, /* R36  - ADC Digital Volume Left */
+       { 0x00FF, 0x01FF, 0 }, /* R37  - ADC Digital Volume Right */
+       { 0x0073, 0x0073, 0 }, /* R38  - ADC Digital 0 */
+       { 0x1800, 0x1800, 0 }, /* R39  - Digital Microphone 0 */
+       { 0xDFEF, 0xDFEF, 0 }, /* R40  - DRC 0 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R41  - DRC 1 */
+       { 0x003F, 0x003F, 0 }, /* R42  - DRC 2 */
+       { 0x07FF, 0x07FF, 0 }, /* R43  - DRC 3 */
+       { 0x009F, 0x009F, 0 }, /* R44  - Analogue Left Input 0 */
+       { 0x009F, 0x009F, 0 }, /* R45  - Analogue Right Input 0 */
+       { 0x007F, 0x007F, 0 }, /* R46  - Analogue Left Input 1 */
+       { 0x007F, 0x007F, 0 }, /* R47  - Analogue Right Input 1 */
+       { 0x0000, 0x0000, 0 }, /* R48 */
+       { 0x0000, 0x0000, 0 }, /* R49 */
+       { 0x0000, 0x0000, 0 }, /* R50 */
+       { 0x0000, 0x0000, 0 }, /* R51 */
+       { 0x0000, 0x0000, 0 }, /* R52 */
+       { 0x0000, 0x0000, 0 }, /* R53 */
+       { 0x0000, 0x0000, 0 }, /* R54 */
+       { 0x0000, 0x0000, 0 }, /* R55 */
+       { 0x0000, 0x0000, 0 }, /* R56 */
+       { 0x017F, 0x01FF, 0 }, /* R57  - Analogue OUT1 Left */
+       { 0x017F, 0x01FF, 0 }, /* R58  - Analogue OUT1 Right */
+       { 0x017F, 0x01FF, 0 }, /* R59  - Analogue OUT2 Left */
+       { 0x017F, 0x01FF, 0 }, /* R60  - Analogue OUT2 Right */
+       { 0x000F, 0x000F, 0 }, /* R61  - Analogue OUT12 ZC */
+       { 0x0000, 0x0000, 0 }, /* R62 */
+       { 0x0000, 0x0000, 0 }, /* R63 */
+       { 0x0000, 0x0000, 0 }, /* R64 */
+       { 0x0000, 0x0000, 0 }, /* R65 */
+       { 0x0000, 0x0000, 0 }, /* R66 */
+       { 0x000F, 0x000F, 0 }, /* R67  - DC Servo 0 */
+       { 0xFFFF, 0xFFFF, 1 }, /* R68  - DC Servo 1 */
+       { 0x0F0F, 0x0F0F, 0 }, /* R69  - DC Servo 2 */
+       { 0x0000, 0x0000, 0 }, /* R70 */
+       { 0x007F, 0x007F, 0 }, /* R71  - DC Servo 4 */
+       { 0x007F, 0x007F, 0 }, /* R72  - DC Servo 5 */
+       { 0x00FF, 0x00FF, 1 }, /* R73  - DC Servo 6 */
+       { 0x00FF, 0x00FF, 1 }, /* R74  - DC Servo 7 */
+       { 0x00FF, 0x00FF, 1 }, /* R75  - DC Servo 8 */
+       { 0x00FF, 0x00FF, 1 }, /* R76  - DC Servo 9 */
+       { 0x0FFF, 0x0000, 1 }, /* R77  - DC Servo Readback 0 */
+       { 0x0000, 0x0000, 0 }, /* R78 */
+       { 0x0000, 0x0000, 0 }, /* R79 */
+       { 0x0000, 0x0000, 0 }, /* R80 */
+       { 0x0000, 0x0000, 0 }, /* R81 */
+       { 0x0000, 0x0000, 0 }, /* R82 */
+       { 0x0000, 0x0000, 0 }, /* R83 */
+       { 0x0000, 0x0000, 0 }, /* R84 */
+       { 0x0000, 0x0000, 0 }, /* R85 */
+       { 0x0000, 0x0000, 0 }, /* R86 */
+       { 0x0000, 0x0000, 0 }, /* R87 */
+       { 0x0000, 0x0000, 0 }, /* R88 */
+       { 0x0000, 0x0000, 0 }, /* R89 */
+       { 0x00FF, 0x00FF, 0 }, /* R90  - Analogue HP 0 */
+       { 0x0000, 0x0000, 0 }, /* R91 */
+       { 0x0000, 0x0000, 0 }, /* R92 */
+       { 0x0000, 0x0000, 0 }, /* R93 */
+       { 0x00FF, 0x00FF, 0 }, /* R94  - Analogue Lineout 0 */
+       { 0x0000, 0x0000, 0 }, /* R95 */
+       { 0x0000, 0x0000, 0 }, /* R96 */
+       { 0x0000, 0x0000, 0 }, /* R97 */
+       { 0x0001, 0x0001, 0 }, /* R98  - Charge Pump 0 */
+       { 0x0000, 0x0000, 0 }, /* R99 */
+       { 0x0000, 0x0000, 0 }, /* R100 */
+       { 0x0000, 0x0000, 0 }, /* R101 */
+       { 0x0000, 0x0000, 0 }, /* R102 */
+       { 0x0000, 0x0000, 0 }, /* R103 */
+       { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */
+       { 0x0000, 0x0000, 0 }, /* R105 */
+       { 0x0000, 0x0000, 0 }, /* R106 */
+       { 0x0000, 0x0000, 0 }, /* R107 */
+       { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */
+       { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */
+       { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */
+       { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */
+       { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */
+       { 0x0000, 0x0000, 0 }, /* R113 */
+       { 0x0000, 0x0000, 0 }, /* R114 */
+       { 0x0000, 0x0000, 0 }, /* R115 */
+       { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */
+       { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */
+       { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */
+       { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */
+       { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */
+       { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */
+       { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */
+       { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */
+       { 0x0000, 0x0000, 0 }, /* R125 */
+       { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */
+       { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */
+       { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */
+       { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */
+       { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */
+       { 0x0000, 0x0000, 0 }, /* R131 */
+       { 0x0000, 0x0000, 0 }, /* R132 */
+       { 0x0000, 0x0000, 0 }, /* R133 */
+       { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */
+       { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */
+       { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */
+       { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */
+       { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */
+       { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */
+       { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */
+       { 0x0000, 0x0000, 0 }, /* R158 */
+       { 0x0000, 0x0000, 0 }, /* R159 */
+       { 0x0000, 0x0000, 0 }, /* R160 */
+       { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */
+       { 0x0000, 0x0000, 0 }, /* R162 */
+       { 0x0000, 0x0000, 0 }, /* R163 */
+       { 0x0000, 0x0000, 0 }, /* R164 */
+       { 0x0000, 0x0000, 0 }, /* R165 */
+       { 0x0000, 0x0000, 0 }, /* R166 */
+       { 0x0000, 0x0000, 0 }, /* R167 */
+       { 0x0000, 0x0000, 0 }, /* R168 */
+       { 0x0000, 0x0000, 0 }, /* R169 */
+       { 0x0000, 0x0000, 0 }, /* R170 */
+       { 0x0000, 0x0000, 0 }, /* R171 */
+       { 0x0000, 0x0000, 0 }, /* R172 */
+       { 0x0000, 0x0000, 0 }, /* R173 */
+       { 0x0000, 0x0000, 0 }, /* R174 */
+       { 0x0000, 0x0000, 0 }, /* R175 */
+       { 0x0000, 0x0000, 0 }, /* R176 */
+       { 0x0000, 0x0000, 0 }, /* R177 */
+       { 0x0000, 0x0000, 0 }, /* R178 */
+       { 0x0000, 0x0000, 0 }, /* R179 */
+       { 0x0000, 0x0000, 0 }, /* R180 */
+       { 0x0000, 0x0000, 0 }, /* R181 */
+       { 0x0000, 0x0000, 0 }, /* R182 */
+       { 0x0000, 0x0000, 0 }, /* R183 */
+       { 0x0000, 0x0000, 0 }, /* R184 */
+       { 0x0000, 0x0000, 0 }, /* R185 */
+       { 0x0000, 0x0000, 0 }, /* R186 */
+       { 0x0000, 0x0000, 0 }, /* R187 */
+       { 0x0000, 0x0000, 0 }, /* R188 */
+       { 0x0000, 0x0000, 0 }, /* R189 */
+       { 0x0000, 0x0000, 0 }, /* R190 */
+       { 0x0000, 0x0000, 0 }, /* R191 */
+       { 0x0000, 0x0000, 0 }, /* R192 */
+       { 0x0000, 0x0000, 0 }, /* R193 */
+       { 0x0000, 0x0000, 0 }, /* R194 */
+       { 0x0000, 0x0000, 0 }, /* R195 */
+       { 0x0000, 0x0000, 0 }, /* R196 */
+       { 0x0000, 0x0000, 0 }, /* R197 */
+       { 0x0000, 0x0000, 0 }, /* R198 */
+       { 0x0000, 0x0000, 0 }, /* R199 */
+       { 0x0000, 0x0000, 0 }, /* R200 */
+       { 0x0000, 0x0000, 0 }, /* R201 */
+       { 0x0000, 0x0000, 0 }, /* R202 */
+       { 0x0000, 0x0000, 0 }, /* R203 */
+       { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */
+       { 0x0000, 0x0000, 0 }, /* R205 */
+       { 0x0000, 0x0000, 0 }, /* R206 */
+       { 0x0000, 0x0000, 0 }, /* R207 */
+       { 0x0000, 0x0000, 0 }, /* R208 */
+       { 0x0000, 0x0000, 0 }, /* R209 */
+       { 0x0000, 0x0000, 0 }, /* R210 */
+       { 0x0000, 0x0000, 0 }, /* R211 */
+       { 0x0000, 0x0000, 0 }, /* R212 */
+       { 0x0000, 0x0000, 0 }, /* R213 */
+       { 0x0000, 0x0000, 0 }, /* R214 */
+       { 0x0000, 0x0000, 0 }, /* R215 */
+       { 0x0000, 0x0000, 0 }, /* R216 */
+       { 0x0000, 0x0000, 0 }, /* R217 */
+       { 0x0000, 0x0000, 0 }, /* R218 */
+       { 0x0000, 0x0000, 0 }, /* R219 */
+       { 0x0000, 0x0000, 0 }, /* R220 */
+       { 0x0000, 0x0000, 0 }, /* R221 */
+       { 0x0000, 0x0000, 0 }, /* R222 */
+       { 0x0000, 0x0000, 0 }, /* R223 */
+       { 0x0000, 0x0000, 0 }, /* R224 */
+       { 0x0000, 0x0000, 0 }, /* R225 */
+       { 0x0000, 0x0000, 0 }, /* R226 */
+       { 0x0000, 0x0000, 0 }, /* R227 */
+       { 0x0000, 0x0000, 0 }, /* R228 */
+       { 0x0000, 0x0000, 0 }, /* R229 */
+       { 0x0000, 0x0000, 0 }, /* R230 */
+       { 0x0000, 0x0000, 0 }, /* R231 */
+       { 0x0000, 0x0000, 0 }, /* R232 */
+       { 0x0000, 0x0000, 0 }, /* R233 */
+       { 0x0000, 0x0000, 0 }, /* R234 */
+       { 0x0000, 0x0000, 0 }, /* R235 */
+       { 0x0000, 0x0000, 0 }, /* R236 */
+       { 0x0000, 0x0000, 0 }, /* R237 */
+       { 0x0000, 0x0000, 0 }, /* R238 */
+       { 0x0000, 0x0000, 0 }, /* R239 */
+       { 0x0000, 0x0000, 0 }, /* R240 */
+       { 0x0000, 0x0000, 0 }, /* R241 */
+       { 0x0000, 0x0000, 0 }, /* R242 */
+       { 0x0000, 0x0000, 0 }, /* R243 */
+       { 0x0000, 0x0000, 0 }, /* R244 */
+       { 0x0000, 0x0000, 0 }, /* R245 */
+       { 0x0000, 0x0000, 0 }, /* R246 */
+       { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */
+       { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */
+};
+
+static int wm8904_volatile_register(unsigned int reg)
+{
+       return wm8904_access[reg].vol;
+}
+
+static int wm8904_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0);
+}
+
+static int wm8904_configure_clocking(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       unsigned int clock0, clock2, rate;
+
+       /* Gate the clock while we're updating to avoid misclocking */
+       clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_SYSCLK_SRC, 0);
+
+       /* This should be done on init() for bypass paths */
+       switch (wm8904->sysclk_src) {
+       case WM8904_CLK_MCLK:
+               dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate);
+
+               clock2 &= ~WM8904_SYSCLK_SRC;
+               rate = wm8904->mclk_rate;
+
+               /* Ensure the FLL is stopped */
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                   WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+               break;
+
+       case WM8904_CLK_FLL:
+               dev_dbg(codec->dev, "Using %dHz FLL clock\n",
+                       wm8904->fll_fout);
+
+               clock2 |= WM8904_SYSCLK_SRC;
+               rate = wm8904->fll_fout;
+               break;
+
+       default:
+               dev_err(codec->dev, "System clock not configured\n");
+               return -EINVAL;
+       }
+
+       /* SYSCLK shouldn't be over 13.5MHz */
+       if (rate > 13500000) {
+               clock0 = WM8904_MCLK_DIV;
+               wm8904->sysclk_rate = rate / 2;
+       } else {
+               clock0 = 0;
+               wm8904->sysclk_rate = rate;
+       }
+
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV,
+                           clock0);
+
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2);
+
+       dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate);
+
+       return 0;
+}
+
+static void wm8904_set_drc(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int save, i;
+
+       /* Save any enables; the configuration should clear them. */
+       save = snd_soc_read(codec, WM8904_DRC_0);
+
+       for (i = 0; i < WM8904_DRC_REGS; i++)
+               snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff,
+                                   pdata->drc_cfgs[wm8904->drc_cfg].regs[i]);
+
+       /* Reenable the DRC */
+       snd_soc_update_bits(codec, WM8904_DRC_0,
+                           WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save);
+}
+
+static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;       
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int value = ucontrol->value.integer.value[0];
+
+       if (value >= pdata->num_drc_cfgs)
+               return -EINVAL;
+
+       wm8904->drc_cfg = value;
+
+       wm8904_set_drc(codec);
+
+       return 0;
+}
+
+static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
+
+       return 0;
+}
+
+static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int best, best_val, save, i, cfg;
+
+       if (!pdata || !wm8904->num_retune_mobile_texts)
+               return;
+
+       /* Find the version of the currently selected configuration
+        * with the nearest sample rate. */
+       cfg = wm8904->retune_mobile_cfg;
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                          wm8904->retune_mobile_texts[cfg]) == 0 &&
+                   abs(pdata->retune_mobile_cfgs[i].rate
+                       - wm8904->fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
+                                      - wm8904->fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n",
+               pdata->retune_mobile_cfgs[best].name,
+               pdata->retune_mobile_cfgs[best].rate,
+               wm8904->fs);
+
+       /* The EQ will be disabled while reconfiguring it, remember the
+        * current configuration. 
+        */
+       save = snd_soc_read(codec, WM8904_EQ1);
+
+       for (i = 0; i < WM8904_EQ_REGS; i++)
+               snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff,
+                               pdata->retune_mobile_cfgs[best].regs[i]);
+
+       snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save);
+}
+
+static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;       
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int value = ucontrol->value.integer.value[0];
+
+       if (value >= pdata->num_retune_mobile_cfgs)
+               return -EINVAL;
+
+       wm8904->retune_mobile_cfg = value;
+
+       wm8904_set_retune_mobile(codec);
+
+       return 0;
+}
+
+static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
+
+       return 0;
+}
+
+static int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8904_set_deemph(struct snd_soc_codec *codec)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int val, i, best;
+
+       /* If we're using deemphasis select the nearest available sample 
+        * rate.
+        */
+       if (wm8904->deemph) {
+               best = 1;
+               for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+                       if (abs(deemph_settings[i] - wm8904->fs) <
+                           abs(deemph_settings[best] - wm8904->fs))
+                               best = i;
+               }
+
+               val = best << WM8904_DEEMPH_SHIFT;
+       } else {
+               val = 0;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+
+       return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
+                                  WM8904_DEEMPH_MASK, val);
+}
+
+static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       return wm8904->deemph;
+}
+
+static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int deemph = ucontrol->value.enumerated.item[0];
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       wm8904->deemph = deemph;
+
+       return wm8904_set_deemph(codec);
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *input_mode_text[] = {
+       "Single-Ended", "Differential Line", "Differential Mic"
+};
+
+static const struct soc_enum lin_mode =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+
+static const struct soc_enum rin_mode =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+
+static const char *hpf_mode_text[] = {
+       "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static const struct soc_enum hpf_mode =
+       SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+
+static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
+                WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
+
+SOC_ENUM("Left Caputure Mode", lin_mode),
+SOC_ENUM("Right Capture Mode", rin_mode),
+
+/* No TLV since it depends on mode */
+SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0,
+            WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
+            WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0),
+
+SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
+SOC_ENUM("High Pass Filter Mode", hpf_mode),
+
+SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0),
+};
+
+static const char *drc_path_text[] = {
+       "ADC", "DAC"
+};
+
+static const struct soc_enum drc_path =
+       SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text);
+
+static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {
+SOC_SINGLE_TLV("Digital Playback Boost Volume", 
+              WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv),
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT,
+                WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT,
+                WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT,
+            WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT,
+            WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT,
+                WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT,
+            WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT,
+            WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0),
+
+SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0),
+SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0),
+SOC_ENUM("DRC Path", drc_path),
+SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+                   wm8904_get_deemph, wm8904_put_deemph),
+};
+
+static const struct snd_kcontrol_new wm8904_snd_controls[] = {
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0,
+              sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new wm8904_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       BUG_ON(event != SND_SOC_DAPM_POST_PMU);
+
+       /* Maximum startup time */
+       udelay(500);
+
+       return 0;
+}
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8904_priv *wm8904 = codec->private_data;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* If we're using the FLL then we only start it when
+                * required; we assume that the configuration has been
+                * done previously and all we need to do is kick it
+                * off.
+                */
+               switch (wm8904->sysclk_src) {
+               case WM8904_CLK_FLL:
+                       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                           WM8904_FLL_OSC_ENA,
+                                           WM8904_FLL_OSC_ENA);
+
+                       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                           WM8904_FLL_ENA,
+                                           WM8904_FLL_ENA);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                   WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int reg, val;
+       int dcs_mask;
+       int dcs_l, dcs_r;
+       int dcs_l_reg, dcs_r_reg;
+       int timeout;
+
+       /* This code is shared between HP and LINEOUT; we do all our
+        * power management in stereo pairs to avoid latency issues so
+        * we reuse shift to identify which rather than strcmp() the
+        * name. */
+       reg = w->shift;
+
+       switch (reg) {
+       case WM8904_ANALOGUE_HP_0:
+               dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
+               dcs_r_reg = WM8904_DC_SERVO_8;
+               dcs_l_reg = WM8904_DC_SERVO_9;
+               dcs_l = 0;
+               dcs_r = 1;
+               break;
+       case WM8904_ANALOGUE_LINEOUT_0:
+               dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
+               dcs_r_reg = WM8904_DC_SERVO_6;
+               dcs_l_reg = WM8904_DC_SERVO_7;
+               dcs_l = 2;
+               dcs_r = 3;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* Power on the amplifier */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA | WM8904_HPR_ENA,
+                                   WM8904_HPL_ENA | WM8904_HPR_ENA);
+
+               /* Enable the first stage */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY,
+                                   WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY);
+
+               /* Power up the DC servo */
+               snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
+                                   dcs_mask, dcs_mask);
+
+               /* Either calibrate the DC servo or restore cached state
+                * if we have that.
+                */
+               if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) {
+                       dev_dbg(codec->dev, "Restoring DC servo state\n");
+
+                       snd_soc_write(codec, dcs_l_reg,
+                                     wm8904->dcs_state[dcs_l]);
+                       snd_soc_write(codec, dcs_r_reg,
+                                     wm8904->dcs_state[dcs_r]);
+
+                       snd_soc_write(codec, WM8904_DC_SERVO_1, dcs_mask);
+
+                       timeout = 20;
+               } else {
+                       dev_dbg(codec->dev, "Calibrating DC servo\n");
+
+                       snd_soc_write(codec, WM8904_DC_SERVO_1,
+                               dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT);
+
+                       timeout = 500;
+               }
+
+               /* Wait for DC servo to complete */
+               dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT;
+               do {
+                       val = snd_soc_read(codec, WM8904_DC_SERVO_READBACK_0);
+                       if ((val & dcs_mask) == dcs_mask)
+                               break;
+
+                       msleep(1);
+               } while (--timeout);
+
+               if ((val & dcs_mask) != dcs_mask)
+                       dev_warn(codec->dev, "DC servo timed out\n");
+               else
+                       dev_dbg(codec->dev, "DC servo ready\n");
+
+               /* Enable the output stage */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+                                   WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
+
+               /* Unshort the output itself */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_RMV_SHORT |
+                                   WM8904_HPR_RMV_SHORT,
+                                   WM8904_HPL_RMV_SHORT |
+                                   WM8904_HPR_RMV_SHORT);
+
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Short the output */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_RMV_SHORT |
+                                   WM8904_HPR_RMV_SHORT, 0);
+
+               /* Cache the DC servo configuration; this will be
+                * invalidated if we change the configuration. */
+               wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg);
+               wm8904->dcs_state[dcs_r] = snd_soc_read(codec, dcs_r_reg);
+
+               snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
+                                   dcs_mask, 0);
+
+               /* Disable the amplifier input and output stages */
+               snd_soc_update_bits(codec, reg,
+                                   WM8904_HPL_ENA | WM8904_HPR_ENA |
+                                   WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY |
+                                   WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+                                   0);
+               break;
+       }
+
+       return 0;
+}
+
+static const char *lin_text[] = {
+       "IN1L", "IN2L", "IN3L"
+};
+
+static const struct soc_enum lin_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text);
+
+static const struct snd_kcontrol_new lin_mux =
+       SOC_DAPM_ENUM("Left Capture Mux", lin_enum);
+
+static const struct soc_enum lin_inv_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text);
+
+static const struct snd_kcontrol_new lin_inv_mux =
+       SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum);
+
+static const char *rin_text[] = {
+       "IN1R", "IN2R", "IN3R"
+};
+
+static const struct soc_enum rin_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text);
+
+static const struct snd_kcontrol_new rin_mux =
+       SOC_DAPM_ENUM("Right Capture Mux", rin_enum);
+
+static const struct soc_enum rin_inv_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text);
+
+static const struct snd_kcontrol_new rin_inv_mux =
+       SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum);
+
+static const char *aif_text[] = {
+       "Left", "Right"
+};
+
+static const struct soc_enum aifoutl_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text);
+
+static const struct snd_kcontrol_new aifoutl_mux =
+       SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
+
+static const struct soc_enum aifoutr_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text);
+
+static const struct snd_kcontrol_new aifoutr_mux =
+       SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
+
+static const struct soc_enum aifinl_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text);
+
+static const struct snd_kcontrol_new aifinl_mux =
+       SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
+
+static const struct soc_enum aifinr_enum =
+       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text);
+
+static const struct snd_kcontrol_new aifinr_mux =
+       SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
+
+static const struct snd_soc_dapm_widget wm8904_core_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8904_CLOCK_RATES_2, 2, 0, sysclk_event,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8904_CLOCK_RATES_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8904_CLOCK_RATES_2, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8904_adc_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux),
+SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
+                &lin_inv_mux),
+SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux),
+SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
+                &rin_inv_mux),
+
+SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("Right Capture PGA", WM8904_POWER_MANAGEMENT_0, 0, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8904_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8904_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux),
+SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = {
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux),
+SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux),
+
+SND_SOC_DAPM_DAC("DACL", NULL, WM8904_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0),
+
+SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event,
+                   SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("HPL PGA", WM8904_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("HPR PGA", WM8904_POWER_MANAGEMENT_2, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LINEL PGA", WM8904_POWER_MANAGEMENT_3, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINER PGA", WM8904_POWER_MANAGEMENT_3, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0,
+                  0, NULL, 0, out_pga_event,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0,
+                  0, NULL, 0, out_pga_event,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+};
+
+static const char *out_mux_text[] = {
+       "DAC", "Bypass"
+};
+
+static const struct soc_enum hpl_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+       SOC_DAPM_ENUM("HPL Mux", hpl_enum);
+
+static const struct soc_enum hpr_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+       SOC_DAPM_ENUM("HPR Mux", hpr_enum);
+
+static const struct soc_enum linel_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text);
+
+static const struct snd_kcontrol_new linel_mux =
+       SOC_DAPM_ENUM("LINEL Mux", linel_enum);
+
+static const struct soc_enum liner_enum =
+       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
+
+static const struct snd_kcontrol_new liner_mux =
+       SOC_DAPM_ENUM("LINEL Mux", liner_enum);
+
+static const char *sidetone_text[] = {
+       "None", "Left", "Right"
+};
+
+static const struct soc_enum dacl_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text);
+
+static const struct snd_kcontrol_new dacl_sidetone_mux =
+       SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum);
+
+static const struct soc_enum dacr_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text);
+
+static const struct snd_kcontrol_new dacr_sidetone_mux =
+       SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum);
+
+static const struct snd_soc_dapm_widget wm8904_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Class G", WM8904_CLASS_W_0, 0, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &dacl_sidetone_mux),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &dacr_sidetone_mux),
+
+SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
+SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("LINEL Mux", SND_SOC_NOPM, 0, 0, &linel_mux),
+SND_SOC_DAPM_MUX("LINER Mux", SND_SOC_NOPM, 0, 0, &liner_mux),
+};
+
+static const struct snd_soc_dapm_route core_intercon[] = {
+       { "CLK_DSP", NULL, "SYSCLK" },
+       { "TOCLK", NULL, "SYSCLK" },
+};
+
+static const struct snd_soc_dapm_route adc_intercon[] = {
+       { "Left Capture Mux", "IN1L", "IN1L" },
+       { "Left Capture Mux", "IN2L", "IN2L" },
+       { "Left Capture Mux", "IN3L", "IN3L" },
+
+       { "Left Capture Inverting Mux", "IN1L", "IN1L" },
+       { "Left Capture Inverting Mux", "IN2L", "IN2L" },
+       { "Left Capture Inverting Mux", "IN3L", "IN3L" },
+
+       { "Right Capture Mux", "IN1R", "IN1R" },
+       { "Right Capture Mux", "IN2R", "IN2R" },
+       { "Right Capture Mux", "IN3R", "IN3R" },
+
+       { "Right Capture Inverting Mux", "IN1R", "IN1R" },
+       { "Right Capture Inverting Mux", "IN2R", "IN2R" },
+       { "Right Capture Inverting Mux", "IN3R", "IN3R" },
+
+       { "Left Capture PGA", NULL, "Left Capture Mux" },
+       { "Left Capture PGA", NULL, "Left Capture Inverting Mux" },
+
+       { "Right Capture PGA", NULL, "Right Capture Mux" },
+       { "Right Capture PGA", NULL, "Right Capture Inverting Mux" },
+
+       { "AIFOUTL", "Left",  "ADCL" },
+       { "AIFOUTL", "Right", "ADCR" },
+       { "AIFOUTR", "Left",  "ADCL" },
+       { "AIFOUTR", "Right", "ADCR" },
+
+       { "ADCL", NULL, "CLK_DSP" },
+       { "ADCL", NULL, "Left Capture PGA" },
+
+       { "ADCR", NULL, "CLK_DSP" },
+       { "ADCR", NULL, "Right Capture PGA" },
+};
+
+static const struct snd_soc_dapm_route dac_intercon[] = {
+       { "DACL", "Right", "AIFINR" },
+       { "DACL", "Left",  "AIFINL" },
+       { "DACL", NULL, "CLK_DSP" },
+
+       { "DACR", "Right", "AIFINR" },
+       { "DACR", "Left",  "AIFINL" },
+       { "DACR", NULL, "CLK_DSP" },
+
+       { "Charge pump", NULL, "SYSCLK" },
+
+       { "Headphone Output", NULL, "HPL PGA" },
+       { "Headphone Output", NULL, "HPR PGA" },
+       { "Headphone Output", NULL, "Charge pump" },
+       { "Headphone Output", NULL, "TOCLK" },
+
+       { "Line Output", NULL, "LINEL PGA" },
+       { "Line Output", NULL, "LINER PGA" },
+       { "Line Output", NULL, "Charge pump" },
+       { "Line Output", NULL, "TOCLK" },
+
+       { "HPOUTL", NULL, "Headphone Output" },
+       { "HPOUTR", NULL, "Headphone Output" },
+
+       { "LINEOUTL", NULL, "Line Output" },
+       { "LINEOUTR", NULL, "Line Output" },
+};
+
+static const struct snd_soc_dapm_route wm8904_intercon[] = {
+       { "Left Sidetone", "Left", "ADCL" },
+       { "Left Sidetone", "Right", "ADCR" },
+       { "DACL", NULL, "Left Sidetone" },
+       
+       { "Right Sidetone", "Left", "ADCL" },
+       { "Right Sidetone", "Right", "ADCR" },
+       { "DACR", NULL, "Right Sidetone" },
+
+       { "Left Bypass", NULL, "Class G" },
+       { "Left Bypass", NULL, "Left Capture PGA" },
+
+       { "Right Bypass", NULL, "Class G" },
+       { "Right Bypass", NULL, "Right Capture PGA" },
+
+       { "HPL Mux", "DAC", "DACL" },
+       { "HPL Mux", "Bypass", "Left Bypass" },
+
+       { "HPR Mux", "DAC", "DACR" },
+       { "HPR Mux", "Bypass", "Right Bypass" },
+
+       { "LINEL Mux", "DAC", "DACL" },
+       { "LINEL Mux", "Bypass", "Left Bypass" },
+
+       { "LINER Mux", "DAC", "DACR" },
+       { "LINER Mux", "Bypass", "Right Bypass" },
+
+       { "HPL PGA", NULL, "HPL Mux" },
+       { "HPR PGA", NULL, "HPR Mux" },
+
+       { "LINEL PGA", NULL, "LINEL Mux" },
+       { "LINER PGA", NULL, "LINER Mux" },
+};
+
+static int wm8904_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_add_controls(codec, wm8904_adc_snd_controls,
+                            ARRAY_SIZE(wm8904_adc_snd_controls));
+       snd_soc_add_controls(codec, wm8904_dac_snd_controls,
+                            ARRAY_SIZE(wm8904_dac_snd_controls));
+       snd_soc_add_controls(codec, wm8904_snd_controls,
+                            ARRAY_SIZE(wm8904_snd_controls));
+
+       snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets,
+                                 ARRAY_SIZE(wm8904_core_dapm_widgets));
+       snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets,
+                                 ARRAY_SIZE(wm8904_adc_dapm_widgets));
+       snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets,
+                                 ARRAY_SIZE(wm8904_dac_dapm_widgets));
+       snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets,
+                                 ARRAY_SIZE(wm8904_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, core_intercon,
+                               ARRAY_SIZE(core_intercon));
+       snd_soc_dapm_add_routes(codec, adc_intercon, ARRAY_SIZE(adc_intercon));
+       snd_soc_dapm_add_routes(codec, dac_intercon, ARRAY_SIZE(dac_intercon));
+       snd_soc_dapm_add_routes(codec, wm8904_intercon,
+                               ARRAY_SIZE(wm8904_intercon));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static struct {
+       int ratio;
+       unsigned int clk_sys_rate;
+} clk_sys_rates[] = {
+       {   64,  0 },
+       {  128,  1 },
+       {  192,  2 },
+       {  256,  3 },
+       {  384,  4 },
+       {  512,  5 },
+       {  786,  6 },
+       { 1024,  7 },
+       { 1408,  8 },
+       { 1536,  9 },
+};
+
+static struct {
+       int rate;
+       int sample_rate;
+} sample_rates[] = {
+       { 8000,  0  },
+       { 11025, 1  },
+       { 12000, 1  },
+       { 16000, 2  },
+       { 22050, 3  },
+       { 24000, 3  },
+       { 32000, 4  },
+       { 44100, 5  },
+       { 48000, 5  },
+};
+
+static struct {
+       int div; /* *10 due to .5s */
+       int bclk_div;
+} bclk_divs[] = {
+       { 10,  0  },
+       { 15,  1  },
+       { 20,  2  },
+       { 30,  3  },
+       { 40,  4  },
+       { 50,  5  },
+       { 55,  6  },
+       { 60,  7  },
+       { 80,  8  },
+       { 100, 9  },
+       { 110, 10 },
+       { 120, 11 },
+       { 160, 12 },
+       { 200, 13 },
+       { 220, 14 },
+       { 240, 16 },
+       { 200, 17 },
+       { 320, 18 },
+       { 440, 19 },
+       { 480, 20 },
+};
+
+
+static int wm8904_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 wm8904_priv *wm8904 = codec->private_data;
+       int ret, i, best, best_val, cur_val;
+       unsigned int aif1 = 0;
+       unsigned int aif2 = 0;
+       unsigned int aif3 = 0;
+       unsigned int clock1 = 0;
+       unsigned int dac_digital1 = 0;
+
+       /* What BCLK do we need? */
+       wm8904->fs = params_rate(params);
+       if (wm8904->tdm_slots) {
+               dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
+                       wm8904->tdm_slots, wm8904->tdm_width);
+               wm8904->bclk = snd_soc_calc_bclk(wm8904->fs,
+                                                wm8904->tdm_width, 2,
+                                                wm8904->tdm_slots);
+       } else {
+               wm8904->bclk = snd_soc_params_to_bclk(params);
+       }
+
+       dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk);
+
+       ret = wm8904_configure_clocking(codec);
+       if (ret != 0)
+               return ret;
+
+       /* Select nearest CLK_SYS_RATE */
+       best = 0;
+       best_val = abs((wm8904->sysclk_rate / clk_sys_rates[0].ratio)
+                      - wm8904->fs);
+       for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+               cur_val = abs((wm8904->sysclk_rate /
+                              clk_sys_rates[i].ratio) - wm8904->fs);;
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+               clk_sys_rates[best].ratio);
+       clock1 |= (clk_sys_rates[best].clk_sys_rate
+                  << WM8904_CLK_SYS_RATE_SHIFT);
+
+       /* SAMPLE_RATE */
+       best = 0;
+       best_val = abs(wm8904->fs - sample_rates[0].rate);
+       for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+               /* Closest match */
+               cur_val = abs(wm8904->fs - sample_rates[i].rate);
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+               sample_rates[best].rate);
+       clock1 |= (sample_rates[best].sample_rate
+                  << WM8904_SAMPLE_RATE_SHIFT);
+
+       /* Enable sloping stopband filter for low sample rates */
+       if (wm8904->fs <= 24000)
+               dac_digital1 |= WM8904_DAC_SB_FILT;
+
+       /* BCLK_DIV */
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               cur_val = ((wm8904->sysclk_rate * 10) / bclk_divs[i].div)
+                       - wm8904->bclk;
+               if (cur_val < 0) /* Table is sorted */
+                       break;
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div;
+       dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+               bclk_divs[best].div, wm8904->bclk);
+       aif2 |= bclk_divs[best].bclk_div;
+
+       /* LRCLK is a simple fraction of BCLK */
+       dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs);
+       aif3 |= wm8904->bclk / wm8904->fs;
+
+       /* Apply the settings */
+       snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
+                           WM8904_DAC_SB_FILT, dac_digital1);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+                           WM8904_AIF_WL_MASK, aif1);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_2,
+                           WM8904_BCLK_DIV_MASK, aif2);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
+                           WM8904_LRCLK_RATE_MASK, aif3);
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_1,
+                           WM8904_SAMPLE_RATE_MASK |
+                           WM8904_CLK_SYS_RATE_MASK, clock1);
+
+       /* Update filters for the new settings */
+       wm8904_set_retune_mobile(codec);
+       wm8904_set_deemph(codec);
+
+       return 0;
+}
+
+
+static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8904_priv *priv = codec->private_data;
+
+       switch (clk_id) {
+       case WM8904_CLK_MCLK:
+               priv->sysclk_src = clk_id;
+               priv->mclk_rate = freq;
+               break;
+
+       case WM8904_CLK_FLL:
+               priv->sysclk_src = clk_id;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       wm8904_configure_clocking(codec);
+
+       return 0;
+}
+
+static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int aif1 = 0;
+       unsigned int aif3 = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               aif3 |= WM8904_LRCLK_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               aif1 |= WM8904_BCLK_DIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif1 |= WM8904_BCLK_DIR;
+               aif3 |= WM8904_LRCLK_DIR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               aif1 |= WM8904_AIF_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif1 |= 0x3;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif1 |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif1 |= 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8904_AIF_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif1 |= WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif1 |= WM8904_AIF_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif1 |= WM8904_AIF_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+                           WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV |
+                           WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1);
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
+                           WM8904_LRCLK_DIR, aif3);
+
+       return 0;
+}
+
+
+static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                              unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int aif1 = 0;
+
+       /* Don't need to validate anything if we're turning off TDM */
+       if (slots == 0)
+               goto out;
+
+       /* Note that we allow configurations we can't handle ourselves - 
+        * for example, we can generate clocks for slots 2 and up even if
+        * we can't use those slots ourselves.
+        */
+       aif1 |= WM8904_AIFADC_TDM | WM8904_AIFDAC_TDM;
+
+       switch (rx_mask) {
+       case 3:
+               break;
+       case 0xc:
+               aif1 |= WM8904_AIFADC_TDM_CHAN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       switch (tx_mask) {
+       case 3:
+               break;
+       case 0xc:
+               aif1 |= WM8904_AIFDAC_TDM_CHAN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+out:
+       wm8904->tdm_width = slot_width;
+       wm8904->tdm_slots = slots / 2;
+
+       snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+                           WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN |
+                           WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1);
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_clk_ref_div;
+       u16 n;
+       u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod, target;
+       unsigned int div;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_clk_ref_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_clk_ref_div++;
+
+               if (div > 8) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 4;
+       while (Fout * div < 90000000) {
+               div++;
+               if (div > 64) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * div;
+       fll_div->fll_outdiv = div - 1;
+
+       pr_debug("Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       target /= fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       /* Now, calculate N.K */
+       Ndiv = target / Fref;
+
+       fll_div->n = Ndiv;
+       Nmod = target % Fref;
+       pr_debug("Nmod=%d\n", Nmod);
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, Fref);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       fll_div->k = K / 10;
+
+       pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+                fll_div->n, fll_div->k,
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_clk_ref_div);
+
+       return 0;
+}
+
+static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8904_priv *wm8904 = codec->private_data;
+       struct _fll_div fll_div;
+       int ret, val;
+       int clock2, fll1;
+
+       /* Any change? */
+       if (source == wm8904->fll_src && Fref == wm8904->fll_fref &&
+           Fout == wm8904->fll_fout)
+               return 0;
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8904->fll_fref = 0;
+               wm8904->fll_fout = 0;
+
+               /* Gate SYSCLK to avoid glitches */
+               snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                                   WM8904_CLK_SYS_ENA, 0);
+
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                                   WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+
+               goto out;
+       }
+
+       /* Validate the FLL ID */
+       switch (source) {
+       case WM8904_FLL_MCLK:
+       case WM8904_FLL_LRCLK:
+       case WM8904_FLL_BCLK:
+               ret = fll_factors(&fll_div, Fref, Fout);
+               if (ret != 0)
+                       return ret;
+               break;
+
+       case WM8904_FLL_FREE_RUNNING:
+               dev_dbg(codec->dev, "Using free running FLL\n");
+               /* Force 12MHz and output/4 for now */
+               Fout = 12000000;
+               Fref = 12000000;
+
+               memset(&fll_div, 0, sizeof(fll_div));
+               fll_div.fll_outdiv = 3;
+               break;
+
+       default:
+               dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+               return -EINVAL;
+       }
+
+       /* Save current state then disable the FLL and SYSCLK to avoid
+        * misclocking */
+       clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
+       fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1);
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_CLK_SYS_ENA, 0);
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+
+       /* Unlock forced oscilator control to switch it on/off */
+       snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
+                           WM8904_USER_KEY, WM8904_USER_KEY);
+
+       if (fll_id == WM8904_FLL_FREE_RUNNING) {
+               val = WM8904_FLL_FRC_NCO;
+       } else {
+               val = 0;
+       }
+
+       snd_soc_update_bits(codec, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO,
+                           val);
+       snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
+                           WM8904_USER_KEY, 0);
+
+       switch (fll_id) {
+       case WM8904_FLL_MCLK:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                                   WM8904_FLL_CLK_REF_SRC_MASK, 0);
+               break;
+
+       case WM8904_FLL_LRCLK:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                                   WM8904_FLL_CLK_REF_SRC_MASK, 1);
+               break;
+
+       case WM8904_FLL_BCLK:
+               snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                                   WM8904_FLL_CLK_REF_SRC_MASK, 2);
+               break;
+       }
+
+       if (fll_div.k)
+               val = WM8904_FLL_FRACN_ENA;
+       else
+               val = 0;
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_FRACN_ENA, val);
+
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_2,
+                           WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK,
+                           (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT));
+
+       snd_soc_write(codec, WM8904_FLL_CONTROL_3, fll_div.k);
+
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK,
+                           fll_div.n << WM8904_FLL_N_SHIFT);
+
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+                           WM8904_FLL_CLK_REF_DIV_MASK,
+                           fll_div.fll_clk_ref_div 
+                           << WM8904_FLL_CLK_REF_DIV_SHIFT);
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8904->fll_fref = Fref;
+       wm8904->fll_fout = Fout;
+       wm8904->fll_src = source;
+
+       /* Enable the FLL if it was previously active */
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_OSC_ENA, fll1);
+       snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+                           WM8904_FLL_ENA, fll1);
+
+out:
+       /* Reenable SYSCLK if it was previously active */
+       snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+                           WM8904_CLK_SYS_ENA, clock2);
+
+       return 0;
+}
+
+static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int val;
+
+       if (mute)
+               val = WM8904_DAC_MUTE;
+       else
+               val = 0;
+
+       snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val);
+
+       return 0;
+}
+
+static int wm8904_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8904_priv *wm8904 = codec->private_data;
+       int ret, i;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID resistance 2*50k */
+               snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                   WM8904_VMID_RES_MASK,
+                                   0x1 << WM8904_VMID_RES_SHIFT);
+
+               /* Normal bias current */
+               snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                   WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+                                                   wm8904->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       /* Sync back cached values if they're
+                        * different from the hardware default.
+                        */
+                       for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) {
+                               if (!wm8904_access[i].writable)
+                                       continue;
+
+                               if (wm8904->reg_cache[i] == wm8904_reg[i])
+                                       continue;
+
+                               snd_soc_write(codec, i, wm8904->reg_cache[i]);
+                       }
+
+                       /* Enable bias */
+                       snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                           WM8904_BIAS_ENA, WM8904_BIAS_ENA);
+
+                       /* Enable VMID, VMID buffering, 2*5k resistance */
+                       snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                           WM8904_VMID_ENA |
+                                           WM8904_VMID_RES_MASK,
+                                           WM8904_VMID_ENA |
+                                           0x3 << WM8904_VMID_RES_SHIFT);
+
+                       /* Let VMID ramp */
+                       msleep(1);
+               }
+
+               /* Maintain VMID with 2*250k */
+               snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                   WM8904_VMID_RES_MASK,
+                                   0x2 << WM8904_VMID_RES_SHIFT);
+
+               /* Bias current *0.5 */
+               snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                   WM8904_ISEL_MASK, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Turn off VMID */
+               snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+                                   WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0);
+
+               /* Stop bias generation */
+               snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+                                   WM8904_BIAS_ENA, 0);
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies),
+                                      wm8904->supplies);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8904_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8904_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8904_dai_ops = {
+       .set_sysclk = wm8904_set_sysclk,
+       .set_fmt = wm8904_set_fmt,
+       .set_tdm_slot = wm8904_set_tdm_slot,
+       .set_pll = wm8904_set_fll,
+       .hw_params = wm8904_hw_params,
+       .digital_mute = wm8904_digital_mute,
+};
+
+struct snd_soc_dai wm8904_dai = {
+       .name = "WM8904",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8904_RATES,
+               .formats = WM8904_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8904_RATES,
+               .formats = WM8904_FORMATS,
+       },
+       .ops = &wm8904_dai_ops,
+       .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8904_dai);
+
+#ifdef CONFIG_PM
+static int wm8904_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm8904_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+       wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define wm8904_suspend NULL
+#define wm8904_resume NULL
+#endif
+
+static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
+{
+       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       struct snd_kcontrol_new control =
+               SOC_ENUM_EXT("EQ Mode",
+                            wm8904->retune_mobile_enum,
+                            wm8904_get_retune_mobile_enum,
+                            wm8904_put_retune_mobile_enum);
+       int ret, i, j;
+       const char **t;
+
+       /* We need an array of texts for the enum API but the number
+        * of texts is likely to be less than the number of
+        * configurations due to the sample rate dependency of the
+        * configurations. */
+       wm8904->num_retune_mobile_texts = 0;
+       wm8904->retune_mobile_texts = NULL;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               for (j = 0; j < wm8904->num_retune_mobile_texts; j++) {
+                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                                  wm8904->retune_mobile_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != wm8904->num_retune_mobile_texts)
+                       continue;
+
+               /* Expand the array... */
+               t = krealloc(wm8904->retune_mobile_texts,
+                            sizeof(char *) * 
+                            (wm8904->num_retune_mobile_texts + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* ...store the new entry... */
+               t[wm8904->num_retune_mobile_texts] = 
+                       pdata->retune_mobile_cfgs[i].name;
+
+               /* ...and remember the new version. */
+               wm8904->num_retune_mobile_texts++;
+               wm8904->retune_mobile_texts = t;
+       }
+
+       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+               wm8904->num_retune_mobile_texts);
+
+       wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
+       wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
+
+       ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+       if (ret != 0)
+               dev_err(wm8904->codec.dev,
+                       "Failed to add ReTune Mobile control: %d\n", ret);
+}
+
+static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
+{
+       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_pdata *pdata = wm8904->pdata;
+       int ret, i;
+
+       if (!pdata) {
+               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+                                    ARRAY_SIZE(wm8904_eq_controls));
+               return;
+       }
+
+       dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+
+       if (pdata->num_drc_cfgs) {
+               struct snd_kcontrol_new control =
+                       SOC_ENUM_EXT("DRC Mode", wm8904->drc_enum,
+                                    wm8904_get_drc_enum, wm8904_put_drc_enum);
+
+               /* We need an array of texts for the enum API */
+               wm8904->drc_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_drc_cfgs, GFP_KERNEL);
+               if (!wm8904->drc_texts) {
+                       dev_err(wm8904->codec.dev,
+                               "Failed to allocate %d DRC config texts\n",
+                               pdata->num_drc_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_drc_cfgs; i++)
+                       wm8904->drc_texts[i] = pdata->drc_cfgs[i].name;
+
+               wm8904->drc_enum.max = pdata->num_drc_cfgs;
+               wm8904->drc_enum.texts = wm8904->drc_texts;
+
+               ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+               if (ret != 0)
+                       dev_err(wm8904->codec.dev,
+                               "Failed to add DRC mode control: %d\n", ret);
+
+               wm8904_set_drc(codec);
+       }
+
+       dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
+               pdata->num_retune_mobile_cfgs);
+
+       if (pdata->num_retune_mobile_cfgs)
+               wm8904_handle_retune_mobile_pdata(wm8904);
+       else
+               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+                                    ARRAY_SIZE(wm8904_eq_controls));
+}
+
+static int wm8904_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (wm8904_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = wm8904_codec;
+       codec = wm8904_codec;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+               goto pcm_err;
+       }
+
+       wm8904_handle_pdata(codec->private_data);
+
+       wm8904_add_widgets(codec);
+
+       return ret;
+
+pcm_err:
+       return ret;
+}
+
+static int wm8904_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8904 = {
+       .probe =        wm8904_probe,
+       .remove =       wm8904_remove,
+       .suspend =      wm8904_suspend,
+       .resume =       wm8904_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
+
+static int wm8904_register(struct wm8904_priv *wm8904,
+                          enum snd_soc_control_type control)
+{
+       int ret;
+       struct snd_soc_codec *codec = &wm8904->codec;
+       int i;
+
+       if (wm8904_codec) {
+               dev_err(codec->dev, "Another WM8904 is registered\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = wm8904;
+       codec->name = "WM8904";
+       codec->owner = THIS_MODULE;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8904_set_bias_level;
+       codec->dai = &wm8904_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = WM8904_MAX_REGISTER;
+       codec->reg_cache = &wm8904->reg_cache;
+       codec->volatile_register = wm8904_volatile_register;
+
+       memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
+               wm8904->supplies[i].supply = wm8904_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies),
+                                wm8904->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+                                   wm8904->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read ID register\n");
+               goto err_enable;
+       }
+       if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) {
+               dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8904_REVISION);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_enable;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       ret = wm8904_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err_enable;
+       }
+
+       wm8904_dai.dev = codec->dev;
+
+       /* Change some default settings - latch VU and enable ZC */
+       wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
+       wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
+       wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
+       wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
+               WM8904_HPOUTLZC;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
+               WM8904_HPOUTRZC;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
+               WM8904_LINEOUTLZC;
+       wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
+               WM8904_LINEOUTRZC;
+       wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
+
+       /* Set Class W by default - this will be managed by the Class
+        * G widget at runtime where bypass paths are available.
+        */
+       wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
+
+       /* Use normal bias source */
+       wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
+
+       wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Bias level configuration will have done an extra enable */
+       regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+
+       wm8904_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm8904_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+err:
+       kfree(wm8904);
+       return ret;
+}
+
+static void wm8904_unregister(struct wm8904_priv *wm8904)
+{
+       wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+       snd_soc_unregister_dai(&wm8904_dai);
+       snd_soc_unregister_codec(&wm8904->codec);
+       kfree(wm8904);
+       wm8904_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8904_priv *wm8904;
+       struct snd_soc_codec *codec;
+
+       wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
+       if (wm8904 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8904->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+
+       i2c_set_clientdata(i2c, wm8904);
+       codec->control_data = i2c;
+       wm8904->pdata = i2c->dev.platform_data;
+
+       codec->dev = &i2c->dev;
+
+       return wm8904_register(wm8904, SND_SOC_I2C);
+}
+
+static __devexit int wm8904_i2c_remove(struct i2c_client *client)
+{
+       struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
+       wm8904_unregister(wm8904);
+       return 0;
+}
+
+static const struct i2c_device_id wm8904_i2c_id[] = {
+       { "wm8904", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
+
+static struct i2c_driver wm8904_i2c_driver = {
+       .driver = {
+               .name = "WM8904",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8904_i2c_probe,
+       .remove =   __devexit_p(wm8904_i2c_remove),
+       .id_table = wm8904_i2c_id,
+};
+#endif
+
+static int __init wm8904_modinit(void)
+{
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8904_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8904_modinit);
+
+static void __exit wm8904_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8904_i2c_driver);
+#endif
+}
+module_exit(wm8904_exit);
+
+MODULE_DESCRIPTION("ASoC WM8904 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
new file mode 100644 (file)
index 0000000..b68886d
--- /dev/null
@@ -0,0 +1,1681 @@
+/*
+ * wm8904.h  --  WM8904 ASoC driver
+ *
+ * Copyright 2009 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * 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 _WM8904_H
+#define _WM8904_H
+
+#define WM8904_CLK_MCLK 1
+#define WM8904_CLK_FLL  2
+
+#define WM8904_FLL_MCLK          1
+#define WM8904_FLL_BCLK          2
+#define WM8904_FLL_LRCLK         3
+#define WM8904_FLL_FREE_RUNNING  4
+
+extern struct snd_soc_dai wm8904_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8904;
+
+/*
+ * Register values.
+ */
+#define WM8904_SW_RESET_AND_ID                  0x00
+#define WM8904_REVISION                                0x01
+#define WM8904_BIAS_CONTROL_0                   0x04
+#define WM8904_VMID_CONTROL_0                   0x05
+#define WM8904_MIC_BIAS_CONTROL_0               0x06
+#define WM8904_MIC_BIAS_CONTROL_1               0x07
+#define WM8904_ANALOGUE_DAC_0                   0x08
+#define WM8904_MIC_FILTER_CONTROL               0x09
+#define WM8904_ANALOGUE_ADC_0                   0x0A
+#define WM8904_POWER_MANAGEMENT_0               0x0C
+#define WM8904_POWER_MANAGEMENT_2               0x0E
+#define WM8904_POWER_MANAGEMENT_3               0x0F
+#define WM8904_POWER_MANAGEMENT_6               0x12
+#define WM8904_CLOCK_RATES_0                    0x14
+#define WM8904_CLOCK_RATES_1                    0x15
+#define WM8904_CLOCK_RATES_2                    0x16
+#define WM8904_AUDIO_INTERFACE_0                0x18
+#define WM8904_AUDIO_INTERFACE_1                0x19
+#define WM8904_AUDIO_INTERFACE_2                0x1A
+#define WM8904_AUDIO_INTERFACE_3                0x1B
+#define WM8904_DAC_DIGITAL_VOLUME_LEFT          0x1E
+#define WM8904_DAC_DIGITAL_VOLUME_RIGHT         0x1F
+#define WM8904_DAC_DIGITAL_0                    0x20
+#define WM8904_DAC_DIGITAL_1                    0x21
+#define WM8904_ADC_DIGITAL_VOLUME_LEFT          0x24
+#define WM8904_ADC_DIGITAL_VOLUME_RIGHT         0x25
+#define WM8904_ADC_DIGITAL_0                    0x26
+#define WM8904_DIGITAL_MICROPHONE_0             0x27
+#define WM8904_DRC_0                            0x28
+#define WM8904_DRC_1                            0x29
+#define WM8904_DRC_2                            0x2A
+#define WM8904_DRC_3                            0x2B
+#define WM8904_ANALOGUE_LEFT_INPUT_0            0x2C
+#define WM8904_ANALOGUE_RIGHT_INPUT_0           0x2D
+#define WM8904_ANALOGUE_LEFT_INPUT_1            0x2E
+#define WM8904_ANALOGUE_RIGHT_INPUT_1           0x2F
+#define WM8904_ANALOGUE_OUT1_LEFT               0x39
+#define WM8904_ANALOGUE_OUT1_RIGHT              0x3A
+#define WM8904_ANALOGUE_OUT2_LEFT               0x3B
+#define WM8904_ANALOGUE_OUT2_RIGHT              0x3C
+#define WM8904_ANALOGUE_OUT12_ZC                0x3D
+#define WM8904_DC_SERVO_0                       0x43
+#define WM8904_DC_SERVO_1                       0x44
+#define WM8904_DC_SERVO_2                       0x45
+#define WM8904_DC_SERVO_4                       0x47
+#define WM8904_DC_SERVO_5                       0x48
+#define WM8904_DC_SERVO_6                       0x49
+#define WM8904_DC_SERVO_7                       0x4A
+#define WM8904_DC_SERVO_8                       0x4B
+#define WM8904_DC_SERVO_9                       0x4C
+#define WM8904_DC_SERVO_READBACK_0              0x4D
+#define WM8904_ANALOGUE_HP_0                    0x5A
+#define WM8904_ANALOGUE_LINEOUT_0               0x5E
+#define WM8904_CHARGE_PUMP_0                    0x62
+#define WM8904_CLASS_W_0                        0x68
+#define WM8904_WRITE_SEQUENCER_0                0x6C
+#define WM8904_WRITE_SEQUENCER_1                0x6D
+#define WM8904_WRITE_SEQUENCER_2                0x6E
+#define WM8904_WRITE_SEQUENCER_3                0x6F
+#define WM8904_WRITE_SEQUENCER_4                0x70
+#define WM8904_FLL_CONTROL_1                    0x74
+#define WM8904_FLL_CONTROL_2                    0x75
+#define WM8904_FLL_CONTROL_3                    0x76
+#define WM8904_FLL_CONTROL_4                    0x77
+#define WM8904_FLL_CONTROL_5                    0x78
+#define WM8904_GPIO_CONTROL_1                   0x79
+#define WM8904_GPIO_CONTROL_2                   0x7A
+#define WM8904_GPIO_CONTROL_3                   0x7B
+#define WM8904_GPIO_CONTROL_4                   0x7C
+#define WM8904_DIGITAL_PULLS                    0x7E
+#define WM8904_INTERRUPT_STATUS                 0x7F
+#define WM8904_INTERRUPT_STATUS_MASK            0x80
+#define WM8904_INTERRUPT_POLARITY               0x81
+#define WM8904_INTERRUPT_DEBOUNCE               0x82
+#define WM8904_EQ1                              0x86
+#define WM8904_EQ2                              0x87
+#define WM8904_EQ3                              0x88
+#define WM8904_EQ4                              0x89
+#define WM8904_EQ5                              0x8A
+#define WM8904_EQ6                              0x8B
+#define WM8904_EQ7                              0x8C
+#define WM8904_EQ8                              0x8D
+#define WM8904_EQ9                              0x8E
+#define WM8904_EQ10                             0x8F
+#define WM8904_EQ11                             0x90
+#define WM8904_EQ12                             0x91
+#define WM8904_EQ13                             0x92
+#define WM8904_EQ14                             0x93
+#define WM8904_EQ15                             0x94
+#define WM8904_EQ16                             0x95
+#define WM8904_EQ17                             0x96
+#define WM8904_EQ18                             0x97
+#define WM8904_EQ19                             0x98
+#define WM8904_EQ20                             0x99
+#define WM8904_EQ21                             0x9A
+#define WM8904_EQ22                             0x9B
+#define WM8904_EQ23                             0x9C
+#define WM8904_EQ24                             0x9D
+#define WM8904_CONTROL_INTERFACE_TEST_1         0xA1
+#define WM8904_ANALOGUE_OUTPUT_BIAS_0           0xCC
+#define WM8904_FLL_NCO_TEST_0                   0xF7
+#define WM8904_FLL_NCO_TEST_1                   0xF8
+
+#define WM8904_REGISTER_COUNT                   101
+#define WM8904_MAX_REGISTER                     0xF8
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - SW Reset and ID
+ */
+#define WM8904_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8904_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8904_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Revision
+ */
+#define WM8904_REVISION_MASK                   0x000F  /* REVISION - [3:0] */
+#define WM8904_REVISION_SHIFT                       0  /* REVISION - [3:0] */
+#define WM8904_REVISION_WIDTH                      16  /* REVISION - [3:0] */
+
+/*
+ * R4 (0x04) - Bias Control 0
+ */
+#define WM8904_POBCTRL                          0x0010  /* POBCTRL */
+#define WM8904_POBCTRL_MASK                     0x0010  /* POBCTRL */
+#define WM8904_POBCTRL_SHIFT                         4  /* POBCTRL */
+#define WM8904_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8904_ISEL_MASK                        0x000C  /* ISEL - [3:2] */
+#define WM8904_ISEL_SHIFT                            2  /* ISEL - [3:2] */
+#define WM8904_ISEL_WIDTH                            2  /* ISEL - [3:2] */
+#define WM8904_STARTUP_BIAS_ENA                 0x0002  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_MASK            0x0002  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_SHIFT                1  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8904_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R5 (0x05) - VMID Control 0
+ */
+#define WM8904_VMID_BUF_ENA                     0x0040  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_MASK                0x0040  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_SHIFT                    6  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8904_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM8904_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM8904_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM8904_VMID_ENA                         0x0001  /* VMID_ENA */
+#define WM8904_VMID_ENA_MASK                    0x0001  /* VMID_ENA */
+#define WM8904_VMID_ENA_SHIFT                        0  /* VMID_ENA */
+#define WM8904_VMID_ENA_WIDTH                        1  /* VMID_ENA */
+
+/*
+ * R6 (0x06) - Mic Bias Control 0
+ */
+#define WM8904_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
+#define WM8904_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
+#define WM8904_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8904_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICDET_ENA                       0x0002  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_MASK                  0x0002  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_SHIFT                      1  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8904_MICBIAS_ENA                      0x0001  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_MASK                 0x0001  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_SHIFT                     0  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R7 (0x07) - Mic Bias Control 1
+ */
+#define WM8904_MIC_DET_FILTER_ENA               0x8000  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_MASK          0x8000  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_SHIFT             15  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_WIDTH              1  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA             0x4000  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_MASK        0x4000  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_SHIFT           14  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_WIDTH            1  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MICBIAS_SEL_MASK                 0x0007  /* MICBIAS_SEL - [2:0] */
+#define WM8904_MICBIAS_SEL_SHIFT                     0  /* MICBIAS_SEL - [2:0] */
+#define WM8904_MICBIAS_SEL_WIDTH                     3  /* MICBIAS_SEL - [2:0] */
+
+/*
+ * R8 (0x08) - Analogue DAC 0
+ */
+#define WM8904_DAC_BIAS_SEL_MASK                0x0018  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_BIAS_SEL_SHIFT                    3  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_BIAS_SEL_WIDTH                    2  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_VMID_BIAS_SEL_MASK           0x0006  /* DAC_VMID_BIAS_SEL - [2:1] */
+#define WM8904_DAC_VMID_BIAS_SEL_SHIFT               1  /* DAC_VMID_BIAS_SEL - [2:1] */
+#define WM8904_DAC_VMID_BIAS_SEL_WIDTH               2  /* DAC_VMID_BIAS_SEL - [2:1] */
+
+/*
+ * R9 (0x09) - mic Filter Control
+ */
+#define WM8904_MIC_DET_SET_THRESHOLD_MASK       0xF000  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_SET_THRESHOLD_SHIFT          12  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_SET_THRESHOLD_WIDTH           4  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_MASK     0x0F00  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_SHIFT         8  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_WIDTH         4  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_MASK     0x00F0  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_SHIFT         4  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_WIDTH         4  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_MASK   0x000F  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_SHIFT       0  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_WIDTH       4  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+
+/*
+ * R10 (0x0A) - Analogue ADC 0
+ */
+#define WM8904_ADC_OSR128                       0x0001  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_MASK                  0x0001  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_SHIFT                      0  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+
+/*
+ * R12 (0x0C) - Power Management 0
+ */
+#define WM8904_INL_ENA                          0x0002  /* INL_ENA */
+#define WM8904_INL_ENA_MASK                     0x0002  /* INL_ENA */
+#define WM8904_INL_ENA_SHIFT                         1  /* INL_ENA */
+#define WM8904_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8904_INR_ENA                          0x0001  /* INR_ENA */
+#define WM8904_INR_ENA_MASK                     0x0001  /* INR_ENA */
+#define WM8904_INR_ENA_SHIFT                         0  /* INR_ENA */
+#define WM8904_INR_ENA_WIDTH                         1  /* INR_ENA */
+
+/*
+ * R14 (0x0E) - Power Management 2
+ */
+#define WM8904_HPL_PGA_ENA                      0x0002  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_MASK                 0x0002  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_SHIFT                     1  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_WIDTH                     1  /* HPL_PGA_ENA */
+#define WM8904_HPR_PGA_ENA                      0x0001  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_MASK                 0x0001  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_SHIFT                     0  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_WIDTH                     1  /* HPR_PGA_ENA */
+
+/*
+ * R15 (0x0F) - Power Management 3
+ */
+#define WM8904_LINEOUTL_PGA_ENA                 0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_MASK            0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_SHIFT                1  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_WIDTH                1  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA                 0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_MASK            0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_SHIFT                0  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_WIDTH                1  /* LINEOUTR_PGA_ENA */
+
+/*
+ * R18 (0x12) - Power Management 6
+ */
+#define WM8904_DACL_ENA                         0x0008  /* DACL_ENA */
+#define WM8904_DACL_ENA_MASK                    0x0008  /* DACL_ENA */
+#define WM8904_DACL_ENA_SHIFT                        3  /* DACL_ENA */
+#define WM8904_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8904_DACR_ENA                         0x0004  /* DACR_ENA */
+#define WM8904_DACR_ENA_MASK                    0x0004  /* DACR_ENA */
+#define WM8904_DACR_ENA_SHIFT                        2  /* DACR_ENA */
+#define WM8904_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8904_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8904_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R20 (0x14) - Clock Rates 0
+ */
+#define WM8904_TOCLK_RATE_DIV16                 0x4000  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_MASK            0x4000  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_SHIFT               14  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_WIDTH                1  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_X4                    0x2000  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_MASK               0x2000  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_SHIFT                  13  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_WIDTH                   1  /* TOCLK_RATE_X4 */
+#define WM8904_SR_MODE                          0x1000  /* SR_MODE */
+#define WM8904_SR_MODE_MASK                     0x1000  /* SR_MODE */
+#define WM8904_SR_MODE_SHIFT                        12  /* SR_MODE */
+#define WM8904_SR_MODE_WIDTH                         1  /* SR_MODE */
+#define WM8904_MCLK_DIV                         0x0001  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_MASK                    0x0001  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_SHIFT                        0  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_WIDTH                        1  /* MCLK_DIV */
+
+/*
+ * R21 (0x15) - Clock Rates 1
+ */
+#define WM8904_CLK_SYS_RATE_MASK                0x3C00  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_CLK_SYS_RATE_SHIFT                   10  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8904_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8904_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R22 (0x16) - Clock Rates 2
+ */
+#define WM8904_MCLK_INV                         0x8000  /* MCLK_INV */
+#define WM8904_MCLK_INV_MASK                    0x8000  /* MCLK_INV */
+#define WM8904_MCLK_INV_SHIFT                       15  /* MCLK_INV */
+#define WM8904_MCLK_INV_WIDTH                        1  /* MCLK_INV */
+#define WM8904_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_MASK                  0x4000  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_SHIFT                     14  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_WIDTH                      1  /* SYSCLK_SRC */
+#define WM8904_TOCLK_RATE                       0x1000  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_MASK                  0x1000  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_SHIFT                     12  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM8904_OPCLK_ENA                        0x0008  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_MASK                   0x0008  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_SHIFT                       3  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8904_CLK_SYS_ENA                      0x0004  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_MASK                 0x0004  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_SHIFT                     2  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8904_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8904_TOCLK_ENA                        0x0001  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_MASK                   0x0001  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_SHIFT                       0  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Audio Interface 0
+ */
+#define WM8904_DACL_DATINV                      0x1000  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_MASK                 0x1000  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_SHIFT                    12  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8904_DACR_DATINV                      0x0800  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_MASK                 0x0800  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_SHIFT                    11  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+#define WM8904_DAC_BOOST_MASK                   0x0600  /* DAC_BOOST - [10:9] */
+#define WM8904_DAC_BOOST_SHIFT                       9  /* DAC_BOOST - [10:9] */
+#define WM8904_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [10:9] */
+#define WM8904_LOOPBACK                         0x0100  /* LOOPBACK */
+#define WM8904_LOOPBACK_MASK                    0x0100  /* LOOPBACK */
+#define WM8904_LOOPBACK_SHIFT                        8  /* LOOPBACK */
+#define WM8904_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+#define WM8904_AIFADCL_SRC                      0x0080  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_MASK                 0x0080  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_SHIFT                     7  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8904_AIFADCR_SRC                      0x0040  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_MASK                 0x0040  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_SHIFT                     6  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8904_AIFDACL_SRC                      0x0020  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_MASK                 0x0020  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_SHIFT                     5  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8904_AIFDACR_SRC                      0x0010  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_MASK                 0x0010  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_SHIFT                     4  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8904_ADC_COMP                         0x0008  /* ADC_COMP */
+#define WM8904_ADC_COMP_MASK                    0x0008  /* ADC_COMP */
+#define WM8904_ADC_COMP_SHIFT                        3  /* ADC_COMP */
+#define WM8904_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8904_ADC_COMPMODE                     0x0004  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_MASK                0x0004  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_SHIFT                    2  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8904_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM8904_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM8904_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM8904_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8904_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R25 (0x19) - Audio Interface 1
+ */
+#define WM8904_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFADC_TDM                       0x0800  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_MASK                  0x0800  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_SHIFT                     11  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_CHAN                  0x0400  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_MASK             0x0400  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_SHIFT                10  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8904_AIF_TRIS                         0x0100  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_MASK                    0x0100  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_SHIFT                        8  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM8904_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8904_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8904_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8904_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM8904_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM8904_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM8904_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM8904_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM8904_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R26 (0x1A) - Audio Interface 2
+ */
+#define WM8904_OPCLK_DIV_MASK                   0x0F00  /* OPCLK_DIV - [11:8] */
+#define WM8904_OPCLK_DIV_SHIFT                       8  /* OPCLK_DIV - [11:8] */
+#define WM8904_OPCLK_DIV_WIDTH                       4  /* OPCLK_DIV - [11:8] */
+#define WM8904_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM8904_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM8904_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R27 (0x1B) - Audio Interface 3
+ */
+#define WM8904_LRCLK_DIR                        0x0800  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_MASK                   0x0800  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_SHIFT                      11  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8904_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8904_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8904_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R30 (0x1E) - DAC Digital Volume Left
+ */
+#define WM8904_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8904_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8904_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8904_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8904_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital Volume Right
+ */
+#define WM8904_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8904_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8904_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8904_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8904_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R32 (0x20) - DAC Digital 0
+ */
+#define WM8904_ADCL_DAC_SVOL_MASK               0x0F00  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCL_DAC_SVOL_SHIFT                   8  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8904_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8904_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R33 (0x21) - DAC Digital 1
+ */
+#define WM8904_DAC_MONO                         0x1000  /* DAC_MONO */
+#define WM8904_DAC_MONO_MASK                    0x1000  /* DAC_MONO */
+#define WM8904_DAC_MONO_SHIFT                       12  /* DAC_MONO */
+#define WM8904_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8904_DAC_SB_FILT                      0x0800  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_MASK                 0x0800  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_SHIFT                    11  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8904_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8904_DAC_UNMUTE_RAMP                  0x0200  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_MASK             0x0200  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_SHIFT                 9  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_OSR128                       0x0040  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_MASK                  0x0040  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_SHIFT                      6  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+#define WM8904_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8904_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8904_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8904_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R36 (0x24) - ADC Digital Volume Left
+ */
+#define WM8904_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8904_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8904_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8904_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8904_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R37 (0x25) - ADC Digital Volume Right
+ */
+#define WM8904_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8904_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8904_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8904_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8904_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R38 (0x26) - ADC Digital 0
+ */
+#define WM8904_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF                          0x0010  /* ADC_HPF */
+#define WM8904_ADC_HPF_MASK                     0x0010  /* ADC_HPF */
+#define WM8904_ADC_HPF_SHIFT                         4  /* ADC_HPF */
+#define WM8904_ADC_HPF_WIDTH                         1  /* ADC_HPF */
+#define WM8904_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8904_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R39 (0x27) - Digital Microphone 0
+ */
+#define WM8904_DMIC_ENA                         0x1000  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_MASK                    0x1000  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_SHIFT                       12  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_WIDTH                        1  /* DMIC_ENA */
+#define WM8904_DMIC_SRC                         0x0800  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_MASK                    0x0800  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_SHIFT                       11  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_WIDTH                        1  /* DMIC_SRC */
+
+/*
+ * R40 (0x28) - DRC 0
+ */
+#define WM8904_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8904_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8904_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8904_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8904_DRC_DAC_PATH                     0x4000  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_MASK                0x4000  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_SHIFT                   14  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_WIDTH                    1  /* DRC_DAC_PATH */
+#define WM8904_DRC_GS_HYST_LVL_MASK             0x1800  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_GS_HYST_LVL_SHIFT                11  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_GS_HYST_LVL_WIDTH                 2  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_FF_DELAY                     0x0020  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_MASK                0x0020  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_SHIFT                    5  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8904_DRC_GS_ENA                       0x0008  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_MASK                  0x0008  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_SHIFT                      3  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_WIDTH                      1  /* DRC_GS_ENA */
+#define WM8904_DRC_QR                           0x0004  /* DRC_QR */
+#define WM8904_DRC_QR_MASK                      0x0004  /* DRC_QR */
+#define WM8904_DRC_QR_SHIFT                          2  /* DRC_QR */
+#define WM8904_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM8904_DRC_ANTICLIP                     0x0002  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_MASK                0x0002  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_SHIFT                    1  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM8904_DRC_GS_HYST                      0x0001  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_MASK                 0x0001  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_SHIFT                     0  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_WIDTH                     1  /* DRC_GS_HYST */
+
+/*
+ * R41 (0x29) - DRC 1
+ */
+#define WM8904_DRC_ATK_MASK                     0xF000  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_ATK_SHIFT                        12  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_ATK_WIDTH                         4  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_DCY_MASK                     0x0F00  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_DCY_SHIFT                         8  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_DCY_WIDTH                         4  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_QR_THR_MASK                  0x00C0  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_THR_SHIFT                      6  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_DCY_MASK                  0x0030  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_QR_DCY_SHIFT                      4  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8904_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8904_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R42 (0x2A) - DRC 2
+ */
+#define WM8904_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM8904_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM8904_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R43 (0x2B) - DRC 3
+ */
+#define WM8904_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM8904_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM8904_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R44 (0x2C) - Analogue Left Input 0
+ */
+#define WM8904_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8904_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8904_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8904_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8904_LIN_VOL_MASK                     0x001F  /* LIN_VOL - [4:0] */
+#define WM8904_LIN_VOL_SHIFT                         0  /* LIN_VOL - [4:0] */
+#define WM8904_LIN_VOL_WIDTH                         5  /* LIN_VOL - [4:0] */
+
+/*
+ * R45 (0x2D) - Analogue Right Input 0
+ */
+#define WM8904_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8904_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8904_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8904_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8904_RIN_VOL_MASK                     0x001F  /* RIN_VOL - [4:0] */
+#define WM8904_RIN_VOL_SHIFT                         0  /* RIN_VOL - [4:0] */
+#define WM8904_RIN_VOL_WIDTH                         5  /* RIN_VOL - [4:0] */
+
+/*
+ * R46 (0x2E) - Analogue Left Input 1
+ */
+#define WM8904_INL_CM_ENA                       0x0040  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_MASK                  0x0040  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_SHIFT                      6  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_WIDTH                      1  /* INL_CM_ENA */
+#define WM8904_L_IP_SEL_N_MASK                  0x0030  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_N_SHIFT                      4  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_N_WIDTH                      2  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_P_MASK                  0x000C  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_IP_SEL_P_SHIFT                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_IP_SEL_P_WIDTH                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_MODE_MASK                      0x0003  /* L_MODE - [1:0] */
+#define WM8904_L_MODE_SHIFT                          0  /* L_MODE - [1:0] */
+#define WM8904_L_MODE_WIDTH                          2  /* L_MODE - [1:0] */
+
+/*
+ * R47 (0x2F) - Analogue Right Input 1
+ */
+#define WM8904_INR_CM_ENA                       0x0040  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_MASK                  0x0040  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_SHIFT                      6  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_WIDTH                      1  /* INR_CM_ENA */
+#define WM8904_R_IP_SEL_N_MASK                  0x0030  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_N_SHIFT                      4  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_N_WIDTH                      2  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_P_MASK                  0x000C  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_IP_SEL_P_SHIFT                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_IP_SEL_P_WIDTH                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_MODE_MASK                      0x0003  /* R_MODE - [1:0] */
+#define WM8904_R_MODE_SHIFT                          0  /* R_MODE - [1:0] */
+#define WM8904_R_MODE_WIDTH                          2  /* R_MODE - [1:0] */
+
+/*
+ * R57 (0x39) - Analogue OUT1 Left
+ */
+#define WM8904_HPOUTL_MUTE                      0x0100  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_MASK                 0x0100  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_SHIFT                     8  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_WIDTH                     1  /* HPOUTL_MUTE */
+#define WM8904_HPOUT_VU                         0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_MASK                    0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_SHIFT                        7  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8904_HPOUTLZC                         0x0040  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_MASK                    0x0040  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_SHIFT                        6  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_WIDTH                        1  /* HPOUTLZC */
+#define WM8904_HPOUTL_VOL_MASK                  0x003F  /* HPOUTL_VOL - [5:0] */
+#define WM8904_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [5:0] */
+#define WM8904_HPOUTL_VOL_WIDTH                      6  /* HPOUTL_VOL - [5:0] */
+
+/*
+ * R58 (0x3A) - Analogue OUT1 Right
+ */
+#define WM8904_HPOUTR_MUTE                      0x0100  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_MASK                 0x0100  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_SHIFT                     8  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_WIDTH                     1  /* HPOUTR_MUTE */
+#define WM8904_HPOUT_VU                         0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_MASK                    0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_SHIFT                        7  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8904_HPOUTRZC                         0x0040  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_MASK                    0x0040  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_SHIFT                        6  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_WIDTH                        1  /* HPOUTRZC */
+#define WM8904_HPOUTR_VOL_MASK                  0x003F  /* HPOUTR_VOL - [5:0] */
+#define WM8904_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [5:0] */
+#define WM8904_HPOUTR_VOL_WIDTH                      6  /* HPOUTR_VOL - [5:0] */
+
+/*
+ * R59 (0x3B) - Analogue OUT2 Left
+ */
+#define WM8904_LINEOUTL_MUTE                    0x0100  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_MASK               0x0100  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_SHIFT                   8  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_WIDTH                   1  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUT_VU                       0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_MASK                  0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_SHIFT                      7  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_WIDTH                      1  /* LINEOUT_VU */
+#define WM8904_LINEOUTLZC                       0x0040  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_MASK                  0x0040  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_SHIFT                      6  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_WIDTH                      1  /* LINEOUTLZC */
+#define WM8904_LINEOUTL_VOL_MASK                0x003F  /* LINEOUTL_VOL - [5:0] */
+#define WM8904_LINEOUTL_VOL_SHIFT                    0  /* LINEOUTL_VOL - [5:0] */
+#define WM8904_LINEOUTL_VOL_WIDTH                    6  /* LINEOUTL_VOL - [5:0] */
+
+/*
+ * R60 (0x3C) - Analogue OUT2 Right
+ */
+#define WM8904_LINEOUTR_MUTE                    0x0100  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_MASK               0x0100  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_SHIFT                   8  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_WIDTH                   1  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUT_VU                       0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_MASK                  0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_SHIFT                      7  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_WIDTH                      1  /* LINEOUT_VU */
+#define WM8904_LINEOUTRZC                       0x0040  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_MASK                  0x0040  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_SHIFT                      6  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_WIDTH                      1  /* LINEOUTRZC */
+#define WM8904_LINEOUTR_VOL_MASK                0x003F  /* LINEOUTR_VOL - [5:0] */
+#define WM8904_LINEOUTR_VOL_SHIFT                    0  /* LINEOUTR_VOL - [5:0] */
+#define WM8904_LINEOUTR_VOL_WIDTH                    6  /* LINEOUTR_VOL - [5:0] */
+
+/*
+ * R61 (0x3D) - Analogue OUT12 ZC
+ */
+#define WM8904_HPL_BYP_ENA                      0x0008  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_MASK                 0x0008  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_SHIFT                     3  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_WIDTH                     1  /* HPL_BYP_ENA */
+#define WM8904_HPR_BYP_ENA                      0x0004  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_MASK                 0x0004  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_SHIFT                     2  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_WIDTH                     1  /* HPR_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA                 0x0002  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_MASK            0x0002  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_SHIFT                1  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_WIDTH                1  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA                 0x0001  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_MASK            0x0001  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_SHIFT                0  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_WIDTH                1  /* LINEOUTR_BYP_ENA */
+
+/*
+ * R67 (0x43) - DC Servo 0
+ */
+#define WM8904_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R68 (0x44) - DC Servo 1
+ */
+#define WM8904_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R69 (0x45) - DC Servo 2
+ */
+#define WM8904_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8904_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8904_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R71 (0x47) - DC Servo 4
+ */
+#define WM8904_DCS_SERIES_NO_23_MASK            0x007F  /* DCS_SERIES_NO_23 - [6:0] */
+#define WM8904_DCS_SERIES_NO_23_SHIFT                0  /* DCS_SERIES_NO_23 - [6:0] */
+#define WM8904_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [6:0] */
+
+/*
+ * R72 (0x48) - DC Servo 5
+ */
+#define WM8904_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8904_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8904_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R73 (0x49) - DC Servo 6
+ */
+#define WM8904_DCS_DAC_WR_VAL_3_MASK            0x00FF  /* DCS_DAC_WR_VAL_3 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_3_SHIFT                0  /* DCS_DAC_WR_VAL_3 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [7:0] */
+
+/*
+ * R74 (0x4A) - DC Servo 7
+ */
+#define WM8904_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R75 (0x4B) - DC Servo 8
+ */
+#define WM8904_DCS_DAC_WR_VAL_1_MASK            0x00FF  /* DCS_DAC_WR_VAL_1 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_1_SHIFT                0  /* DCS_DAC_WR_VAL_1 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [7:0] */
+
+/*
+ * R76 (0x4C) - DC Servo 9
+ */
+#define WM8904_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R77 (0x4D) - DC Servo Readback 0
+ */
+#define WM8904_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8904_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8904_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R90 (0x5A) - Analogue HP 0
+ */
+#define WM8904_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8904_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8904_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8904_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8904_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8904_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8904_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8904_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8904_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8904_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R94 (0x5E) - Analogue Lineout 0
+ */
+#define WM8904_LINEOUTL_RMV_SHORT               0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_MASK          0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_SHIFT              7  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_WIDTH              1  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_ENA_OUTP                0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_MASK           0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_SHIFT               6  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_WIDTH               1  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_DLY                 0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_MASK            0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_SHIFT                5  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_WIDTH                1  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA                     0x0010  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_MASK                0x0010  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_SHIFT                    4  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_WIDTH                    1  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTR_RMV_SHORT               0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_MASK          0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_SHIFT              3  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_WIDTH              1  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_ENA_OUTP                0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_MASK           0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_SHIFT               2  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_WIDTH               1  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_DLY                 0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_MASK            0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_SHIFT                1  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_WIDTH                1  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA                     0x0001  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_MASK                0x0001  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_SHIFT                    0  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_WIDTH                    1  /* LINEOUTR_ENA */
+
+/*
+ * R98 (0x62) - Charge Pump 0
+ */
+#define WM8904_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8904_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8904_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8904_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R104 (0x68) - Class W 0
+ */
+#define WM8904_CP_DYN_PWR                       0x0001  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_MASK                  0x0001  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_WIDTH                      1  /* CP_DYN_PWR */
+
+/*
+ * R108 (0x6C) - Write Sequencer 0
+ */
+#define WM8904_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8904_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8904_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8904_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R109 (0x6D) - Write Sequencer 1
+ */
+#define WM8904_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8904_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8904_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R110 (0x6E) - Write Sequencer 2
+ */
+#define WM8904_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8904_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8904_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8904_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R111 (0x6F) - Write Sequencer 3
+ */
+#define WM8904_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8904_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8904_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8904_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8904_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8904_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8904_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8904_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R112 (0x70) - Write Sequencer 4
+ */
+#define WM8904_WSEQ_CURRENT_INDEX_MASK          0x03F0  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R116 (0x74) - FLL Control 1
+ */
+#define WM8904_FLL_FRACN_ENA                    0x0004  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_MASK               0x0004  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_SHIFT                   2  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_WIDTH                   1  /* FLL_FRACN_ENA */
+#define WM8904_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8904_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8904_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8904_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8904_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R117 (0x75) - FLL Control 2
+ */
+#define WM8904_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8904_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8904_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R118 (0x76) - FLL Control 3
+ */
+#define WM8904_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM8904_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM8904_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R119 (0x77) - FLL Control 4
+ */
+#define WM8904_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8904_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8904_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8904_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM8904_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM8904_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R120 (0x78) - FLL Control 5
+ */
+#define WM8904_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_SRC_MASK             0x0003  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM8904_FLL_CLK_REF_SRC_SHIFT                 0  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM8904_FLL_CLK_REF_SRC_WIDTH                 2  /* FLL_CLK_REF_SRC - [1:0] */
+
+/*
+ * R121 (0x79) - GPIO Control 1
+ */
+#define WM8904_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_MASK                    0x0020  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_SHIFT                        5  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_WIDTH                        1  /* GPIO1_PU */
+#define WM8904_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_MASK                    0x0010  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_SHIFT                        4  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_WIDTH                        1  /* GPIO1_PD */
+#define WM8904_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+#define WM8904_GPIO1_SEL_SHIFT                       0  /* GPIO1_SEL - [3:0] */
+#define WM8904_GPIO1_SEL_WIDTH                       4  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R122 (0x7A) - GPIO Control 2
+ */
+#define WM8904_GPIO2_PU                         0x0020  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_MASK                    0x0020  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_SHIFT                        5  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_WIDTH                        1  /* GPIO2_PU */
+#define WM8904_GPIO2_PD                         0x0010  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_MASK                    0x0010  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_SHIFT                        4  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_WIDTH                        1  /* GPIO2_PD */
+#define WM8904_GPIO2_SEL_MASK                   0x000F  /* GPIO2_SEL - [3:0] */
+#define WM8904_GPIO2_SEL_SHIFT                       0  /* GPIO2_SEL - [3:0] */
+#define WM8904_GPIO2_SEL_WIDTH                       4  /* GPIO2_SEL - [3:0] */
+
+/*
+ * R123 (0x7B) - GPIO Control 3
+ */
+#define WM8904_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_MASK                    0x0020  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_SHIFT                        5  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_WIDTH                        1  /* GPIO3_PU */
+#define WM8904_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_MASK                    0x0010  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_SHIFT                        4  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_WIDTH                        1  /* GPIO3_PD */
+#define WM8904_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+#define WM8904_GPIO3_SEL_SHIFT                       0  /* GPIO3_SEL - [3:0] */
+#define WM8904_GPIO3_SEL_WIDTH                       4  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - GPIO Control 4
+ */
+#define WM8904_GPI7_ENA                         0x0200  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_MASK                    0x0200  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_SHIFT                        9  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_WIDTH                        1  /* GPI7_ENA */
+#define WM8904_GPI8_ENA                         0x0100  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_MASK                    0x0100  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_SHIFT                        8  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_WIDTH                        1  /* GPI8_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA               0x0080  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_MASK          0x0080  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_SHIFT              7  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_WIDTH              1  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_SEL_MASK               0x000F  /* GPIO_BCLK_SEL - [3:0] */
+#define WM8904_GPIO_BCLK_SEL_SHIFT                   0  /* GPIO_BCLK_SEL - [3:0] */
+#define WM8904_GPIO_BCLK_SEL_WIDTH                   4  /* GPIO_BCLK_SEL - [3:0] */
+
+/*
+ * R126 (0x7E) - Digital Pulls
+ */
+#define WM8904_MCLK_PU                          0x0080  /* MCLK_PU */
+#define WM8904_MCLK_PU_MASK                     0x0080  /* MCLK_PU */
+#define WM8904_MCLK_PU_SHIFT                         7  /* MCLK_PU */
+#define WM8904_MCLK_PU_WIDTH                         1  /* MCLK_PU */
+#define WM8904_MCLK_PD                          0x0040  /* MCLK_PD */
+#define WM8904_MCLK_PD_MASK                     0x0040  /* MCLK_PD */
+#define WM8904_MCLK_PD_SHIFT                         6  /* MCLK_PD */
+#define WM8904_MCLK_PD_WIDTH                         1  /* MCLK_PD */
+#define WM8904_DACDAT_PU                        0x0020  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_MASK                   0x0020  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_SHIFT                       5  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_WIDTH                       1  /* DACDAT_PU */
+#define WM8904_DACDAT_PD                        0x0010  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_MASK                   0x0010  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_SHIFT                       4  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_WIDTH                       1  /* DACDAT_PD */
+#define WM8904_LRCLK_PU                         0x0008  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_MASK                    0x0008  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_SHIFT                        3  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_WIDTH                        1  /* LRCLK_PU */
+#define WM8904_LRCLK_PD                         0x0004  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_MASK                    0x0004  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_SHIFT                        2  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_WIDTH                        1  /* LRCLK_PD */
+#define WM8904_BCLK_PU                          0x0002  /* BCLK_PU */
+#define WM8904_BCLK_PU_MASK                     0x0002  /* BCLK_PU */
+#define WM8904_BCLK_PU_SHIFT                         1  /* BCLK_PU */
+#define WM8904_BCLK_PU_WIDTH                         1  /* BCLK_PU */
+#define WM8904_BCLK_PD                          0x0001  /* BCLK_PD */
+#define WM8904_BCLK_PD_MASK                     0x0001  /* BCLK_PD */
+#define WM8904_BCLK_PD_SHIFT                         0  /* BCLK_PD */
+#define WM8904_BCLK_PD_WIDTH                         1  /* BCLK_PD */
+
+/*
+ * R127 (0x7F) - Interrupt Status
+ */
+#define WM8904_IRQ                              0x0400  /* IRQ */
+#define WM8904_IRQ_MASK                         0x0400  /* IRQ */
+#define WM8904_IRQ_SHIFT                            10  /* IRQ */
+#define WM8904_IRQ_WIDTH                             1  /* IRQ */
+#define WM8904_GPIO_BCLK_EINT                   0x0200  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_MASK              0x0200  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_SHIFT                  9  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_WIDTH                  1  /* GPIO_BCLK_EINT */
+#define WM8904_WSEQ_EINT                        0x0100  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_MASK                   0x0100  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_SHIFT                       8  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_WIDTH                       1  /* WSEQ_EINT */
+#define WM8904_GPIO3_EINT                       0x0080  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_MASK                  0x0080  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_SHIFT                      7  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_WIDTH                      1  /* GPIO3_EINT */
+#define WM8904_GPIO2_EINT                       0x0040  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_MASK                  0x0040  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_SHIFT                      6  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_WIDTH                      1  /* GPIO2_EINT */
+#define WM8904_GPIO1_EINT                       0x0020  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_MASK                  0x0020  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_SHIFT                      5  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_WIDTH                      1  /* GPIO1_EINT */
+#define WM8904_GPI8_EINT                        0x0010  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_MASK                   0x0010  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_SHIFT                       4  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_WIDTH                       1  /* GPI8_EINT */
+#define WM8904_GPI7_EINT                        0x0008  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_MASK                   0x0008  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_SHIFT                       3  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_WIDTH                       1  /* GPI7_EINT */
+#define WM8904_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8904_MIC_SHRT_EINT                    0x0002  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_MASK               0x0002  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_SHIFT                   1  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_WIDTH                   1  /* MIC_SHRT_EINT */
+#define WM8904_MIC_DET_EINT                     0x0001  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_MASK                0x0001  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_SHIFT                    0  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_WIDTH                    1  /* MIC_DET_EINT */
+
+/*
+ * R128 (0x80) - Interrupt Status Mask
+ */
+#define WM8904_IM_GPIO_BCLK_EINT                0x0200  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_MASK           0x0200  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_SHIFT               9  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_WIDTH               1  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_WSEQ_EINT                     0x0100  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_MASK                0x0100  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_SHIFT                    8  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_WIDTH                    1  /* IM_WSEQ_EINT */
+#define WM8904_IM_GPIO3_EINT                    0x0080  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_MASK               0x0080  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_SHIFT                   7  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_WIDTH                   1  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO2_EINT                    0x0040  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_MASK               0x0040  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_SHIFT                   6  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_WIDTH                   1  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO1_EINT                    0x0020  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_MASK               0x0020  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_SHIFT                   5  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_WIDTH                   1  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPI8_EINT                     0x0010  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_MASK                0x0010  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_SHIFT                    4  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_WIDTH                    1  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI7_EINT                     0x0008  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_MASK                0x0008  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_SHIFT                    3  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_WIDTH                    1  /* IM_GPI7_EINT */
+#define WM8904_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_MIC_SHRT_EINT                 0x0002  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_MASK            0x0002  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_SHIFT                1  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_WIDTH                1  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_DET_EINT                  0x0001  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_MASK             0x0001  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_SHIFT                 0  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_WIDTH                 1  /* IM_MIC_DET_EINT */
+
+/*
+ * R129 (0x81) - Interrupt Polarity
+ */
+#define WM8904_GPIO_BCLK_EINT_POL               0x0200  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_MASK          0x0200  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_SHIFT              9  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_WIDTH              1  /* GPIO_BCLK_EINT_POL */
+#define WM8904_WSEQ_EINT_POL                    0x0100  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_MASK               0x0100  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_SHIFT                   8  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_WIDTH                   1  /* WSEQ_EINT_POL */
+#define WM8904_GPIO3_EINT_POL                   0x0080  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_MASK              0x0080  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_SHIFT                  7  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_WIDTH                  1  /* GPIO3_EINT_POL */
+#define WM8904_GPIO2_EINT_POL                   0x0040  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_MASK              0x0040  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_SHIFT                  6  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_WIDTH                  1  /* GPIO2_EINT_POL */
+#define WM8904_GPIO1_EINT_POL                   0x0020  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_MASK              0x0020  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_SHIFT                  5  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_WIDTH                  1  /* GPIO1_EINT_POL */
+#define WM8904_GPI8_EINT_POL                    0x0010  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_MASK               0x0010  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_SHIFT                   4  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_WIDTH                   1  /* GPI8_EINT_POL */
+#define WM8904_GPI7_EINT_POL                    0x0008  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_MASK               0x0008  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_SHIFT                   3  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_WIDTH                   1  /* GPI7_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL                0x0004  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_MASK           0x0004  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_SHIFT               2  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_WIDTH               1  /* FLL_LOCK_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL                0x0002  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_MASK           0x0002  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_SHIFT               1  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_WIDTH               1  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL                 0x0001  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_MASK            0x0001  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_SHIFT                0  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_WIDTH                1  /* MIC_DET_EINT_POL */
+
+/*
+ * R130 (0x82) - Interrupt Debounce
+ */
+#define WM8904_GPIO_BCLK_EINT_DB                0x0200  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_MASK           0x0200  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_SHIFT               9  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_WIDTH               1  /* GPIO_BCLK_EINT_DB */
+#define WM8904_WSEQ_EINT_DB                     0x0100  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_MASK                0x0100  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_SHIFT                    8  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_WIDTH                    1  /* WSEQ_EINT_DB */
+#define WM8904_GPIO3_EINT_DB                    0x0080  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_MASK               0x0080  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_SHIFT                   7  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_WIDTH                   1  /* GPIO3_EINT_DB */
+#define WM8904_GPIO2_EINT_DB                    0x0040  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_MASK               0x0040  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_SHIFT                   6  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_WIDTH                   1  /* GPIO2_EINT_DB */
+#define WM8904_GPIO1_EINT_DB                    0x0020  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_MASK               0x0020  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_SHIFT                   5  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_WIDTH                   1  /* GPIO1_EINT_DB */
+#define WM8904_GPI8_EINT_DB                     0x0010  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_MASK                0x0010  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_SHIFT                    4  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_WIDTH                    1  /* GPI8_EINT_DB */
+#define WM8904_GPI7_EINT_DB                     0x0008  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_MASK                0x0008  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_SHIFT                    3  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_WIDTH                    1  /* GPI7_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB                 0x0004  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_MASK            0x0004  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_SHIFT                2  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_WIDTH                1  /* FLL_LOCK_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB                 0x0002  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_MASK            0x0002  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_SHIFT                1  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_WIDTH                1  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB                  0x0001  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_MASK             0x0001  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_SHIFT                 0  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_WIDTH                 1  /* MIC_DET_EINT_DB */
+
+/*
+ * R134 (0x86) - EQ1
+ */
+#define WM8904_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8904_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8904_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8904_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R135 (0x87) - EQ2
+ */
+#define WM8904_EQ_B1_GAIN_MASK                  0x001F  /* EQ_B1_GAIN - [4:0] */
+#define WM8904_EQ_B1_GAIN_SHIFT                      0  /* EQ_B1_GAIN - [4:0] */
+#define WM8904_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [4:0] */
+
+/*
+ * R136 (0x88) - EQ3
+ */
+#define WM8904_EQ_B2_GAIN_MASK                  0x001F  /* EQ_B2_GAIN - [4:0] */
+#define WM8904_EQ_B2_GAIN_SHIFT                      0  /* EQ_B2_GAIN - [4:0] */
+#define WM8904_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [4:0] */
+
+/*
+ * R137 (0x89) - EQ4
+ */
+#define WM8904_EQ_B3_GAIN_MASK                  0x001F  /* EQ_B3_GAIN - [4:0] */
+#define WM8904_EQ_B3_GAIN_SHIFT                      0  /* EQ_B3_GAIN - [4:0] */
+#define WM8904_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [4:0] */
+
+/*
+ * R138 (0x8A) - EQ5
+ */
+#define WM8904_EQ_B4_GAIN_MASK                  0x001F  /* EQ_B4_GAIN - [4:0] */
+#define WM8904_EQ_B4_GAIN_SHIFT                      0  /* EQ_B4_GAIN - [4:0] */
+#define WM8904_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [4:0] */
+
+/*
+ * R139 (0x8B) - EQ6
+ */
+#define WM8904_EQ_B5_GAIN_MASK                  0x001F  /* EQ_B5_GAIN - [4:0] */
+#define WM8904_EQ_B5_GAIN_SHIFT                      0  /* EQ_B5_GAIN - [4:0] */
+#define WM8904_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [4:0] */
+
+/*
+ * R140 (0x8C) - EQ7
+ */
+#define WM8904_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM8904_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM8904_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R141 (0x8D) - EQ8
+ */
+#define WM8904_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM8904_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM8904_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R142 (0x8E) - EQ9
+ */
+#define WM8904_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM8904_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM8904_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R143 (0x8F) - EQ10
+ */
+#define WM8904_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM8904_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM8904_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R144 (0x90) - EQ11
+ */
+#define WM8904_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM8904_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM8904_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R145 (0x91) - EQ12
+ */
+#define WM8904_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM8904_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM8904_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R146 (0x92) - EQ13
+ */
+#define WM8904_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM8904_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM8904_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R147 (0x93) - EQ14
+ */
+#define WM8904_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM8904_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM8904_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R148 (0x94) - EQ15
+ */
+#define WM8904_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM8904_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM8904_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R149 (0x95) - EQ16
+ */
+#define WM8904_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM8904_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM8904_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R150 (0x96) - EQ17
+ */
+#define WM8904_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM8904_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM8904_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R151 (0x97) - EQ18
+ */
+#define WM8904_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM8904_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM8904_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R152 (0x98) - EQ19
+ */
+#define WM8904_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM8904_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM8904_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R153 (0x99) - EQ20
+ */
+#define WM8904_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM8904_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM8904_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R154 (0x9A) - EQ21
+ */
+#define WM8904_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM8904_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM8904_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R155 (0x9B) - EQ22
+ */
+#define WM8904_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM8904_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM8904_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R156 (0x9C) - EQ23
+ */
+#define WM8904_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM8904_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM8904_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R157 (0x9D) - EQ24
+ */
+#define WM8904_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM8904_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM8904_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+/*
+ * R161 (0xA1) - Control Interface Test 1
+ */
+#define WM8904_USER_KEY                         0x0002  /* USER_KEY */
+#define WM8904_USER_KEY_MASK                    0x0002  /* USER_KEY */
+#define WM8904_USER_KEY_SHIFT                        1  /* USER_KEY */
+#define WM8904_USER_KEY_WIDTH                        1  /* USER_KEY */
+
+/*
+ * R204 (0xCC) - Analogue Output Bias 0
+ */
+#define WM8904_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
+#define WM8904_PGA_BIAS_SHIFT                        4  /* PGA_BIAS - [6:4] */
+#define WM8904_PGA_BIAS_WIDTH                        3  /* PGA_BIAS - [6:4] */
+
+/*
+ * R247 (0xF7) - FLL NCO Test 0
+ */
+#define WM8904_FLL_FRC_NCO                      0x0001  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_MASK                 0x0001  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_SHIFT                     0  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+
+/*
+ * R248 (0xF8) - FLL NCO Test 1
+ */
+#define WM8904_FLL_FRC_NCO_VAL_MASK             0x003F  /* FLL_FRC_NCO_VAL - [5:0] */
+#define WM8904_FLL_FRC_NCO_VAL_SHIFT                 0  /* FLL_FRC_NCO_VAL - [5:0] */
+#define WM8904_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [5:0] */
+
+#endif